[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

obj.send(attr) = value

ryanslists

5/28/2006 8:51:00 PM

Hello,

I would like to do something very simple -- assign a value to an object
attribute that has been accessed dynamically.

In Perl, this would be

my %hash = (foo => 90890, bar =>34243);
$obj->$_($hash{$_}) foreach keys %hash;

In Ruby I tried

obj.send(attr) = foo.attr

but it exploded with an error.

I found a very complicated four year old thread on comp.lang.ruby
called "dynamically assigning instance variables:"

http://groups.google.com/group/comp.lang.ruby/browse_thread/thread/b2aab9a5478ae552/bebbab29a34c759e?lnk=st&q=ruby+send+name+attribute+assign&rnum=1#bebbab...

It is 27 posts long and contains baroque syntax like

def biv(attributes)
attributes.each do |k, v|
type.send(:defin, k)
send(k.to_s + "=", v)
end
end

This can't be the only way to do such a simple thing in Ruby ... or is
it? Also, if so, where can I learn more about why the equals sign is
considered part of the method name?

Thanks for any help!
Ryan Tate

5 Answers

Tim Hunter

5/28/2006 10:11:00 PM

0

ryanslists@gmail.com wrote:
> Hello,
>
> I would like to do something very simple -- assign a value to an object
> attribute that has been accessed dynamically.
>
> In Perl, this would be
>
> my %hash = (foo => 90890, bar =>34243);
> $obj->$_($hash{$_}) foreach keys %hash;
>
> In Ruby I tried
>
> obj.send(attr) = foo.attr
>
> but it exploded with an error.
>
> I found a very complicated four year old thread on comp.lang.ruby
> called "dynamically assigning instance variables:"
>
> http://groups.google.com/group/comp.lang.ruby/browse_thread/thread/b2aab9a5478ae552/bebbab29a34c759e?lnk=st&q=ruby+send+name+attribute+assign&rnum=1#bebbab...
>
> It is 27 posts long and contains baroque syntax like
>
> def biv(attributes)
> attributes.each do |k, v|
> type.send(:defin, k)
> send(k.to_s + "=", v)
> end
> end
>
> This can't be the only way to do such a simple thing in Ruby ... or is
> it? Also, if so, where can I learn more about why the equals sign is
> considered part of the method name?
>
> Thanks for any help!
> Ryan Tate
>

Read about Ruby's attr_reader, attr_writer, and attr_accessor methods.
These helper methods define an instance variable and either an attribute
reader method, an attribute writer method, or both.

class MyClass
attr_accessor :myvar
end

Here the attr_accessor method defines on your behalf the variable
@myvar, the reader method myvar() and the writer method myvar=(). The
methods are defined like this:

def myvar
@myvar
end

def myvar=(x)
@myvar = x
end


When Ruby sees:

x = MyClass.new
x.myvar = 1

Then it calls x.myvar=(1).

If you want to use __send__ ("send" is deprecated in favor of "__send__"
now) to call the attribute writer, you'd use

x.__send__("myvar=", 1)

If you have the name of the attribute in a variable, to call its writer
method you might use something like this (remember that "+" is string
concatenation):

var = "myvar"
x.__send__(var + "=", 1)

It's very common to use symbols instead of strings for things like
method names (like I did in the attr_accessor call above), so you might
instead have the attribute name as a symbol in a variable. You can't use
"+" on a symbol so you have to convert the symbol to a string with to_s:

var = :myvar
x.__send__(var.to_s + "=", 1)

Starting to make sense now?

ryanslists

5/29/2006 12:56:00 AM

0

Thanks Tim, the attr_* docs did explain well the whole methodname=
thing. It sounds like I do have to use the relatively baroque syntax,
which I guess is fine.

It just seems inelegant by ruby standards -- it would be cool if there
was a method called __attr_write__ or somesuch --
obj.__attr_write__(methodname, value). I'm also not sure why
obj.__send__(methodname, value) doesn't just work --- I guess there is
difference between method arguments and assigned values --
obj.foo(a,b,c) = value is valid maybe? As you can see I am new to the
language.

Also, the .__send__ over .send is hugely lame, but whatever Done
decision apparently And I can keep using for now ;->

Do appreciate your help.

Best regards,
RT

Tim Hunter

5/29/2006 1:17:00 AM

0

ryanslists@gmail.com wrote:
> Thanks Tim, the attr_* docs did explain well the whole methodname=
> thing. It sounds like I do have to use the relatively baroque syntax,
> which I guess is fine.
>
> It just seems inelegant by ruby standards -- it would be cool if there
> was a method called __attr_write__ or somesuch --
> obj.__attr_write__(methodname, value). I'm also not sure why
> obj.__send__(methodname, value) doesn't just work --- I guess there is
> difference between method arguments and assigned values --
> obj.foo(a,b,c) = value is valid maybe? As you can see I am new to the
> language.
>
> Also, the .__send__ over .send is hugely lame, but whatever Done
> decision apparently And I can keep using for now ;->
>
> Do appreciate your help.
>
> Best regards,
> RT
>

A few weeks ago I read some good advice for Ruby newbies: Use Ruby for
90 days before making any judgments. This will give you an opportunity
to see how the language fits together. There's a reason behind
everything you're questioning.

Robert Klemme

5/29/2006 7:19:00 AM

0

ryanslists@gmail.com wrote:
> Thanks Tim, the attr_* docs did explain well the whole methodname=
> thing. It sounds like I do have to use the relatively baroque syntax,
> which I guess is fine.
>
> It just seems inelegant by ruby standards -- it would be cool if there
> was a method called __attr_write__ or somesuch --
> obj.__attr_write__(methodname, value). I'm also not sure why
> obj.__send__(methodname, value) doesn't just work --- I guess there is
> difference between method arguments and assigned values --
> obj.foo(a,b,c) = value is valid maybe? As you can see I am new to the
> language.
>
> Also, the .__send__ over .send is hugely lame, but whatever Done
> decision apparently And I can keep using for now ;->
>
> Do appreciate your help.
>
> Best regards,
> RT
>

You need to do

obj.send("#{attr_name}=", val)

and not

obj.send(attr_name) = val

Kind regards

robert

Dave Burt

5/30/2006 8:30:00 AM

0

Robert Klemme wrote:
> You need to do
>
> obj.send("#{attr_name}=", val)
>
> and not
>
> obj.send(attr_name) = val

Alternatively, you can define an attribute accessor that accepts an
optional setter parameter:

class Foo
def bar(*args)
@bar = *args unless args.empty?
@bar
end
end

and use it like this:

obj.send("bar", new_value)

The Traits library on RubyForge adds default values and inheritability
as well as this ("trait 'bar'" will define a method like the above) --
you might want to check that out, too.

Cheers,
Dave