Иногда бывают моменты, когда Вам может быть нужно создать набор спецификаций для rspec, отличающихся одним-двумя вызовами или параметрами. У меня в проекте сложилась такая ситуация, и я решил попробовать использовать возможности Ruby для динамической генерации кода чтобы, сделать spec-файлы короче и избежать дублирования.

У меня есть хелпер, который используется в нескольких универсальных темплейтах для генерации похожих страниц. Этот хелпер возвращвет URL по набору параметров и типу ссылки. Он может принимать 5 различных типов ссылок и выбрасывает исключение с случаях, когда тип ссылки не поддерживается. Без использования динамической генерации кода мне пришлось бы создать 5 различных спецификаций (по одной для каждого типа ссылок) для того, чтобы иметь возможность видеть каждый тип ссылок отдельной строкой в результатах теста. С использованием же динамической генерации код выглядит примерно так:

describe VideoHelper, 'when profile_video_url method called' do
  before do
    @user = mock('user')
  end
 
  url_types = {
    'personal_feed' => 'personal_feed',
    'favorites' => 'favorites',
    'voted' => 'voted_videos',
    'posted' => 'posted_videos',
    'commented' => 'commented_videos'
  }
 
  url_types.each do |url_type, route|
    it "should return #{route}_url for #{url_type} type urls" do
      @user.should_receive(:login).at_least(1).times.and_return('login')
      profile_video_url(url_type, @user, 2, 'expert').should == send("#{route}_url", @user, 2, 'expert')
    end
  end
 
  it 'should raise ArgumentError("Invalid feed type") on invalid url_types' do
    lambda { profile_video_url('crap', @user, 2, 'expert') }.should raise_error(ArgumentError, 'Invalid feed type')
  end
end

Эта техника может быть использована даже для целых describe-секций, но я не буду приводить здесь гору кода, который получился у меня. Так или иначе, идея предельно проста: вы можете использовать любые циклы с секцией describe внутри и вызовами метода send() для динамического конструирования Вашего кода.