eval, attr_* like methods

P

Patrick Gundlach

Dear all,

I'd like to create methods similar to the attr_* way. I'd like to
write

class Foo
lookup_meth :bar, :baz

def some_other_methods
....
end

end

The lookup_meth should define for class Foo methods such as

def bar
# tricky lookup stuff
return value
end
def bar=(obj)
@bar=obj
end


How would I write such lookup_meth? I've been playing a bit with eval,
but I didn't get it quite right.

Patrick
 
B

Brian Schröder

Dear all,
=20
I'd like to create methods similar to the attr_* way. I'd like to
write
=20
class Foo
lookup_meth :bar, :baz
=20
def some_other_methods
....
end
=20
end
=20
The lookup_meth should define for class Foo methods such as
=20
def bar
# tricky lookup stuff
return value
end
def bar=3D(obj)
@bar=3Dobj
end
=20
=20
How would I write such lookup_meth? I've been playing a bit with eval,
but I didn't get it quite right.
=20
Patrick
=20
=20

class Object
def self.lookup_meth(*args)
args.each do | name |
eval %(
def #{name}
=09@#{name} ||=3D '24'
end

def #{name}=3D(arg)
=09@#{name} =3D arg
end
)
end
end
end

class Test
lookup_meth :test1, :test2

def testme
p self.test1
self.test1 =3D 42
p self.test1
end
end

Test.new.testme
=3D>=20
"24"
42

Hope that helps,

Brian

--=20
http://ruby.brian-schroeder.de/

Stringed instrument chords: http://chordlist.brian-schroeder.de/
 
P

Patrick Gundlach

Hello Brian,
class Object
def self.lookup_meth(*args)
args.each do | name |
eval %(
def #{name}
@#{name} ||= '24'
end

def #{name}=(arg)
@#{name} = arg
end
)
end
end
end

class Test
lookup_meth :test1, :test2

def testme
p self.test1
self.test1 = 42
p self.test1
end
end

Test.new.testme
=>
"24"
42

Hope that helps,

Yes, it helps! But there are two more questions left: since this
lookup_meth is defined in Ojbect, it might get overridden by another
method definition of the same name, right? Is it possible to move this
definition somewhere 'closer' to my classes? And number two: I have
one variable that I need to check. Example:

def self.lookup_meth(*args)
args.each do | name |
eval %(
def #{name}
if @othervar # <-----------
puts "hello"
end
@#{name} ||= '24'
end

Any way to avoid a warning about 'instance variable @othervar not
initialized'?

Thanks so far,

Patrick
 
P

Patrick Gundlach

[...]
Any way to avoid a warning about 'instance variable @othervar not
initialized'?

This warning doesn't show up in production code. Strange.... I'll
investigate.

Patrick
 
D

David A. Black

--8323328-1026756949-1123867032=:16311
Content-Type: MULTIPART/MIXED; BOUNDARY="8323328-1026756949-1123867032=:16311"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

--8323328-1026756949-1123867032=:16311
Content-Type: TEXT/PLAIN; charset=X-UNKNOWN; format=flowed
Content-Transfer-Encoding: QUOTED-PRINTABLE

Hi --

class Object
def self.lookup_meth(*args)
args.each do | name |
eval %(
def #{name}
=09@#{name} ||=3D '24'
end

def #{name}=3D(arg)
=09@#{name} =3D arg
end
)
end
end
end

class Test
lookup_meth :test1, :test2

def testme
p self.test1
self.test1 =3D 42
p self.test1
end
end

Test.new.testme
=3D>
"24"
42

# However.....

p test1 =3D> "24"

You've defined them as instance methods of Object, so they appear at
the top level.

You'd probably want:

class Module
def lookup_meth(*args)
args.each do |arg|
define_method(arg) do
instance_variable_get("@#{arg}")
end
define_method("#{arg}=3D") do |v|
instance_variable_set("@#{arg}", v)
end
end
end
end

or similar.


David

--=20
David A. Black
(e-mail address removed)
--8323328-1026756949-1123867032=:16311--
--8323328-1026756949-1123867032=:16311--
 
P

Patrick Gundlach

Hello David,

[...]
You'd probably want:

class Module
def lookup_meth(*args)
args.each do |arg|
define_method(arg) do
instance_variable_get("@#{arg}")
end
define_method("#{arg}=3D") do |v|
instance_variable_set("@#{arg}", v)
end
end
end
end

That's cool. Where does 'Module' come into play? What part of

class Foo ; end

is or is related to 'Module'? Hmm, I think I see: class is an instance
of Class, which is a subclass of Module, right? So the above with

class Class
def lookup_meth(*args)
args.each do |arg|
....

should do the same? But why is 'def' not a method of Class? Or would
be this too tricky to implement, so it is part of some other level of
parsing?

Patrick
 
C

Charles Steinman

Patrick said:
That's cool. Where does 'Module' come into play? What part of

class Foo ; end

is or is related to 'Module'? Hmm, I think I see: class is an instance
of Class, which is a subclass of Module, right?

That's right.
class Class
def lookup_meth(*args)
args.each do |arg|
....

should do the same?

For classes, yes. It would not work with modules, obviously.
But why is 'def' not a method of Class? Or would
be this too tricky to implement, so it is part of some other level of
parsing?

It wouldn't work to make def a method, because what goes after "def"
(e.g. "my_cool_method(something, something_else)") isn't a valid object
in Ruby. You can use Module#define_method if you want something similar.
 
N

Navindra Umanee

Patrick Gundlach said:
Yes, it helps! But there are two more questions left: since this
lookup_meth is defined in Ojbect, it might get overridden by another
method definition of the same name, right? Is it possible to move this
definition somewhere 'closer' to my classes? And number two: I have

You can move it as close as to the class itself. It's just a class
method. Or you could put it in a super-class and inherit from that.

class Test
def self.do_something(*args)
puts "doing something with #{args}"
end
end

class Test
do_something :foobar
end

Cheers,
Navin.
 
D

Dave Burt

Patrick Gundlach asked:
... since this
lookup_meth is defined in Ojbect, it might get overridden by another
method definition of the same name, right? Is it possible to move this
definition somewhere 'closer' to my classes?

You can define your lookup_meth in the target class directly:
class Test
def self.lookup_meth(*args)
#...
end
lookup_meth :test1, :test2
end

Or you can define it in a module, and extend the classes you want to use it
in:
module LookupMeth
def lookup_meth(*args)
#... (no changes required here)
end
end
class Test
extend LookupMeth
lookup_meth :test1, :test2
end
And number two: I have
one variable that I need to check. Example:

def self.lookup_meth(*args)
args.each do | name |
eval %(
def #{name}
if @othervar # <-----------
puts "hello"
end
@#{name} ||= '24'
end

Any way to avoid a warning about 'instance variable @othervar not
initialized'?

You can initialize the variable the line before:
@othervar ||= nil
Or you can change your if condition:
if defined?(@otherbar) && @othervar

Cheers,
Dave
 
D

Dave Burt

I wrote earlier:
You can define your lookup_meth in the target class directly:
...
Or you can define it in a module, and extend the classes you want to use
it in:

I'd like to add that Dwemthy's Array does a similar kind of thing, and is an
interesting game, and you should have a read, and maybe try and get through
the Array.

http://poignantguide.net/dwemthy/

Here's a teaser:
class Dragon < Creature
life 1340 # tough scales
strength 451 # bristling veins
charisma 1020 # toothy smile
weapon 939 # fire breath
end

Cheers,

Dave
 
P

Patrick Gundlach

Hi Dave,
I'd like to add that Dwemthy's Array does a similar kind of thing, and is an
interesting game, and you should have a read, and maybe try and get through
the Array.

http://poignantguide.net/dwemthy/
Here's a teaser:
class Dragon < Creature
life 1340 # tough scales
strength 451 # bristling veins
charisma 1020 # toothy smile
weapon 939 # fire breath
end


Thats really neat. Thanks Why for this examples and for the pretty
nice guide.


Patrick
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top