assert_latest{} detects new model objects

Railsers:

This simple test shows assert_latest{} in action:

     c1, c2 = assert_latest Chat do
                Chat.create(:user => aaron, :utterance => 'foo')
                Chat.create(:user => becky, :utterance => 'bar')
              end

     assert{ c1.utterance == 'foo' }
     assert{ c2.utterance == 'bar' }

assert_latest{} sampled the maximum Chat id before yielding to its block. Then it returned any records found with an id greater than that maximum. This helps us write more elaborate production code, which might not return its new objects to its callers.

This blog describes assert_latest's rationale and original functionality:

   http://www.oreillynet.com/onlamp/blog/2007/07/assert_latest_and_greatest.html

The latest and greatest version of assert_latest{} contains some new features.

Firstly, the assertion now takes any number of model types. That prevents this icky situation:

   chat = nil
   prop = assert_latest Prop do
     chat = assert_latest Chat do
       production_code_that_props_and_chats()
     end
   end
   assert{ chat.user == prop.user }

The nested blocks interfered with chat's scope, forcing un-Ruby-like contortions when you need to compare the two returned objects. And assert_latest{} is not DRY - it appears twice!

To reduce duplication, you may now pass both models into one assert_latest call. You can also drop in a diagnostic string:

     p, c = assert_latest Prop, Chat, 'diagnostic' do
              Prop.create(:name => 'foo', :price => 42)
              Chat.create(:user => aaron, :utterance => 'bar')
            end

     assert{ p.name == 'foo' }
     assert{ c.utterance == 'bar' }

The returned objects can be individual items, or arrays of returned items:

     p, cz = assert_latest Prop, Chat do
               Prop.create(:name => 'foo', :price => 42)
               Chat.create(:user => aaron, :utterance => 'foo')
               Chat.create(:user => aaron, :utterance => 'bar')
             end

     assert{ p.name == 'foo' }
     assert{ cz.first.utterance == 'foo' }
     assert{ cz. last.utterance == 'bar' }

Ruby lets you unroll those returned arrays. This allows you to check your returned count implicitly:

     p, (c1, c2) = assert_latest Prop, Chat do
        ...

I added assert_latest{} (and its evil twin, deny_latest{}) to the assert_efficient_sql package, because they both require ActiveRecord. Get them all, on the usual channels, with Piston:

   piston import svn://rubyforge.org/var/svn/efficient-sql/ \
                      vendor/plugins/efficient-sql

Oh, one more feature. When assert_latest fails, it reflects its called block's source into its diagnostic. That requires the RubyReflector module that
assert{ 2.0 } uses, so you will need that too:

   gem install assert2