Tuesday, June 16, 2009

Categorizing Meals

‹prev | My Chain | next›

The next couple of items in the navigation-from-the-homepage Cucumber involve clicking through to a meal:



The next undefined step is "When I click on the first meal". Hmm... I think I forgot to link to the meals from the homepage. Looking closer I find an example that superficially describes linking to meals, but actually only verifies that it includes the title text:
  it "should link to the meal titles" do
render("/views/index.haml")
response.should have_selector("h2", :content => "Bar")
end
I rename that example as "should include meal titles". Then I create the real example for linking to meals:
  it "should link to the the meal titles" do
render("/views/index.haml")
response.should have_selector("a",
:href => "/meals/2009/05/15",
:content => "Bar")
end
Once I get that passing by adding the appropriate %a Haml tag, it is time to move back to the Cucumber scenario. I can mark the next two steps as passing at this point. I can both click a meal link and verify that I am on the meal page:
When /^I click on the first meal$/ do
click_link "Meal 0"
end

Then /^I should see the meal page$/ do
response.should have_selector("h1",
:content => "Meal 0")
end
Those two steps pass, putting me half way through the exploration-from-the-homepage scenario:



The next "then" step states that "the Italian category should be highlighted". I already have something similar for the recipe page:
%ul#eee-categories
%li= recipe_category_link(@recipe, 'Italian')
%li= recipe_category_link(@recipe, 'Asian')
...
To determine if a meal is Italian, each of the recipes on the menu need to be checked. If any of them are Italian, then the meal will be considered Italian. So I'll need to load the recipes and I'll need to update the recipe_category_link to handle more than one recipe.

First up, loading a recipe from wiki text. For text similar to "[recipe:2009/06/16]", CouchDB should be queried and the results parsed:
describe "wiki_recipe" do
before(:each) do
@json = '{"_id":"2009-06-16-recipe","title":"Recipe for Foo"}'
end
it "should lookup a recipe from recipe wiki text" do
RestClient.
should_receive(:get).
with(/2009-06-16/).
and_return(@json)

wiki_recipe(" [recipe:2009/06/16]")
end
it "should return a recipe from recipe wiki text" do
RestClient.
stub!(:get).
and_return(@json)

wiki_recipe(" [recipe:2009/06/16]").
should == { "_id" => "2009-06-16-recipe",
"title" => "Recipe for Foo" }

end
it "should return nil for non-recipe wiki text" do
wiki_recipe("[rcip:2009/06/16]").should be_nil
end
end
I can make those three examples pass with:
    def wiki_recipe(text)
if text =~ /\[recipe:([-\/\w]+)/
permalink = $1.gsub(/\//, '-')
JSON.parse(RestClient.get("#{_db}/#{permalink}"))
end
end
When viewing a meal, I load all recipes into an instance variable in the Sinatra app:
  @recipes = @meal['menu'].map { |m| wiki_recipe(m) }.compact
With the Sinatra app using wiki_recipe to lookup recipes, I need to get recipe_category_link to use multiple recipes to determine whether or not to highlight category links. The example uses two "recipes", one with an "italian" category, which should highlight the link:
  it "should create an active link if any recipes include the category" do
recipes = [{ 'tag_names' => ['italian'] },
{ 'tag_names' => ['foo'] }]
recipe_category_link(recipes, 'Italian').
should have_selector("a", :class => "active")
end
I make that example pass (while keeping the existing, non-array examples passing) with:
    def recipe_category_link(recipe, category)
recipes = recipe.is_a?(Array) ? recipe : [recipe]
if recipes.any? { |r|
r['tag_names'] &&
r['tag_names'].include?(category.downcase)
}
%Q|<a class="active">#{category}</a>|
else
%Q|<a>#{category}</a>|
end
end
I then use the new recipe_category_link and the @recipes instance variable assigned in the Sinatra application to build category links in the meal Haml template:
%ul#eee-categories
%li= recipe_category_link(@recipes, 'Italian')
%li= recipe_category_link(@recipes, 'Asian')
%li= recipe_category_link(@recipes, 'Latin')
%li= recipe_category_link(@recipes, 'Breakfast')
%li= recipe_category_link(@recipes, 'Chicken')
%li= recipe_category_link(@recipes, 'Fish')
%li= recipe_category_link(@recipes, 'Meat')
%li= recipe_category_link(@recipes, 'Salad')
%li= recipe_category_link(@recipes, 'Vegetarian')
%li
%a Recipes
Finally, with that in place, I work back out to the Cucumber scenario. Implementing the Italian-category-should-be-highlighted step:
Then /^the Italian category should be highlighted$/ do
response.should have_selector("a",
:class => "active",
:content => "Italian")
end
And now, I am one step closer to being done with this scenario:


(commit)

Astute readers will note that the recipe_category_link omits the href attribute. It is not much of a link without that attribute. Fortunately, subsequent steps in this scenario cover this omission. Something for another day.

No comments:

Post a Comment