From: Sean O'Halpin Date: 2005-11-27T01:08:19+09:00 Subject: Re: Nubish questions about syntax and gems On 11/26/05, Ross Bamford wrote: 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