The Bang Is for Surprise

Published on:
Tags: rspec, ruby

Note: I’m using Ruby 2.0.0 and RSpec 2.13.1 for these samples. Behavior may be slightly different in older versions. YMMV!

One of the more well known features of RSpec is let. It provides a way to create a variable as a bareword which is lazy loaded and memoized.

It also has a sibling let!. On the surface, let! is just a let without the lazy loading. So any variable defined with a let! will always be created before a test. This tool has a few nuances that should be know before you reach for it.

Take the following sample. What do you think the result will be?

1
2
3
4
5
6
7
8
9
10
11
describe "Which one wins?" do

  let!(:sample) { "using let bang!" }

  context "inside a context" do
    let(:sample) { "normal let" }

    it { expect(sample).to eq "normal let" }
  end

end

The test passes. This may or may not have been surprising. The rules for nested lets, is that the let defined closet to the test in the hierarchy wins. But, didn’t I say let! always created the object which was then memoized?

I’ll get to more about how let and let! are implemented in a minute. For now, I want to point out a subtle surprise waiting for you; or possibly bring to light that nagging itch at the back of your brain.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
describe "Using Conflicting Let and Let!" do

  let!(:user) { create :user, name: 'bob' }

  # LOTS OF CODE SO YOU CAN'T SEE THE ABOVE LINE

  context "inside a context" do
    let(:user) { create :user, name: 'alice' }

    # Will this pass?
    it do
      expect(User.count).to eq 0
    end
  end

end

Surprise! The test fails:

1
2
3
4
5
6
7
  1) Which one wins? inside a context
     Failure/Error: expect(User.count).to eq 0

       expected: 0
            got: 1

       (compared using ==)

WAT?

user was never explicitly referenced in our test or a before block. Above I also stated that the let closest to the test wins. Theoretically, by these rules one would naturally think the test would have passed. Yet, someone was created in the database.

Which user definition do you think was created?

If we dump the User collection before the expect line we see:

1
[<User id: 1, name: "alice", ...>]

Not only did the inner normal let block appear to override the outer, the outer let! behavior took affect!

Let’s try one more:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
describe "Using Conflicting Nested Let!" do

  let!(:user) { create :user, name: 'bob' }


  context "inside a context" do
    # Now we'll use the bang version here
    let!(:user) { create :user, name: 'alice' }

    # Will this pass?
    it do
      expect(User.count).to eq 1
    end
  end

end

Surprise! It passes:

1
2
3
4
5
6
Using Conflicting Nested Let!
  inside a context
    should eq 1

Finished in 0.02185 seconds
1 example, 0 failures

Again, dumping the user created we see our good friend Alice:

1
[<User id: 1, name: "alice", ...>]

If you’re scratching your brain right now. Don’t worry. I did too the first time. However, once we cover what is happening behind that curtain things will make perfect sense.

How let and let! Work

Pay [no] attention to that man behind the curtain!” - The Wizard

The reason for this behavior, remember I’m using RSpec 2.13, is that let! just calls let and before behind the scenes:

1
2
3
4
def let!(name, &block)
  let(name, &block)
  before { __send__(name) }
end

And all let does is setup a memoized method based on the name and provided block:

1
2
3
4
5
MemoizedHelpers.module_for(self).send(:define_method, name, &block)

define_method(name) do
  __memoized.fetch(name) { |k| __memoized[k] = super(&nil) }
end

“Using Conflicting Let and Let!” Explained

Going back to the example “Using Conflicting Let and Let!” above, where both let! and let were used. It should be a bit clearer what is really going on.

When the test runs, the let! has already created the before block, which will send the message :user. However, the inner context’s let created a new method with the same name. Thus based on standard Ruby method lookup, when the before block runs the inner method receives the message:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
describe "Using Conflicting Let and Let!" do

  # Expanding the following out:
  # let!(:user) { create :user, name: 'bob' }
  def user
    create :user, name: 'bob'
  end
  before{ user }

  context "inside a context" do
    # Expanding the following out:
    # let(:user) { create :user, name: 'alice' }
    def user
      create :user, name: 'alice'
    end

    # The outer `before` block will run before this example.
    # Due to the examples being objects, the inner
    # `def user` will receive the `:user` message sent
    # by `before`.
    it do
      expect(User.count).to eq 0
    end
  end

end

“Using Conflicting Nested Let!” Explained

It should also start to make sense what was going on with the “Using Conflicting Nested Let!” example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
describe "Using Conflicting Nested Let!" do

  # Expanding the following out:
  # let!(:user) { create :user, name: 'bob' }
  def user
    create :user, name: 'bob'
  end
  before{ user }

  context "inside a context" do
    # Now we'll use the bang version here
    # Expanding the following out:
    # let!(:user) { create :user, name: 'alice' }
    def user
      create :user, name: 'alice'
    end
    before{ user }

    # The outer `before` block will run before this example.
    # Due to the examples being objects, the inner
    # `def user` will receive the `:user` message sent
    # by the outer `before`.
    #
    # The inner `before` block will run next, also sending
    # the message `:user`. This is also received by the
    # inner example object. However, since `let` is also
    # memoized, this doesn't actually execute the `:create`.
    # It just returns the already created object.
    it do
      expect(User.count).to eq 1
    end
  end

end

It’s Just a Method

I hope that helps demystify the behavior.

Since let is just a helper for setting up methods on the example group object you can call super in it; though this is generally not an advised practice.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
describe "Just a Method" do

  let!(:sample) { "using let bang!" }

  context "using super()" do
    let(:sample) {
      p super()
      "normal let"
    }

    it { expect(sample).to eq "normal let" }
  end

end
1
2
3
4
Just a Method
  using super()
"using let bang!"
    should eq "normal let"

Avoiding Ambiguity

Since that tiny little ! can be hard to see, especially in a sea of let declarations, it is easy to miss it and get surprised. Additionally, seeing as how mixing let! and let can lead to some surprises, it’s fairly clear why let! has started, rightly so in my opinion, to fall out of favor with some of the RSpec crowd.

Luckily, there should be very few situations you should find yourself in where you want to reach for let! over let. For me, this is usually a situation where I’m creating some sort of persisted resource. For instance, the factory example, or creating a test file on the system.

Options For Preloading

If people are moving away from using let!, how should you preload variables?

Reference in before

Call them just like RSpec does in a before:

1
2
3
4
5
6
7
let(:bob)   { create :user, name: 'bob'   }
let(:alice) { create :user, name: 'alice' }

before do
  bob
  alice
end

To me this looks a bit odd. People I’ve talked to tend to have two reactions:

  1. Why are you referencing a ‘variable’ and not using it?
  2. Wouldn’t it be a bit more explicit to show the creation using an @var?

By now you should know that the first response indicates a lack of understand on how RSpec works. They aren’t variables, they are actually bareword messages.

The second response is a valid point. The result would be:

1
2
3
4
before do
  @bob   = create :user, name: 'bob'
  @alice = create :user, name: 'alice'
end

This goes back to preference and style. My preference is to reach for a bareword whenever I can. One reason is that, when using an instance variables you are now locked in to how both @bob and @alice are created. If you later wanted to modify them, you could but at the expense of already having created the persisted resource; remember before blocks execute outside-in (this isn’t so much of an issue for lightweight objects). Or you have to roll your own memoization scheme (not hard just duplication of work).

Use a method

The next common thing I see done is people say: “I’ll just wrap it all up in a method.”

1
2
3
4
5
6
def create_users
  @bob   = create :user, name: 'bob'
  @alice = create :user, name: 'alice'
end

before { create_users }

Now the before looks better; it’s explicit what is happening. However, the new create_users method looks just like our old before. So this really just added one level of indirection. The main advantage here is if we need to change the behavior we can just write a new create_users method in an inner context. We could also use barewords by making our variables into methods:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def bob
  @bob ||= create :user, name: 'bob'
end

def alice
  @alice ||= create :user, name: 'alice'
end

def create_users
  bob
  alice
end

before { create_users }

Though now we’ve duplicated the lazy loading and memoizing logic already provided by let.

At this point, you’ll probably say, we can make this a bit more explicit and clean it up at the same time:

1
2
3
4
5
6
7
8
9
10
11
12
13
def bob
  @bob ||= create :user, name: 'bob'
end

def alice
  @alice ||= create :user, name: 'alice'
end

def create_users(*users)
  users.each{ |user| public_send user }
end

before { create_users :bob, :alice }

This brings me to my next option.

Explicit Preload

Now there’s nothing inherently wrong with the above methods. However, to me they add a lot of work, without adding much additional value. There are still cases where I’ll break out the generator method as it’s a very useful tool. But this section is about another option, so I’ll get to it.

Having gone through the cycle of improvement the “hard” way, it’s time to show you the shortcut. To me, this is reminiscent of high school calculus class where the teacher made me do everything the difficult, time consuming way, for a week before teaching how it’s usually done with the shorter method.

Since pretty much everything in RSpec is already just a method, we can leverage that to get our desired behavior. This was discussed in a pull request:

1
2
3
4
5
6
7
8
9
10
11
module LetPreloadable
  def preload(*names)
    before do
      names.each { |name| __send__ name }
    end
  end
end

RSpec.configure do |rspec|
  rspec.extend LetPreloadable
end

You can place the module code anywhere you want (usually in spec/support). Then you’ll load it in a RSpec.configure block either in the same file or in spec_helper.rb.

Our setup now looks like:

1
2
3
4
let(:bob)   { create :user, name: 'bob'   }
let(:alice) { create :user, name: 'alice' }

preload :bob, :alice

Going back to our original example. There is now more context to what is happening without the confusing mix of let and let!:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
describe "No More Conflicting Let and Let!" do

  let(:user) { create :user, name: 'bob' }

  preload :user

  context "inside a context" do
    let(:user) { create :user, name: 'alice' }

    it do
      expect(User.count).to eq 1
    end
  end

end

Introducing Conjurer Gem

I’ve started using this in enough new projects that I wanted an easy way to just add it. I also wanted to be able to include any changes easily. Thus, I’ve rolled it all up into a gem: conjurer

Happy RSpecing!!

Quirky Privates

Published on:
Tags: note, ruby

Just one of those little Ruby language quirks. Normally, you have to use the implicit receiver when sending a private message. This can be demonstrated as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Quirky
  def send_private_explicitly
    self.say_hello    # => NoMethodError: private method 'say_hello'
  end

  def send_private_implicitly
    say_hello         # => "Hi there friend!"
  end

  private

  def say_hello
    puts "Hi there friend!"
  end
end

However, this is not true when sending a message that ends in =. In this case you must use the explicit receiver self.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Quirky
  def send_private_setter_explicitly
    self.store_value = 'friend'     # => @private_value='friend'
    store_value                     # => "Let's get our private value"
  end

  def send_private_setter_implicitly
    store_value = 'friend'          # => @private_value is not set
    store_value                     # => 'friend'
  end

  private

  def store_value=(value)
    @private_value = value
  end

  def store_value
    puts "Let's get our private value"
  end
end

In fact, without the explicit reciever self when sending a private message ending in =, you will instead create a local variable with that name. This is then the reference point for the rest of the method body.

How Basic RSpec Works - Simplified

Published on:
Tags: rspec, ruby

Recently, I had the privilege of giving a talk regarding RSpec at the Arlington Ruby meetup group. The talk was about RSpec and how you can take some next steps with it (slides here: http://rspec-next-steps.herokuapp.com.

The talk was targeted at intermediate RSpec users. There were several in attendance whom were fairly new to RSpec. This made some of the talk seem like “magic”. Based on the questions I received, I wanted to take a moment to address some of the general workings of RSpec, in order to dispel any “magic” that may seem to be happening.

It is my hope to try to show how some of this works. I won’t be covering any of the more advanced topics just yet, as the code can get a bit complicated, and the point here is to simplify how RSpec works. So bare with me and the overly simplistic implementation. The full code is available in the following GitHub gist: https://gist.github.com/4247624

First, we need to setup some methods that define the basic usage of RSpec: describe, subject, before, after, and it.

First up is the outer describe:

1
2
3
4
def describe(object_under_test, &block)
  @obj_under_test = object_under_test
  @test_group     = block
end

In this example we are specifically only supporting a single describe block with no nesting. The reason here is for simplicity. In our case describe is just a method that takes an object or description string and block. Nothing special. Hopefully, this helps make it clear that we are only dealing with a DSL for creating / setting up examples. We’ll store away the test object in an instance variable and keep a reference to the block for later.

Next, we setup a method for gaining access to subject:

1
2
3
4
5
6
7
def subject
  if @obj_under_test.is_a? Class
    @subject ||= @obj_under_test.new
  else
    @obj_under_test
  end
end

If our subject is a class, we create a new memoized instance of it. Otherwise, we simply return the object itself.

Next is the commonly used before blocks and the associated after friend:

1
2
def before(&block) @before_hooks << block end
def after(&block)  @after_hooks  << block end

In this simplistic implementation, it is easy to see how they work. We just keep a reference to all of the block in a normal array (in Ruby the order of insertion is preserved) for use later. We do the same with after.

Last up, is the real meat of the examples, the it block:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def it(description = nil, &block)
  @examples << Example.new(description, block)
end

Example = Struct.new(:description, :test) do
  attr_accessor :result, :failure
  def call
    @result = if test
                begin
                  test.call
                  :passed
                rescue => e
                  @failure = e
                  :failed
                end
              else
                :pending
              end
  end
end

As with the describe method, this takes an optional description and a block to execute (our actual test). We’ll need access to both of these later, and we’ll have multiple examples, so we’ll use a simple object to keep track of each. After creating the example object, we’ll store it in the queue.

At this point it is worth taking a moment to discuss Example#call. We named it call so that accessing it is no different than a traditional block. This makes it easier to change code later.

Inside Example#call, we attempt to pass call on the block that the Example was created with. If this raises an error, we store the exception for access later and mark the test as failed. Something to note here is that the return value of the test block is ignored. A test is marked as passed as long as it does not raise any errors. This is also how RSpec behaves.

If no block was given when we created the Example, then we treat it as pending. I have omitted the pending method, common in RSpec due to the complexity it would add to this example.

Something else to note, since this is an overly simplistic example, we are doing everything in the global main namespace. RSpec does not behave this way, but it helps keep our example simple. Due to this, we’ll need to setup some of our variables:

1
2
3
@before_hooks = []
@after_hooks  = []
@examples     = []

Additionally, we don’t have any matchers defined yet. To keep it simple, I’ll add a TestUnit style assert matcher.

1
2
3
def assert(truthy)
  truthy or raise Error.new("Test failed.")
end

At this point, I hope you can start to get the picture of how our simplified example will run. We’ll setup our run as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def run
  raise 'No object under test defined.' unless @obj_under_test

  puts @obj_under_test
  return unless @test_group

  # Find out what tests need to be run
  @test_group.call

  # Run the tests
  @examples.each_with_index do |example, index|
    @subject = nil
    puts "\n\nEXAMPLE #{index+1}:"
    begin
      @before_hooks.each(&:call)
      example.call
      puts "\n    #{example.description} => #{example.result.upcase}\n"
    rescue => e
      puts "\n    #{example.description} => failed\n"
    ensure
      @after_hooks.reverse_each(&:call)
    end
  end
end

If there is no object under test defined when we run (i.e. describe was never called) then we raise an error. Otherwise, we output the object under test. If this is a class (as is usual for a top level describe block) then we will see the class name. Otherwise, the object itself is output. If it is a string, we’ll get the string value, otherwise, we’ll get the object’s #to_s representation.

It should be noted that in the real RSpec this outputting is much more complicated and left up to various output formatters.

Next we will run the test_group (the body of the describe block). This in turn call all our before, after, and it methods, which set up our environment and define the examples.

All that is left, is to iterate over the examples and run them. Here I’m using each_with_index solely to be able to add some debugging output to make it a bit clearer how things are running. Normally, this would be a simple each iterator.

Before each test run, we make sure we have a new empty subject. We then iterate through each of the before blocks in the order they were defined. At this point we run the example. After the example runs, I’m immediately outputting the results to keep things simple. In the real RSpec, this is handled by an output formatter. Finally, all of the after hooks are run, but in reverse defined order.

It should be noted, that here, as in the real RSpec, if any of the before blocks throw an exception the test fails. However, failures in any after block are ignored.

That’s it. We can then use this to define our sample spec:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Thing
  attr_reader :my_value
  def initialize
    @my_value = rand 5
  end
end

describe Thing do
  before { puts "BEFORE_BLOCK:: First before block" }
  after do
    print "AFTER_BLOCK:: should be called last!"
    print "    Reset @tmp_value(#{@tmp_value.inspect}) => "
    @tmp_value = nil
    puts "@tmp_value(#{@tmp_value.inspect})"
  end

  it 'has access to subject' do
    p subject
    assert subject.my_value < 5
  end

  it 'subject changes only between tests' do
    p subject
    assert subject.equal?(subject)
  end

  it "fails on error" do
    raise Error.new 'Sad face'
  end

  it 'works!' do
    assert @tmp_value == 'test'
  end

  before do
    @tmp_value = 'test'
    print "BEFORE_BLOCK:: Another before block"
    puts "     Set @tmp_value(#{@tmp_value.inspect})"
  end

  it 'is pending'

  after { puts "AFTER_BLOCK:: should be called first!!" }
end

I hope it is clear how this spec will end up running. This is not exactly equivalent to how RSpec will treat things (notice that we need to explicitly clear @tmp_value in an after block, where RSpec will do that for us). This is due to how RSpec creates example classses (which we are not using) and how it binds the blocks to different scopes; we are strictly using the global namespace to keep the example simple.

Check out the gist for the code and output of the sample spec: http://gist.github.com/4247624

Stay tuned for more on RSpec in the future.

=== the Forgotten Equality

Published on:

Recently I was looking for a way to do a comparison on a String with either another String or a Regexp. Most of the discussions on equality focused on ==, eql?, equal?. None of which would satisfy the requirement. So I was left with this code:

1
2
3
4
5
6
7
def matches(compare_with)
  if compare_with.is_a?(Regexp)
    @data_string =~ compare_with
  else
    @data_string == compare_with
  end
end

I was less than thrilled. So I did what everyone does, I asked the internet. Thanks to Twitter, specifically James Edward Gray II @JEG2 who btw completely rocks, I was pointed at ===. Though the documentation on === leaves something to be desired:

Used to compare each of the items with the target in the when clause of
a case statement.

The thing to remember is with case when you have the following:

1
2
3
4
case thing
when other_thing
  # stuff
end

You are just saying other_thing === thing. The comparison is performed with the when expression as the lvalue.

This means I could rewrite the matches method as:

1
2
3
def matches(compare_with)
  compare_with === @data_string
end

This also means it’s possible to be more flexible on the match:

1
2
3
4
5
# @data_string = "coding for fun"
matches "oding"           # false
matches "coding for fun"  # true
matches /oding/           # true
matches String            # true

So, the next time you’re thinking of writing some code that needs to change based on class type or how something compares with something else, think if a case statement applies. If it does, see if === works to produce better code.

Everyone Should Learn Metaprogramming

Published on:

A few weeks ago was the first Steel City Ruby conference. It was a great conference and I would highly recommend you attend next year. While there, I had the opportunity to give my first lightning talk.

An image of me presenting at SCRC12 Now I’m not one for public speaking, in fact it’s terrifying for me. However, the Ruby community is awesome, friendly, and very encouraging. After thinking about it for a while, talking with several people, and reflecting on my time participating in Scrappy Academy, I decided that it was important to speak up about metaprogramming.

I titled my talk: ”Demystifying Metaprogramming.” The intent was to encourage those people who are afraid of “metaprogramming” to give it a try. I strongly believe if you have been programming Ruby (or Rails - this is just Ruby with a fun web framework) for more than two months, you owe it to yourself to learn metaprogramming.

To most people, this included me, they hear about “metaprogramming” as this advanced technique that should be avoided by all but the most wizardly among us. Frankly, this big scary stigma attached to metaprogramming just isn’t warranted.

I’ll let you in on the big secret, “metaprogramming” is just programming. Yep. It’s not scary. It may be a bit complicated, but at the end of the day it is well worth your time to learn. You may even find it to be fun.

To help ease you into the topic, we’ll start with a simple contrived example to demonstrate that you already know everything needed to get started.

1
2
3
def say( phrase )
  puts phrase
end

Yep. That’s a really basic method. It simply puts the object that is passed in. To use this method in irb or pry we could simply:

1
2
3
4
5
6
7
> def say( phrase )
*  puts phrase
* end
=> nil
> say "Steel City Ruby I heard you like programming."
Steel City Ruby I heard you like programming.
=> nil

This shouldn’t be anything shocking so far. In fact, all we’ve done is create a method that calls a method (puts) and pass it a parameter. In fact, this concept is at the heart of the “meta” programming.

All you really are doing is writing methods, that call another method, and pass it a parameter. It just so happens that the parameter you pass, tends to be a block that defines a new method.

Write a method, that calls a method, that creates a method.*

So to extend our example and add the “meta” part to it, we’ll just:

  • Wrap our method in another method
  • Pass our method as the parameter to another method
1
2
3
4
5
6
7
def just_programming
  class_eval do
    def say( phrase )
      puts phrase
    end
  end
end

In this case, we’re using the special class_eval method. In a nutshell, this will change the value of self and then execute the block in this context. In our case, we provide it a block which contains the method definition we wish to dynmically create. The trick here is that class definitions and methods are active code. So the call to def say( phrase ) is run just as if we had typed it directly in the original class definition.

To be able to use this in a context more familiar, we’ll just wrap this in a module. We can then extend that module in our class and dynamically create our method by using our class method just_programming.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
module Meta
  def just_programming
    class_eval do
      def say( phrase )
        puts phrase
      end
    end
  end
end

class Foo
  extend Meta
  just_programming
end

f = Foo.new
f.say "Steel City Ruby I heard you like programming."
=> "Steel City Ruby I heard you like programming."

I hope this has helped illustrate that “metaprogramming” is only programming. It isn’t anything to be afraid of. Sure, it can get complicated at times, but then, what code concepts beyond the bare basics can’t?

You owe it to yourself to learn these nifty and fun coding techniques. They will demystify manly things you think are “magic”, provide a deeper understanding of the Ruby language, and add tools to your belt enabling you to write better code.

There are many resources on these topics if you do a search. Additionally, The Pragmatic Bookshelf has a good set of resources on Ruby and metaprogramming. I found the videos series on The Ruby Object Model and Metaprogramming very enlightening.

Happy programming!

* Technically, this should really be “Write a method, that sends a message, that creates a method.” However, I wanted to emphasise the progression and went with this version.