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!
···
--
Adriano
--
Posted via http://www.ruby-forum.com/.
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
}
···
On Thu, May 20, 2010 at 06:59, Adriano Nagel <anr@safira.com> wrote:
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!
--
Adriano
--
Posted via http://www.ruby-forum.com/\.
--
Thanks & Regards,
Dhruva Sagar.
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 ?
···
On Thu, May 20, 2010 at 06:59, Adriano Nagel <anr@safira.com> wrote:
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!
--
Adriano
--
Posted via http://www.ruby-forum.com/\.
--
Thanks & Regards,
Dhruva Sagar.
Dhruva Sagar wrote:
Should be
instance_eval %{
def status_all(*args)
"#{args.join(' ')}".split
end
}
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
Thanks,
···
--
Adriano
--
Posted via http://www.ruby-forum.com/\.
Dhruva Sagar wrote:
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
Actually, args already is an array and you don't need it as an argument
for status_all (it was passed to status_field).
But the problem here is that this will produce an instance method, not a
class method.
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 ?
I'm extending ActiveRecord, and status_field does more than just define
status_all. For example:
class User < ActiveRecord::Base
status_field :inactive, :active, :suspended
end
will create scopes, instance methods like status_inactive,
status_inactive?, etc.
User.status_all should return all the possible user status. I have it
working, but I would like to learn a better way to do it.
Thanks,
···
--
Adriano
--
Posted via http://www.ruby-forum.com/\.
Adriano Nagel wrote:
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,
···
--
Adriano
--
Posted via http://www.ruby-forum.com/\.
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
···
On Thu, May 20, 2010 at 07:28, Adriano Nagel <anr@safira.com> wrote:
Dhruva Sagar wrote:
> Should be
>
> instance_eval %{
> def status_all(*args)
> "#{args.join(' ')}".split
> end
> }
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
Thanks,
--
Adriano
--
Posted via http://www.ruby-forum.com/\.
--
Thanks & Regards,
Dhruva Sagar.
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
···
On Thu, May 20, 2010 at 08:54, Adriano Nagel <anr@safira.com> wrote:
Dhruva Sagar wrote:
> 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
Actually, args already is an array and you don't need it as an argument
for status_all (it was passed to status_field).
But the problem here is that this will produce an instance method, not a
class method.
> 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 ?
I'm extending ActiveRecord, and status_field does more than just define
status_all. For example:
class User < ActiveRecord::Base
status_field :inactive, :active, :suspended
end
will create scopes, instance methods like status_inactive,
status_inactive?, etc.
User.status_all should return all the possible user status. I have it
working, but I would like to learn a better way to do it.
Thanks,
--
Adriano
--
Posted via http://www.ruby-forum.com/\.
--
Thanks & Regards,
Dhruva Sagar.
Dhruva Sagar wrote:
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,
···
--
Adriano
--
Posted via http://www.ruby-forum.com/\.
Dhruva Sagar wrote:
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,
···
--
Adriano
--
Posted via http://www.ruby-forum.com/\.
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/the-difference-between-eval-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 
···
On Thu, May 20, 2010 at 09:42, Adriano Nagel <anr@safira.com> wrote:
Dhruva Sagar wrote:
> 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,
--
Adriano
--
Posted via http://www.ruby-forum.com/\.
--
Thanks & Regards,
Dhruva Sagar.