# Idiomatic way to merge "multivalued" options

**URL:** <https://www.ruby-forum.com/t/idiomatic-way-to-merge-multivalued-options/83705>\
**Category:** Rails\
**Created:** [January 29, 2007, 1:35am UTC](https://www.ruby-forum.com/t/idiomatic-way-to-merge-multivalued-options/83705 "2007-01-29T01:35:28Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![wickie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/ba9def/32.png) [@wickie](https://www.ruby-forum.com/u/wickie)\
**Post date:** [January 29, 2007, 1:35am UTC](https://www.ruby-forum.com/t/idiomatic-way-to-merge-multivalued-options/83705/1 "2007-01-29T01:35:28Z")

</div>

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:removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
[http://www.schuerig.de/michael/](http://www.schuerig.de/michael/)

---

<div class="post-metadata">

**Author:** ![wickie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/ba9def/32.png) [@wickie](https://www.ruby-forum.com/u/wickie)\
**Post date:** [January 29, 2007, 1:48am UTC](https://www.ruby-forum.com/t/idiomatic-way-to-merge-multivalued-options/83705/2 "2007-01-29T01:48:29Z")

</div>

Michael S. 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  
[Redirecting...](http://www.greencheese.us/ZeekLand) ← NOT a blog!!!

---

<div class="post-metadata">

**Author:** ![wickie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/ba9def/32.png) [@wickie](https://www.ruby-forum.com/u/wickie)\
**Post date:** [January 29, 2007, 1:49am UTC](https://www.ruby-forum.com/t/idiomatic-way-to-merge-multivalued-options/83705/3 "2007-01-29T01:49:29Z")

</div>

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 S. wrote:

> ```
> }.update(options)
> ...
> else
> text_field(object, field, options)
> 
> # add values from other_hash to already present values
> # add new values from other_hash
> 
> ```
> 
> end
> 
> >

–  
View this message in context:  
[http://www.nabble.com/-Rails--Idiomatic-way-to-merge-"multivalued"-options-tf3133390.html#a8682416](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](http://Nabble.com).
