From: Ross Bamford Date: 2005-11-27T04:07:28+09:00 Subject: Re: Nubish questions about syntax and gems Hi Sean, On Sat, 26 Nov 2005 16:08:19 -0000, Sean O'Halpin wrote: > 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: > >> [...] > > define_method method_name do > puts "You called #{method_name}" > end > Ahh, I should have known to check Module :) I'm still getting used to methods coming from all angles. > > 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. > Interesting, I didn't know that (about block args to blocks). I guess if I wanted to pass a block in that way, I'd have to get a Proc for the closure? I've seen code like: some_method(proc { |s| s.do_something }) which seems a bit nasty to me. > Also note the differences in scope between using "def ... end" and a > define_method + a closure. > Okay, I'm with you there. >> >> 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 > Nice one. Gotta get used to this 'effectively adding keywords' thing too. I've gotten around the fact that class definitions can call methods, now I need to get used to it being _my_ methods :) > 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). > This is where I am going around in circles. It's an instance of Class, but it also has a class, Class. So, Class.class == Class. Is that right ? > When you open a class (with say "class A"), all the subsequent statements > are executed in the context of that class instance object. > Yes, I kind of got that, but I wasn't thinking about it properly. I've been playing around with bindings and instance_eval a bit, and the 'self = current object' idea I have to say makes a lot of sense. I see now though, that theres more depth here than I first thought when it comes to the class definition. > 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 Hmm, I think I need to go back to the book on class variables. I can't quite see how they fit in, especially with respect to singleton class and stuff. Thanks for your explanation, though - it's just me :( I'll probably be asking again after I confuse myself some more ;) Cheers for your reply. -- Ross Bamford - rosco@roscopeco.remove.co.uk