I’m looking for a nice and idiomatic way to merge options hashes. The
usual ways for scalar-valued options are
def my_method(options = {})
options = {
:foo => ‘something’,
:bar => ‘else’
}.update(options)
…
end
and
def my_method(options = {})
options = options.reverse_merge(
:foo => ‘something’,
:bar => ‘else’
)
…
end
The cases I’m interested in are different. For illustration, let’s take
a helper method that inserts a text field into the page and adds the
class attribute “special”. In particular, it should not overwrite
existing class attribute options, only add a new one.
def my_special_text_field1(object, field, options = {})
if options[:class]
options[:class] += ’ special’
else
options[:class] = ‘special’
end
text_field(object, field, options)
end
That’s rather clumsy. How about this, then
def my_special_text_field2(object, field, options = {})
options[:class] =
(String(options[:class]).split(/\s+/) | [‘special’]) * ’ ’
text_field(object, field, options)
end
Ugh. Well, it has the added advantage that duplicates are not added.
Alas, the code is not very obvious. But with a bit of encapsulation and
class opening that can be rectified.
def my_special_text_field3(object, field, options = {})
text_field(object, field,
options.merge_multivalued(:class => ‘special’))
end
class Hash
def merge_multivalued(other_hash)
merge_arrays(other_hash) do |old_value, other_array|
(String(old_value).split(/\s+/) | other_array) * ’ ’
end
end
private
def merge_arrays(other_hash, &block)
# add values from other_hash to already present values
merged_old = inject({}) do |memo, (key, value)|
if other_value = other_hash[key]
other_array = other_value.kind_of?(Array) ?
other_value : other_value.split(/\s+/)
memo[key] = block[value, other_array]
else
memo[key] = value
end
memo
end
# add new values from other_hash
other_hash.merge(merged_old)
end
end
That does look a bit over-engineered. Here’s a minimalist (and slightly
rogueish) alternative.
def my_special_text_field4(object, field, options = {})
options[:class] = (Array(options[:class]) | [‘special’]) * ’ ’
text_field(object, field, options)
end
After all this, I still can’t say that I’m fully satisfied with any of
the options. I’m looking forward to suggestions.
Michael
–
Michael S.
mailto:[email protected]
http://www.schuerig.de/michael/