[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

struct equivalent with rails-y keyword args hash?

Giles Bowkett

1/9/2008 5:03:00 AM

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 Bowkett

Podcast: http://hollywoodgrit.bl...
Blog: http://gilesbowkett.bl...
Portfolio: http://www.gilesg...
Tumblelog: http://giles....

9 Answers

ara.t.howard

1/9/2008 5:09:00 AM

0


On Jan 8, 2008, at 10:02 PM, Giles Bowkett 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://codeforp...
--
share your knowledge. it's a way to achieve immortality.
h.h. the 14th dalai lama



Michael Fellinger

1/9/2008 5:38:00 AM

0

On Jan 9, 2008 2:02 PM, Giles Bowkett <gilesb@gmail.com> wrote:
> 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?

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>

Robert Klemme

1/9/2008 12:11:00 PM

0

2008/1/9, Giles Bowkett <gilesb@gmail.com>:
> 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)

Then just use that form.

Kind regards

robert

--
use.inject do |as, often| as.you_can - without end

James Gray

1/9/2008 2:14:00 PM

0

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

> 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)

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 Gray II

Giles Bowkett

1/9/2008 6:14:00 PM

0

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

> 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>

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 Bowkett

Podcast: http://hollywoodgrit.bl...
Blog: http://gilesbowkett.bl...
Portfolio: http://www.gilesg...
Tumblelog: http://giles....

Robert Klemme

1/9/2008 6:26:00 PM

0

On 09.01.2008 19:13, Giles Bowkett wrote:
> several good suggestions but I think this is the one I'll run with:
>
>> 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>
>
> 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.
>

Folks, why do you run around implementing something? The desired
behavior *is already present* with Struct.

Cheers

robert

Giles Bowkett

1/9/2008 6:38:00 PM

0

> 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 Bowkett

Podcast: http://hollywoodgrit.bl...
Blog: http://gilesbowkett.bl...
Portfolio: http://www.gilesg...
Tumblelog: http://giles....

Robert Klemme

1/10/2008 7:22:00 AM

0

On 09.01.2008 19:37, Giles Bowkett wrote:
>> 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.

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

Robert Klemme

1/10/2008 8:49:00 AM

0

2008/1/10, Robert Klemme <shortcutter@googlemail.com>:
> On 09.01.2008 19:37, Giles Bowkett wrote:
> >> 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.
>
> 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

--
use.inject do |as, often| as.you_can - without end