In the past, in environments other than Rails, I''ve a couple of times
gainfully used path expressions to refer to objects in the UI-layer.
Now, in Rails, I''m already using them for creating lists where columns
are described by meta data. I take it that there are even more an
better uses. I haven''t thought this through carefully, so here are just
one example.
Currently, to get a text input field one writes something like this
<%= text_field ''address'', ''street'' %>
This requires the existence of a binding for ''address'' in the
template.
Now assume the address is reachable from another object,
''person'',
anyway. Then how about writing it like this instead:
<%= text_field ''person.address.street'' %>
which is meant to result in this HTML
<input type="text" id="person_address_street"
name="person[address][street]" value="..." />
For iteration over multiple values a wildcard, ''*'', could be
used in the
path. For the moment I don''t quite see how to make this really useful,
though.
I think a fairly minimal language for expressing paths is sufficient in
Rails as there''s always Ruby to fall back on. Full-grown navigational
language such as XPath-applied-to-objects or OGNL (Java) are more
appropriate for environments where the host language is not accessible.
Below is my first stab at an extended Object#send method that handles
paths. I''m interested in your thoughts.
Michael
class Object
alias_method :send_without_path, :send
def send(path, *args)
if path.kind_of?(Symbol)
return self.send_without_path(path, *args)
elsif path.kind_of?(Array)
path = path.dup
elsif path.kind_of?(String)
path = path.split(''.'')
else
raise TypeError, "Unrecognized path type for send:
<#{path}>"
end
method = path.shift
case
when method == ''*''
raise TypeError, "Wildcard path item is only applicable to
Enumerables; self: <#{self}>" unless self.kind_of?(Enumerable)
if !path.empty?
next_value = self.inject([]) { |result, elem|
result << elem.send(path, *args)
}
else
next_value = self
end
return next_value
when self.respond_to?(method)
next_value = self.send_without_path(method, *args)
when self.respond_to?(''[]'')
next_value = self.send_without_path(''[]'', method, *args)
else
raise TypeError, "Can''t advance path to
''#{method}''; no applicable
method for <#{self.inspect}>"
end
if not path.empty?
next_value.send(path, *args)
else
next_value
end
end
end
--
Michael Schuerig Failures to use one''s frontal lobes
mailto:michael-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org can result in the
loss of them.
http://www.schuerig.de/michael/ --William H. Calvin