using dynamic method calling with attr_writer methods

  • Thread starter Markus Hohenhaus
  • Start date
M

Markus Hohenhaus

I'm a total Ruby newbie looking for help.

I'm writing an application where I need to dynamical assign object
variables via attr_writer object methods.

My code is something like this:

class Test < ParentClass
attr_reader :eek:ne, :two, :three
attr_writer :eek:ne, :two, :three

def initialize
super
end

end
( I know I could use attr_accessor but for testing I'll stick to
attr_writer and _reader)

Now I try to call the 'Test' methods dynamical witch 'object.send' from
within my main application:

[...]

@methods = ['one', 'two', 'three']

test = Test.new

@methods.each { |a| test.send(a, 'foo') }

[...]

This throws the error: ArgumentError: wrong number of Arguments (1 for
0)

As far as I understand, this is the correct behaviour. Because without
the second argument, the method call returns the value of the class
variable. So I believe, that this should work if i'll write all the
setter and getter methods myself (which I don't want to, because I'm
using a lot of variables).
Are there any other methods I can use to dynamically call attr_writer
methods to assign values to the class variables or did I get something
wrong and made a mistake?
 
G

Gary Wright

I'm a total Ruby newbie looking for help.
[...]
@methods.each { |a| test.send(a, 'foo') }
This throws the error: ArgumentError: wrong number of Arguments (1 for
0)

The problem is you are calling the 'getters' with an argument ('foo').
Getters don't take an argument, thus the error message. You want:

@methods.each { |a| puts test.send(a) }

I added the puts, otherwise you won't get any output.

If you want to call the setters, you need to send a different method
name:

@methods.each { |a| test.send("#{a}=", 'foo') }

And of course you need to send an argument also.

Gary Wright
 
M

Markus Hohenhaus

The problem is you are calling the 'getters' with an argument ('foo').
Getters don't take an argument, thus the error message. You want:

@methods.each { |a| puts test.send(a) }

I added the puts, otherwise you won't get any output.

Yep, this works perfectly. I already tested this.
If you want to call the setters, you need to send a different method
name:

@methods.each { |a| test.send("#{a}=", 'foo') }

And of course you need to send an argument also.

That's it!! Thanks. Now everything works as expected. Allthough I like
mine better, seems more
logical to me ;).
 
P

Phrogz

That's it!! Thanks. Now everything works as expected. Allthough I like
mine better, seems more
logical to me ;).

Well, you can do that too, if you like:

class Module
def attr_readwrite( *methods )
class_eval{
methods.each{ |method_name|
define_method( method_name ){ |*val|
val = val.first
unless val.nil?
instance_variable_set( "@#{method_name}", val )
else
instance_variable_get( "@#{method_name}" )
end
}
}
}
end
end

class Foo
attr_readwrite :foo, :bar
end

f = Foo.new

f.foo( 42 )
p f.foo
#=> 42
f.foo( 12 )
p f.foo
#=> 12


(I think there's a more elegant way to define the method and detect if
it received a value, but I was too lazy to figure it out.)

I'm pretty sure Ara T. Howard's 'attributes' gem also gives you the
ability to do what you want, where calling the method without a
parameter acts as a getter, and calling it with a parameter acts as a
setter. And I bet his way is clean. :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,969
Messages
2,570,161
Members
46,708
Latest member
SherleneF1

Latest Threads

Top