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 Schuerig
mailto:michael-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org
http://www.schuerig.de/michael/
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Ruby on Rails: Talk" group.
To post to this group, send email to
rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
To unsubscribe from this group, send email to
rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
For more options, visit this group at
http://groups.google.com/group/rubyonrails-talk?hl=en
-~----------~----~----~----~------~----~------~--~---
Michael Schuerig wrote:> I''m looking for a nice and idiomatic way to merge options hashes.The Ruby newsgroup deserves to work on questions like this. news:comp.lang.ruby -- Phlip http://www.greencheese.us/ZeekLand <-- NOT a blog!!! --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Doesn''t it depend on which direction you decide to conduct the merge? E.g.: existing_options.merge(new_options) will overwrite existing keys (which is normally what you want if existing options specify defaults). However: new_options.merge(existing_options) will cause any keys present in new_options to be overwritten by those in existing_options (if they exist). I don''t know if this answers the question, but I hope it helps... Michael Schuerig wrote:> > > > 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 Schuerig > mailto:michael-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org > http://www.schuerig.de/michael/ > > > > >-- View this message in context: http://www.nabble.com/-Rails--Idiomatic-way-to-merge-%22multivalued%22-options-tf3133390.html#a8682416 Sent from the RubyOnRails Users mailing list archive at Nabble.com. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---