Eval, attr_* like methods

(Patrick Gundlach) #1

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

(Brian Schröder) #2

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,

Brian

···

On 12/08/05, Patrick Gundlach <clr7.10.randomuser@spamgourmet.com> wrote:

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

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

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

(Patrick Gundlach) #3

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

(David A. Black) #4

Hi --

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

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

# However.....

   p test1 => "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}=") do |v|
           instance_variable_set("@#{arg}", v)
         end
       end
     end
   end

or similar.

David

···

On Sat, 13 Aug 2005, [ISO-8859-1] Brian Schröder wrote:

On 12/08/05, Patrick Gundlach <clr7.10.randomuser@spamgourmet.com> wrote:

--
David A. Black
dblack@wobblini.net

(Patrick Gundlach) #5

[...]

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

(Patrick Gundlach) #6

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

(Navindra Umanee) #7

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.

···

Patrick Gundlach <clr7.10.randomuser@spamgourmet.com> wrote:

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

(Dave Burt) #8

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

(Charles Steinman) #9

Patrick Gundlach wrote:

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.

(Dave Burt) #10

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

(Patrick Gundlach) #11

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