Thursday, October 1, 2009

Ingredients, in Batches

‹prev | My Chain | next›

Picking back up with my ingredient index:
  it "should link to the recipes" do
render("/views/ingredients.haml")
response.should have_selector("a", :count => 3)
end
The expectation that there should be three links in the output comes from the setup block. There are two recipes, one of which appears under two different ingredients in the index:
  before(:each) do
@ingredients = [{'butter' =>
[
['recipe-id-1', 'title 1'],
['recipe-id-2', 'title 2']
]
},
{'sugar' =>
[
['recipe-id-2', 'title 2']
]
}]
end
When I run the spec, this latest example fails:
jaynestown% spec ./spec/views/ingredients.haml_spec.rb -cfs

ingredients.haml
- should have a list of ingredients
- should have a list of recipes using the ingredients
- should link to the recipes (FAILED - 1)

1)
'ingredients.haml should link to the recipes' FAILED
expected following output to contain a <a/> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body>
<p>
<span class="ingredient">
butter
</span>
<span class="recipes">
title 1, title 2
</span>
</p>
<p>
<span class="ingredient">
sugar
</span>
<span class="recipes">
title 2
</span>
</p>
butterrecipe-id-1title 1recipe-id-2title 2sugarrecipe-id-2title 2
</body></html>

./spec/views/ingredients.haml_spec.rb:30:

Finished in 0.03 seconds

3 examples, 1 failure
To get the 3 links (and make the example pass), I add links to the Haml template:
= @ingredients.each do |ingredient|
%p
%span.ingredient
= ingredient.keys.first
%span.recipes
= ingredient.values.first.map{|recipe| %Q|<a href="">#{recipe[1]}</a>|}.join(", ")
Easy enough, but the href attribute is empty. To drive that, I will focus on one recipe, one context:
  context "an ingredient is used in only one recipe" do
it "should have one link to that recipe" do
render("/views/ingredients.haml")
response.should have_selector("a",
:href => "/recipes/recipe-id-1",
:content => "title 1",
:count => 1)
end
end
For good measure, I also describe the case of multiple recipes sharing a recipe:
  context "an ingredient is used in multiple recipes" do
it "should have multiple links to that recipe" do
render("/views/ingredients.haml")
response.should have_selector("a",
:href => "/recipes/recipe-id-2",
:content => "title 2",
:count => 2)
end
end
Adding the hyperlink to the <a> in the Haml templaate:
      = ingredient.values.first.map{|recipe| %Q|<a href="/recipes/#{recipe[0]}">#{recipe[1]}</a>|}.join(", ")
Makes all examples pass:
jaynestown% spec ./spec/views/ingredients.haml_spec.rb -cfs

ingredients.haml
- should have a list of ingredients
- should have a list of recipes using the ingredients
- should link to the recipes

ingredients.haml an ingredient is used in only one recipe
- should have one link to that recipe

ingredients.haml an ingredient is used in multiple recipes
- should have one link to that recipe

Finished in 0.02 seconds

5 examples, 0 failures
The last thing that needs to go on this page are two columns. In the legacy site, we found that the index looked best with two columns:



I write two, paired examples for this output behavior:
  it "should put half of the ingredients in the first column" do
render("/views/ingredients.haml")
response.should have_selector(".col1", :content => "butter")
end

it "should put the other half of the ingredients in the second column" do
render("/views/ingredients.haml")
response.should have_selector(".col2", :content => "sugar")
end
I can make that pass with a table (for the two columns) and batching the ingredients into two:
%table
%tr
- col = 0
- @ingredients.each_slice((@ingredients.size.to_f/2).round) do |batch|
- col = col + 1
%td{:class => "col#{col}"}
= batch.each do |ingredient|
...
I dislike using accumulators (col), but there is no each_slice_with_index in Enumerator, so...

With that, I am done with my inside code work on this mini-feature. Tomorrow, I will work my way back out to the Cucumber scenario to verify that all the pieces work when put together.

1 comment: