# Struct equivalent with rails-y keyword args hash?

**URL:** <https://www.ruby-forum.com/t/struct-equivalent-with-rails-y-keyword-args-hash/125445>\
**Category:** Ruby\
**Created:** [January 9, 2008, 6:03am UTC](https://www.ruby-forum.com/t/struct-equivalent-with-rails-y-keyword-args-hash/125445 "2008-01-09T06:03:11Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![Giles\_B](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/848f3c/32.png) [@Giles\_B](https://www.ruby-forum.com/u/Giles_B)\
**Post date:** [January 9, 2008, 6:03am UTC](https://www.ruby-forum.com/t/struct-equivalent-with-rails-y-keyword-args-hash/125445/1 "2008-01-09T06:03:11Z")

</div>

I have some code which uses Structs. I’d rather use keyword args. I’m  
generating data objects to store MIDI note data, and it’s kind of  
hideously unreadable:

Note.new(2, 43, 0.25, 127, now += interval)

This would be much nicer:

Note.new(:channel =\> 2,  
:note =\> 43,  
:duration =\> 0.25,  
:velocity =\> 127,  
:time =\> now += interval)

(God I wish I could configure bloody Gmail to use monospaced fonts.)

Anyway, is there an easy equivalent to Struct which, instead of taking  
stuff in sequence, takes a Hash of options, in a Rails-y style? Like a  
HashStruct? Does Facets have such a thing, maybe haps? If not, is the  
basic code for Struct in Ruby, and/or is a class like Struct but with  
Hashes easy to build?

–  
Giles B.

Podcast: [http://hollywoodgrit.blogspot.com](http://hollywoodgrit.blogspot.com)  
Blog: [http://gilesbowkett.blogspot.com](http://gilesbowkett.blogspot.com)  
Portfolio: [http://www.gilesgoatboy.org](http://www.gilesgoatboy.org)  
Tumblelog: [http://giles.tumblr.com](http://giles.tumblr.com)

---

<div class="post-metadata">

**Author:** ![Giles\_B](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/848f3c/32.png) [@Giles\_B](https://www.ruby-forum.com/u/Giles_B)\
**Post date:** [January 9, 2008, 6:10am UTC](https://www.ruby-forum.com/t/struct-equivalent-with-rails-y-keyword-args-hash/125445/2 "2008-01-09T06:10:12Z")

</div>

On Jan 8, 2008, at 10:02 PM, Giles B. wrote:

> Anyway, is there an easy equivalent to Struct which, instead of taking  
> stuff in sequence, takes a Hash of options, in a Rails-y style? Like a  
> HashStruct? Does Facets have such a thing, maybe haps? If not, is the  
> basic code for Struct in Ruby, and/or is a class like Struct but with  
> Hashes easy to build?

i use this alot in rails projects:

require ‘attributes’

class OpenObject  
alias\_method “ **inspect** ”, “inspect”  
alias\_method “ **to\_s** ”, “to\_s”  
alias\_method “ **instance\_eval** ”, “instance\_eval”

```
 instance_methods.each{|m| undef_method m unless m[%r/__/]}

```

alias\_method “instance\_eval”, “ **instance\_eval** ”  
alias\_method “inspect”, “ **inspect** ”  
alias\_method “to\_s”, “ **to\_s** ”

def method\_missing m, \*a, &b  
super if(a.empty? and b.nil?)  
m = m.to\_s  
setter = m.delete!(‘=’) || a.first || b  
if setter  
if a.empty?  
**attribute** m, &b  
else  
**attribute** m =\> a.shift  
end  
else  
nil  
end  
end

def configure kvs = {}, &b  
kvs.each{|k,v| **attribute** k =\> v}  
**instance\_eval** &b if b  
end  
alias\_method “initialize”, “configure”  
alias\_method “eval”, “configure”

def **singleton\_class** &b  
sc =  
class \<\< self  
self  
end  
b ? sc.module\_eval(&b) : sc  
end

def extend \*a, &b  
if b  
**singleton\_class** &b  
self  
else  
super  
end  
end  
alias\_method “extending”, “extend”

def attributes \*a, &b  
**attributes** \*a, &b  
end

def to\_hash  
**attributes**.inject(Hash.new){|h,a| h.update a =\> **send** (a)}  
end

def as\_query  
require ‘cgi’  
e = lambda{|x| CGI.escape x.to\_s}  
to\_hash.map{|k,v| “#{ e[k] }=#{ e[v] }”}.join(“&”)  
end

def respond\_to? \*a, &b  
true  
end  
end  
def openobject(\*a, &b) OpenObject.new(\*a, &b) end

class Object  
def Open \*a, &b  
OpenObject.new(\*a, &b)  
end  
end

it’s all that and so much more.

a @ [http://codeforpeople.com/](http://codeforpeople.com/)

---

<div class="post-metadata">

**Author:** ![Giles\_B](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/848f3c/32.png) [@Giles\_B](https://www.ruby-forum.com/u/Giles_B)\
**Post date:** [January 9, 2008, 1:11pm UTC](https://www.ruby-forum.com/t/struct-equivalent-with-rails-y-keyword-args-hash/125445/3 "2008-01-09T13:11:39Z")

</div>

2008/1/9, Giles B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> ```
> :duration => 0.25,
> :velocity => 127,
> :time => now += interval)
> 
> ```

Then just use that form.

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![Giles\_B](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/848f3c/32.png) [@Giles\_B](https://www.ruby-forum.com/u/Giles_B)\
**Post date:** [January 9, 2008, 6:38am UTC](https://www.ruby-forum.com/t/struct-equivalent-with-rails-y-keyword-args-hash/125445/4 "2008-01-09T06:38:49Z")

</div>

On Jan 9, 2008 2:02 PM, Giles B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> ```
> :duration => 0.25,
> :velocity => 127,
> :time => now += interval)
> 
> ```
> 
> (God I wish I could configure bloody Gmail to use monospaced fonts.)
> 
> Anyway, is there an easy equivalent to Struct which, instead of taking  
> stuff in sequence, takes a Hash of options, in a Rails-y style? Like a  
> HashStruct? Does Facets have such a thing, maybe haps? If not, is the  
> basic code for Struct in Ruby, and/or is a class like Struct but with  
> Hashes easy to build?

One possibility, method for Note only:

manveru@pi ~ % irb  
class Note \< Struct.new(:channel, :note, :duration, :velocity, :time)  
def self.create(hash)  
new(\*hash.values\_at(\*members.map{|m| m.to\_sym}))  
end  
end

# nil

Note.create(:channel =\> 1, :note =\> 2, :duration =\> 3, :velocity =\> 3,  
:time =\> Time.now)

# #\<struct Note channel=1, note=2, duration=3, velocity=3, time=Wed

Jan 09 14:36:21 +0900 2008\>

Second one, method for all Structs:

manveru@pi ~ % irb  
class Struct  
def self.create(hash)  
new(\*hash.values\_at(\*members.map{|m| m.to\_sym}))  
end  
end

# nil

Note = Struct.new(:channel, :note, :duration, :velocity, :time)

# Note

Note.create(:channel =\> 1, :note =\> 2, :duration =\> 3, :velocity =\> 3,  
:time =\> Time.now)

# #\<struct Note channel=1, note=2, duration=3, velocity=3, time=Wed

Jan 09 14:37:20 +0900 2008\>

---

<div class="post-metadata">

**Author:** ![Giles\_B](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/848f3c/32.png) [@Giles\_B](https://www.ruby-forum.com/u/Giles_B)\
**Post date:** [January 9, 2008, 3:14pm UTC](https://www.ruby-forum.com/t/struct-equivalent-with-rails-y-keyword-args-hash/125445/5 "2008-01-09T15:14:45Z")

</div>

On Jan 8, 2008, at 11:02 PM, Giles B. wrote:

> ```
> :duration => 0.25,
> :velocity => 127,
> :time => now += interval)
> 
> ```

One way is:

require “ostruct”

now = Time.now  
interval = 5  
note = OpenStruct.new( :channel =\> 2,  
:note =\> 43,  
:duration =\> 0.25,  
:velocity =\> 127,  
:time =\> now + interval )  
note.channel # =\> 2  
note.velocity # =\> 127

**END**

James Edward G. II

---

<div class="post-metadata">

**Author:** ![Giles\_B](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/848f3c/32.png) [@Giles\_B](https://www.ruby-forum.com/u/Giles_B)\
**Post date:** [January 9, 2008, 7:15pm UTC](https://www.ruby-forum.com/t/struct-equivalent-with-rails-y-keyword-args-hash/125445/6 "2008-01-09T19:15:14Z")

</div>

several good suggestions but I think this is the one I’ll run with:

> # Note
> 
> Note.create(:channel =\> 1, :note =\> 2, :duration =\> 3, :velocity =\> 3,  
> :time =\> Time.now)
> 
> # #\<struct Note channel=1, note=2, duration=3, velocity=3, time=Wed
> 
> Jan 09 14:37:20 +0900 2008\>

Ara’s seems the most robust, but with so much going on and no specs it  
makes me antsy; the OpenStruct looks good too but I want classes as  
well as instances.

–  
Giles B.

Podcast: [http://hollywoodgrit.blogspot.com](http://hollywoodgrit.blogspot.com)  
Blog: [http://gilesbowkett.blogspot.com](http://gilesbowkett.blogspot.com)  
Portfolio: [http://www.gilesgoatboy.org](http://www.gilesgoatboy.org)  
Tumblelog: [http://giles.tumblr.com](http://giles.tumblr.com)

---

<div class="post-metadata">

**Author:** ![Giles\_B](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/848f3c/32.png) [@Giles\_B](https://www.ruby-forum.com/u/Giles_B)\
**Post date:** [January 9, 2008, 7:31pm UTC](https://www.ruby-forum.com/t/struct-equivalent-with-rails-y-keyword-args-hash/125445/7 "2008-01-09T19:31:10Z")

</div>

On 09.01.2008 19:13, Giles B. wrote:

> > # nil

Folks, why do you run around implementing something? The desired  
behavior _is already present_ with Struct.

Cheers

robert

---

<div class="post-metadata">

**Author:** ![Giles\_B](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/848f3c/32.png) [@Giles\_B](https://www.ruby-forum.com/u/Giles_B)\
**Post date:** [January 10, 2008, 8:25am UTC](https://www.ruby-forum.com/t/struct-equivalent-with-rails-y-keyword-args-hash/125445/8 "2008-01-10T08:25:28Z")

</div>

On 09.01.2008 19:37, Giles B. wrote:

> It just stores the hash.  
> Argh!! You are right, I am wrong. I’m sorry, should have payed  
> attention more closely to the output of #inspect. I think I’ll better  
> shut up now.

Cheers

robert

---

<div class="post-metadata">

**Author:** ![Giles\_B](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/848f3c/32.png) [@Giles\_B](https://www.ruby-forum.com/u/Giles_B)\
**Post date:** [January 9, 2008, 7:38pm UTC](https://www.ruby-forum.com/t/struct-equivalent-with-rails-y-keyword-args-hash/125445/9 "2008-01-09T19:38:50Z")

</div>

> Folks, why do you run around implementing something? The desired  
> behavior _is already present_ with Struct.

I tried your code example, and it didn’t work.

class Note \< Struct.new(:channel) ; end

Note.new(:channel =\> 2)  
Note.channel # =\> “{:channel =\> 2}”

It just stores the hash.

–  
Giles B.

Podcast: [http://hollywoodgrit.blogspot.com](http://hollywoodgrit.blogspot.com)  
Blog: [http://gilesbowkett.blogspot.com](http://gilesbowkett.blogspot.com)  
Portfolio: [http://www.gilesgoatboy.org](http://www.gilesgoatboy.org)  
Tumblelog: [http://giles.tumblr.com](http://giles.tumblr.com)

---

<div class="post-metadata">

**Author:** ![Giles\_B](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/848f3c/32.png) [@Giles\_B](https://www.ruby-forum.com/u/Giles_B)\
**Post date:** [November 18, 2011, 1:19pm UTC](https://www.ruby-forum.com/t/struct-equivalent-with-rails-y-keyword-args-hash/125445/10 "2011-11-18T13:19:23Z")

</div>

This thread has been idle for a while, but in case anybody’s still  
watching…

I’ve long wanted the same thing as was originally requested, and I too  
couldn’t find a gem anywhere that has it. So I wrote one. See

```
  http://rubygems.org/gems/key_struct

```

Hope it’s useful to others. Hope if I’ve re-invented the wheel somebody  
will point me to an existing gem.

---

<div class="post-metadata">

**Author:** ![Giles\_B](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/848f3c/32.png) [@Giles\_B](https://www.ruby-forum.com/u/Giles_B)\
**Post date:** [January 10, 2008, 9:49am UTC](https://www.ruby-forum.com/t/struct-equivalent-with-rails-y-keyword-args-hash/125445/11 "2008-01-10T09:49:15Z")

</div>

2008/1/10, Robert K. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> > It just stores the hash.
> 
> Argh!! You are right, I am wrong. I’m sorry, should have payed  
> attention more closely to the output of #inspect. I think I’ll better  
> shut up now.

Hm, could not resist… Here is another variant:

Note = Struct.new(:channel, :note, :duration, :velocity, :time) do  
def self.create(hash)  
new(\*members.map {|me| hash[me.to\_sym]})  
end  
end

irb(main):016:0\* now = interval = 1  
=\> 1  
irb(main):017:0\> n = Note.new(:channel =\> 2,  
irb(main):018:1\* :note =\> 43,  
irb(main):019:1\* :duration =\> 0.25,  
irb(main):020:1\* :velocity =\> 127,  
irb(main):021:1\* :time =\> now += interval)  
=\> #\<struct Note channel={:channel=\>2, :note=\>43, :duration=\>0.25,  
:velocity=\>127, :time=\>2}, note=nil, duration=nil, ve  
locity=nil, time=nil\>  
irb(main):022:0\>

🙂

robert
