I hope can answer some of your questions:
1) Is this the right way to define a method with a dynamic name?
eval <<-EOC
def #{method_name}
'You called #{method_name}'
end
EOC
it seems to(?) work, but I wonder if theres a better way?
You can also use define_method, but it has limitations:
class A
def hello
puts "hello"
end
end
a = A.new
a.hello
method_name = "hello"
A.class_eval {
define_method method_name do
puts "You called #{method_name}"
end
}
a.hello
-- OUTPUT --
hello
You called hello
You can't define methods that take blocks (as you can't pass a block
argument to a block) which means that you need to use your original method
(eval + string) if you want to dynamically create a method that takes
a block argument.
Also note the differences in scope between using "def ... end" and a
define_method + a closure.
2) I'm struggling with boolean attributes, and question marks.
attr_accessor (etc) won't allow me to pass those names in (I guess because
they're illegal instance var names). I tried:
attr_accessor :is_green
alias is_green? is_green
which works, but again it strikes me theres probably a better way that
I've missed.
I can't think of a standard way to do this that is quicker but you could
do this:
class Module
def predicate(*names)
names.each do |name|
attr_accessor name
alias_method "#{name}?", name
end
end
end
class A
predicate :is_green
end
a = A.new
a.is_green = true
p a.is_green?
-- OUTPUT --
true
3) Does this
class MyClass
@field = "one"
end
create a class or instance variable? And from that, does
class MyClass
@@field = "one"
end
create a class variable on MyClass, Class, or something else? I've tried a
few experiments and am more confused than when I started
Just to add a comment to David's explanation.
class A
@foo = "A's foo"
end
p A.instance_eval { @foo }
A.instance_eval { @foo = "A's foo again" }
class A
puts @foo
end
-- OUTPUT --
A's foo
A's foo again
The thing to get your head around is that a class is an object in its own right
(i.e. it is an instance of class Class).
When you open a class (with say "class A"), all the subsequent statements
are executed in the context of that class instance object.
Regarding @@class_variables - they work a bit like globals within a
class hierarchy. For example:
class Model
@@models =
def models
@@models
end
end
class Element < Model
@@models = ['Hello from Element']
end
class Schema < Model
@@models = ['Hello from Schema']
end
e = Element.new
p e.models
__END__
["Hello from Schema"]
In other words, they do not belong to a class as such but a class hierarchy.
(Note how setting @@models in Schema has changed it for Element).
Personally, I avoid using @@class_variables and use class instance variables
(with accessors) instead - much less chance of accidentally stomping on
another class's state.
Regards,
Sean
···
On 11/26/05, Ross Bamford <rosco@roscopeco.remove.co.uk> wrote: