Questions about meta-programming in a shared_examples group

I’ve created a shared_examples group that helps me dry up the testing of
a large set of similar rails controllers.

These controllers have an html interface but mostly what I am testing
with the shared_examples group is the rendering of four
different forms of xml that relate to running a dynamically created Java
Web Start jnlp.

The html reports when running one of the controller specs looks like
this:

Embeddable::DataCollectorsController GET show with mime type of otml
renders the requested data_collector as otml without error

Here’s an example of what one of the controller specs looks like:

http://github.com/stepheneb/rigse/blob/master/spec/controllers/embeddable/data_collectors_controller_spec.rb

require ‘spec_helper’

describe Embeddable::DataCollectorsController do

 it_should_behave_like 'an embeddable controller'

 def with_tags_like_an_otml_data_collector
   with_tag('OTDataCollector') do
     with_tag('source') do
       with_tag('OTDataGraphable') do
         with_tag('dataProducer')
       end
     end
     with_tag('xDataAxis') do
       with_tag('OTDataAxis')
     end
     with_tag('yDataAxis') do
       with_tag('OTDataAxis')
     end
   end
 end

end

I love how clearly each controller spec reads now and how the part that
is different in the otml rendering stands out.

But I wondered if the way I am using lambdas in the shared_examples
helper is fragile and might break if internals in rspec
change. The meta-programming I did to get some of this to work seemed a
bit messy and I was wondering if there was a simpler
way.

The describe statement in the shared_examples_for ‘an embeddable
controller’ for that example looks like this:

describe “with mime type of otml” do
it “renders the requested #{model_ivar_name_lambda.call} as otml
without error” do

The beginning of the shared_examples group looks like this:

http://github.com/stepheneb/rigse/blob/master/spec/support/embeddable_controller_helper.rb

shared_examples_for ‘an embeddable controller’ do
integrate_views

 controller_class_lambda = lambda {
   self.send(:described_class)
 }
 model_class_lambda      = lambda {
   controller_class_lambda.call.name[/(.*)Controller/, 

1].singularize.constantize
}
model_ivar_name_lambda = lambda {
model_class_lambda.call.name.delete_module.underscore_module
}

 def with_tags_like_an_otml(model_name)
   self.send("with_tags_like_an_otml_#{model_name}".to_sym)
 end

 before(:each) do
   @model_class = model_class_lambda.call
   @model_ivar_name = model_ivar_name_lambda.call
   unless instance_variable_defined?("@#{@model_ivar_name}".to_sym)
     @model_ivar = instance_variable_set("@#{@model_ivar_name}",
       Factory.create(@model_ivar_name))
   end
 end

The method in the controller spec: with_tags_like_an_otml_data_collector
is used in the shared_examples group later like this:

with_tag(‘library’) do
with_tags_like_an_otml(@model_ivar_name)
end

Hi Stephen,

On May 10, 2010, at 8:48 PM, Stephen B. wrote:

   with_tag('source') do
 end

end

end

I love how clearly each controller spec reads now and how the part that is different in the otml rendering stands out.

But I wondered if the way I am using lambdas in the shared_examples helper is fragile and might break if internals in rspec change. The meta-programming I did to get some of this to work seemed a bit messy and I was wondering if there was a simpler way.

The most obvious problem is that “have_tag” and “with_tag” will not be
supported in rspec-rails-2.

I haven’t looked at it in a while, but you may want to take a look at
the assert2 gem. It’s mostly focused on test/unit assertions, but there
is an rspec matcher named be_html_with that offers a nice dsl for
something close to what you’re trying to do. Check the bottom of
http://groups.google.com/group/merb/browse_thread/thread/3588d3f75fa0e65c.