define_method inside instance_eval

A

Adriano Nagel

Hi,

I'm trying to create a class macro that, when called, defines a class
method that returns the array passed to the class macro.

For example, I'd have something like this in an included module:

def status_field(*args)
instance_eval { define_method:)status_all) { args } }
end

(I've put a complete example at http://gist.github.com/407035).

I was under the impression that methods created inside instance_eval
would be defined inside the singleton class, but apparently
define_method seems to ignore that (why?).

So I used the string form of instance_eval and produced this eyesore:

instance_eval %{
def status_all
"#{args.join(' ')}".split
end
}

I must be missing something. Any hints on how to solve this problem
properly? I'd also like to avoid using eval on strings.

Thanks!
 
D

Dhruva Sagar

[Note: parts of this message were removed to make it a legal post.]

Well the first thing that I see is that your missing the (*args) in the
method

instance_eval %{
def status_all
"#{args.join(' ')}".split
end
}

Should be

instance_eval %{
def status_all(*args)
"#{args.join(' ')}".split
end
}
 
A

Adriano Nagel

Adriano said:
Sorry, I wasn't clear. This snippet is actually wrapped inside the class
macro, like this:

def status_field(*args)
instance_eval %{
def status_all
"#{args.join(' ')}".split
end
}
end

BTW, it sort of works. But I don't like it at all... It is brittle,
probably unsafe and slow.

I'd like to use a block syntax, for instance.

Thanks,
 
A

Adriano Nagel

Dhruva said:
You can do this :

def status_field(*args)
instance_eval { define_method:)status_all) {|*args| "#{args.join('
')}".split } }
end

or you can do this :

def status_field(*args)
class << self
def status_all(*args)
"#{args.join(' ')}".split
end
end
end

Dhruva, I'd like to get rid of the string manipulation, it would be much
cleaner without it. BTW, the args variable is passed to status_field but
not to status_all to keep things DRY.

Thanks,
 
D

Dhruva Sagar

[Note: parts of this message were removed to make it a legal post.]

Ok I reread your problem.

In your status_all method you can simply return a *args.to_a*. That should
be the simplest approach.

def status_field(*args)
instance_eval { define_method:)status_all) {|*args| args.to_a } }
end

But I am not sure exactly why your taking this approach or what your
intentions are. What should be the behavior on subsequent calls to
status_field ?
 
D

Dhruva Sagar

[Note: parts of this message were removed to make it a legal post.]

To define class methods from a class method :

def status_field(*args)
self.metaclass.send:)define_method, :status_all) { args }
end

OR

def status_field(*args)
(class << self; self; end).instance_eval { define_method:)status_all) {
args } }
end
 
A

Adriano Nagel

Dhruva said:
def status_field(*args)
(class << self; self; end).instance_eval { define_method:)status_all) {
args } }
end

Yep, this works.

Notice that, once you open the metaclass, you can use either
instance_eval or class_eval to define a singleton method.

I guess I still can't come to terms with define_method not generating a
singleton method when used inside instance_eval :)

This is on Ruby 1.8.7. Maybe this is a bug?

Regards,
 
D

Dhruva Sagar

[Note: parts of this message were removed to make it a legal post.]

Its not a bug imo
I am pretty much a amateur and so I keep getting confused between the
various eval methods myself.
Check out this article -
http://web.elctech.com/2009/01/14/t...val-class_eval-module_eval-and-instance_eval/

<http://web.elctech.com/2009/01/14/t...val-class_eval-module_eval-and-instance_eval/>Seems
like if your method status_field was a class method

def self.status_field(*args)

then instance_eval should perhaps create a class method as demonstrated in
the article.

Maybe someone who knows better should also comment :)
 

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,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top