Tuesday, May 19, 2009

Deep Inside View By Month

‹prev | My Chain | next›

Continuing work on viewing meals by month, I work my way into the Sinatra application tonight. Specifying how the application will use the meals-per-month CouchDB views:
    describe "GET /meals/YYYY/MM" do
it "should respond OK" do
get "/meals/2009/05"
response.should be_ok
end

it "should ask CouchDB for meal from year YYYY and month MM" do
RestClient.
should_receive(:get).
with(/key=...2009-05/).
and_return('{"rows": [] }')

get "/meals/2009/05"
end

it "should ask CouchDB how many meals from all months" do
RestClient.
should_receive(:get).
with(/meals.+count_by_month/).
and_return('{"rows": [{"key":"2009-04","value":3},
{"key":"2009-05","value":3}]}')

get "/meals/2009/05"
end
end
That's very similar to the meal-by-year specification. Not surprisingly the code that makes these examples pass is also similar to the code that made the meal-by-year examples pass:
get %r{/meals/(\d+)/(\d+)} do |year, month|
url = "#{@@db}/_design/meals/_view/by_year?group=true&key=%22#{year}-#{month}%22"
data = RestClient.get url
@meals = JSON.parse(data)
@year = year

url = "#{@@db}/_design/meals/_view/count_by_month?group=true"
data = RestClient.get url
@count_by_year = JSON.parse(data)['rows']

haml :meal_by_month
end
While I'm at it, I also add the meals by_month and count_by_month CouchDB views:
{
"views": {
"by_month": {
"map": "function (doc) {
if (doc['type'] == 'Meal') {
emit(doc['date'].substring(0, 7), [doc['_id'], doc['title']]);
}
}",
"reduce": "function(keys, values, rereduce) { return values; }"
},
"count_by_month": {
"map": "function (doc) {
if (doc['type'] == 'Meal') {
emit(doc['date'].substring(0, 7), 1);
}
}",
"reduce": "function(keys, values, rereduce) { return sum(values); }"
}
},
"language": "javascript"
}
They are completely based on the by-year views. I will certainly have to add something to them, but I will defer the addition until I really need it.

With that, it is time to start fleshing out the Haml view. For meals-by-month, we display the title, the summary and a thumbnail image. The example that describes the title (with the setup):
describe "meal_by_month.haml" do
before(:each) do
assigns[:meals] = {
'rows' => [
{ "value" => [['2009-05-14', 'Meal 1']]},
{ "value" => [['2009-05-15', 'Meal 2']]},
]
}
assigns[:year] = 2009
assigns[:month] = '05'
assigns[:count_by_year] = [{"key" => "2009-04", "value" => 3},
{"key" => "2009-05", "value" => 3}]

end

it "should include each meal's title" do
render("/views/meal_by_month.haml")
response.should have_selector("h2", :content => "Meal 1")
end
end
To make that example pass, I need a simple iterator over the meals in the result set (along with some semantic markup):
%h1= "Meals from #{@year}-#{@month}"

.meals
- @meals["rows"].each do |meal|
%h2= meal['value'][0][1]
That will suffice as a stopping point for tonight. I will pick up with the remaining view specs tomorrow.

No comments:

Post a Comment