Brian Takita's blog



Brian TakitaBrian Takita
RR 0.6.2 Released
edit Posted by Brian Takita on Tuesday October 28, 2008 at 06:07AM

This release features a sexier Double definition block syntax using instance_eval:

mock(User) do
  find(1) {user_1}
  find(2) {user_2}
end

RR also maintains its non-instance_evaled Double definition block syntax, if the block has an arity of 1:

mock(User) do |expect|
  expect.find(1) {user_1}
  expect.find(2) {user_2}
end

The instance_eval syntax is very useful in the context of Double Definition chaining:

mock.proxy(User).find(1) do
  mock.proxy! do
    blogs do
      mock.proxy!.find_by_id(2) do |actual_blog|
        actual_blog.name.should == "My ranty blog"
        actual_blog
      end
    end

    fans do
      mock.proxy!.thank_everybody
    end

    foes do
      mock.proxy!.ask_for_forgiveness
    end
  end
end

user = User.find(1)
user.blogs.find_by_id(2) # My ranty blog
user.fans.thank_everybody
user.foes.ask_for_forgiveness

Of course the previous example is a complicated case of interaction testing, and a simpler state-based and/or hybrid approach may be better, but it demonstrates how using instance_eval can promote readability.

Here is the non-instance_eval solution:

mock.proxy(User).find(1) do
  mock.proxy! do |expect|
    expect.blogs do
      mock.proxy!.find_by_id(2) do |actual_blog|
        actual_blog.name.should == "My ranty blog"
        actual_blog
      end
    end

    expect.fans do
      mock.proxy!.thank_everybody
    end

    expect.foes do
      mock.proxy!.ask_for_forgiveness
    end
  end
end

instance_eval Controversy

Ola Bini warned against overusing instance_eval. While instance_eval adds beauty, it can also make things more difficult to extend and debug.

In RR, the DoubleDefinitionCreatorProxy (the object that is instance_evaled when defining Doubles using blocks) uses the blank slate pattern, so arbitrary method names can be passed in to define the Double. The Blank Slate implies that the DoubleDefinitionCreatorProxy will not be extended with methods. James Earl Gray explains the pattern that I used for RR.

spec/test helper methods will not be usable within the instance_evaled blocks because the intent of the DoubleDefinitionCreatorProxy object is incompatible with the instance_eval with delegation pattern. DoubleDefinitionCreatorProxy already uses method_missing to create DoubleDefinitions. If you wish to use spec/test helper methods, you will need to memoize it to a variable and use lexical scoping.

Now, one may want to define a helper method in the test/spec that is returned when the Double is invoked.

describe User do
  describe "#fans.thank_everybody" do
    it "thanks all of my lovely fans" do
      user = User.new
      memoized_my_lovely_fans = my_lovely_fans
      mock(user) {fans {memoized_my_lovely_fans}}
      memoized_my_lovely_fans.each {|fan| mock(fan).thank_you}

      user.fans.thank_everybody
    end

    def my_lovely_fans
      [Fan.new, Fan.new]
    end
  end
end

While I think this will be a good addition to RR, I recognize that adding the instance_eval has the possibility of making RR less usable. I'll pay close attention to see how this pans out and am willing to remove it if there are major issues.

Brian TakitaBrian Takita
Effective Markdown Editing with the WMD editor and the Save Text Area Firefox plugin
edit Posted by Brian Takita on Saturday October 18, 2008 at 08:38PM

Anytime I need to edit Markdown, I reach for the WMD editor. Their splitscreen demo is the most effective way to edit Markdown that I have seen.

The left screen is the editor and the right screen is the "real-time" preview of the Markdown. It is nice because I don't have to press a preview button to see rendered Markdown. The Markdown is also rendered as I type so I get instantaneous feedback of my changes.

There is also a Save Text Area Firefox addon, which enables me to save/load the contents of a text area to/from a file on the filesystem. Also the Ctrl+s shortcut saves the file.

So when editing Markdown, I:

  1. Open Firefox and go to http://wmd-editor.com/examples/splitscreen?blank=1
  2. Load or Save a markdown file by right-clicking the editor screen
    1. Going to the Text submenu
    2. Clicking Load or Save As
  3. Edit the file and see the generated output

Of course, its not a text editor replacement, since the possible text manipulation in Firefox is limited, but the feedback that is provided by WMD is very effective to rapid Markdown editing. I hope this sort of UI becomes more common.

Now if only there were a similar Textile editor...

Brian TakitaBrian Takita
NYC Stand Up 10/15 - 10/16 2008
edit Posted by Brian Takita on Thursday October 16, 2008 at 02:25PM

10/15/2008

Help!

  • Autocompleters - Which one do we use?

    • We are currently using the YUI autocompleter from YUI 2.4.1 which works well. However, we are making significant architectural changes, and the "new" way used the YUI autocomplenet from 2.6.0. We don't want to install YUI just for the autocompleter and we don't want to deal with the version mismatch, so we are going to use a different autocompleter. It seems that there are many autocompleters, so which one do we use?

    • NOTE: We ended up going with the jQuery autocompleter. The autocompleter had issues with noConflict mode and with pressing the backspace key. We fixed them and will post the fixed version to Github soon.

Interesting

  • Postgres replication requires a primary key, and HABTM solutions typically do not use primary keys. Has many through is better anyway.

10/16/2008

Help!

  • CI build is slow and we don't know why

    • Our CI build is failing because of the performance issues. Some strange things we noticed:

    • There are many Sockets in the TIME_WAIT state

    • A possible solution is to run the OSX diskutils on the CI box.

    • Piston Hangs when importing a SVN dependency into a Git repo

Interesting

  • The Heavy team is coming for lunch to discuss process

  • git-svn is difficult to work with

    • Use all Git or all SVN if you can.
  • Polonium

    • Using click_and_wait fixes failures due to timeout on the CI box. It is more performant because click_and_wait is implemented in JS. The standard Polonium wait_for assertions poll into SeleniumRC.

Brian TakitaBrian Takita
NYC Stand Up 10/14 2008
edit Posted by Brian Takita on Tuesday October 14, 2008 at 02:00PM

A developer accidentally committed to an SVN external. Switching the SVN user to have read-only access to the external.

Casebook's ccrb + Funkytown + JsUnit build opens parallels on development boxes. The issue is probably with the Funkytown configuration.

Adam Keyes is coming in to talk to us during lunch today.

Casebook is moving to Git.

Brian TakitaBrian Takita
NYC Stand Up 10/13 2008
edit Posted by Brian Takita on Monday October 13, 2008 at 01:50PM

Interesting

"All your brunch is belong to us" - Damon McCormick

NYC Ruby Tomorrow

Erector 0.4.200 was released. New features include:

  • The Widget#join method, which joins an Array of text/widgets, with a separator which is text or a widget. This translates the standard idiom, without needing calls to raw.

    join [ "People", "Projects" ], " | "

  • Added a Pretty Printer which can be enabled by Erector::Doc.prettyprint_default = true (for example in development.rb)

JsUnit runs very slowly on the CI box on OSX and eventually times out, unless we open a VNC window to the machine. We tried upgrading to a more recent JsUnit, but couldn't get that to work at all.

Nanite looks really cool.

Brian TakitaBrian Takita
RR 0.6.0 Released
edit Posted by Brian Takita on Monday October 13, 2008 at 06:37AM

I'm pleased to announce the 0.6.0 version of RR. The changes include:

  • Declaring Double subject objects without having to pass it in via the mock!, stub!, dont_allow!, instance_of!, and proxy! methods
  • Revised Double chaining API
  • satisfy matcher
  • hash_including matcher

Declaring Double Subjects (The bang methods)

In previous versions of RR, you always needed to pass in the subject of the double. For example:

subject = Object.new
mock(subject).does_something {:and_returns_me}
subject.does_something # :and_returns_me

Now you can have RR automatically create the subject object for you by using the ! method:

subject = mock!.does_something {:and_returns_me}.subject
subject.does_something # :and_returns_me

Now the bang methods by themselves don't really add a whole lot, but when used in the context of Double chaining, they become a powerful addition.

Double Chaining

Nick Kallen presented the use case for Double chaining and contributed a patch for the 0.5.0 release of RR. It has proved useful and is now more fully incorporated into RR. Now you can pass in your subject or use the subject provided by RR by using the ! method. Here are some examples of Double Chaining:

mock(subject).first(1) {mock(Object.new).second(2) {mock(Object.new).third(3) {4}}}
subject.first(1).second(2).third(3) # 4

mock(subject).first(1) {mock!.second(2) {mock!.third(3) {4}}}
subject.first(1).second(2).third(3) # 4

mock(subject).first(1).mock!.second(2).mock!.third(3) {4}
subject.first(1).second(2).third(3) # 4

Of course you have access to the proxy facilities:

mock.proxy(User).find('1').mock.proxy!.children.mock.proxy!.find_all_by_group_id(10)
User.find('1').children.find_all_by_group_id(10) # Makes verifications pass and returns the actual children

You can also do branched Double chaining:

mock(subject).first do
  mock! do |expect|
    expect.branch1.mock!.branch11 {11} # or expect.branch1 {mock!.branch11 {11}}
    expect.branch2.mock!.branch22 {22} # or expect.branch2 {mock!.branch22 {22}}
  end
end
o = subject.first
o.branch1.branch11 # 11
o.branch2.branch22 # 22

Satisfy Matcher

Matthew O'Conner submitted a patch that added the satisfy matcher. This adds the ability to add arbitrary argument expectation matchers.

mock(object).foobar(satisfy {|arg| arg.length == 2})
object.foobar("xy")

Hash Including Matcher

Matthew O'Conner also submitted a patch that added the hash_including matcher. This adds a convenient way to assert that the passed-in hash includes certain key/value pairs.

mock(object).foobar(hash_including(:red => "#FF0000", :blue => "#0000FF"))
object.foobar({:red => "#FF0000", :blue => "#0000FF", :green => "#00FF00"})

Mailing list

RR has a mailing lists at:

Also, RR's rubyforge page is at http://rubyforge.org/projects/double-ruby and of course the github page is at http://github.com/btakita/rr.

Yes, and there is more to come

There are many interesting ideas floating around. Joseph Wilk has been playing around with adding Spies into RR. I'm also thinking about adding Double validation scoping into RR. Also, I'm impressed by Mocha's warning of unused stubs. Josh Susser also proposed having a mode where a warning would occur if a mocked method is not implemented on the subject being mocked.

If you have any feature requests, please send an email to the mailing list or add it to the rubyforge tracker.