I have one remaining open issue in my GitHub tracker: links between recipes are missing. I made a go at fixing the problem last night, but had to back out when the fix was growing too large.
Part of the problem is that the helper method responsible for linking to the next record in a CouchDB view has grown long and complicated:
def link_to_adjacent_view_date(current, couch_view, options={})The most obvious obstacle in adapting this helper for use with recipes is the line that produces the
# If looking for the record previous to this one, then we seek a
# date prior to the current one - build a Proc capable of
# finding that
compare = options[:previous] ?
Proc.new { |date_fragment, current| date_fragment < current} :
Proc.new { |date_fragment, current| date_fragment > current}
# If looking for the record previous to this one, then we need
# to reverse the list before using the compare Proc to detect
# the record
next_result = couch_view.
send(options[:previous] ? :reverse : :map).
detect{|result| compare[result['key'], current.to_s]}
# If a next record was found, then return link text
if next_result
next_uri = next_result['id'].gsub(/-/, '/')
link_text = block_given? ?
yield(next_result['id'], next_result['value']) :
next_result['id']
%Q|<a href="/meals/#{next_uri}">#{link_text}</a>|
else
""
end
end
<a>
tag—the "/meals" URI-space is hard coded in there. But how to drive the URI-space in that method? The quickest means of accomplishing this is to add a urispace argument to the
link_to_adjacent_view_date
helper. That is not an acceptable option in my mind because link_to_adjacent_view_date
already has an explicit arity of 3. I barely remember what the three arguments do—adding a fourth is going to make it impossible. Hiding it in the options
hash argument is disingenuous, at best.I called it an explicit arity of 3 earlier because this helper takes a fourth block argument. It is the responsibility of the block to build the link text. Given that the actual arity is 4, adding yet another argument is right out. But I ought to be able to increase the responsibility of the block—instead of building the link text, it can build the entire link.
In other words, given a CouchDB view with results from April and May of 2009:
before(:each) doThen, when working with the record adjacent to April 2009, I should be able to build a link to the value from May, "bar" in this case:
@by_month = [{"key" => "2009-04", "value" => "foo"},
{"key" => "2009-05", "value" => "bar"}]
end
it "should link to the CouchDB view's key and value, if block is given" doI can make that pass with a somewhat simpler output conditional:
link_to_adjacent_view_date("2009-04", @by_month) do |rec|
%Q|<a href="/foo">#{rec}</a>|
end.
should have_selector("a",
:href => "/foo",
:content => "bar")
end
# If a next record was found, then return link textIf a block if given, the result of the conditional is the entire block itself. If no block is given, then a default, meal-centric (for backward compatibility) string results.
if next_result
if block_given?
yield next_result['value']
else
next_uri = next_result['key'].gsub(/-/, '/')
%Q|<a href="/meals/#{next_uri}">#{next_result['key']}</a>|
end
else
""
end
The specs all pass for the helper. As expected, the specs for the meal view fail (since it is not longer generating a link to the text. After correcting that, I drive intra-recipe links. The specs are largely based on the intra-meal links, making the process relatively easy. And, like that, intra-recipe links are working:
I close the issue with that fix, but I am not happy with the ultimate solution. I think that Rails concepts and habits have had a bad influence on me in this case. Specifically, I am treating helpers like Rails's view helpers and
RestClient
calls to CouchDB as model interactions. Neither is the case. In simple Sinatra apps, helpers can help views or controllers and RestClient
is pulling back Hash
objects, not MVC models.Ultimately, I think a cleaner solution would have been to have the
link_to_adjacent_view_date
helper request the appropriate CouchDB view directly, using limit=1
to pull back the single next record. Since I have this working, I leave that to another day with a TODO
note.
No comments:
Post a Comment