I have have several model classes for which I want some shared behavior. I wanted their parent class to create class methods for the child classes ... something like "set_table_name" does. So I followed the code and I adapted code from ActionRecord::Base.define_attr_method. The following does what I want, but I can''t understand what the " sing = class << self; self; end " code is doing and is there any less obscure way to still capture the context of the passed in fields? --------- class Parent < ActionRecord::Base def self.special_fields [] end def self.set_special_fields(fields) sing = class << self; self; end sing.send( :define_method, "special_fields") {fields} end end class Child1 < Parent set_special_fields [1] end class Child2 < Parent set_special_fields [2, 3] end puts "Parent.special_fields: " + Parent.special_fields.inspect puts "Child1.special_fields: " + Child1.special_fields.inspect puts "Child2.special_fields: " + Child2.special_fields.inspect puts "Child1.special_fields: " + Child1.special_fields.inspect gives: Parent.special_fields: [] Child1.special_fields: [1] Child2.special_fields: [2, 3] Child1.special_fields: [1]
Steve Downey wrote:> I have have several model classes for which I want some shared > behavior. I wanted their parent class to create class methods for the > child classes ... something like "set_table_name" does. > > So I followed the code and I adapted code from > ActionRecord::Base.define_attr_method. The following does what I want, > but I can''t understand what the " sing = class << self; self; end " > code is doing and is there any less obscure way to still capture the > context of the passed in fields?What they are doing is opening the class of the current object. The current object happens to be the class that you are in. Essentially all it is doing is adding a singleton method the current class. Example: class A def self.set_fields( args ) s = class << self; self; end s.send( :define_method, "special_fields" ){ args } end end is adding the method ''special_fields'' to the class A. So you can now say: A.set_fields( "a b c d" ) A.special_fields #=> which returns "a b c d" You could rewrite the above to something like: class A def self.set_fields( args ) self.class.send( :define_method, "special_fields" ){ args } end end A.set_fields( "a b c d" ) A.special_fields #=> which returns "a b c d" You should note that: s = class << self; self; end is returning the last value evaluated inside of the "class << self; .... ; end" block. If you said: s = class << self; 5; end then ''s'' would be equal to 5. Opening the class definition for the current object just to return itself is silly in my opinion, and it makes the code look more cryptic. I would suggest to keep it clean with: s = self.class if you want to get the class of the current object. I hope this helps more then it hurts. =) Zach
> What they are doing is opening the class of the current object. The > current object happens to be the class that you are in. > > Essentially all it is doing is adding a singleton method the current > class. > > Example: > class A > def self.set_fields( args ) > s = class << self; self; end > s.send( :define_method, "special_fields" ){ args } > end > end > > is adding the method ''special_fields'' to the class A. So you can now say: > > A.set_fields( "a b c d" ) > A.special_fields #=> which returns "a b c d" > > You could rewrite the above to something like: > > class A > def self.set_fields( args ) > self.class.send( :define_method, "special_fields" ){ args } > end > end > > A.set_fields( "a b c d" ) > A.special_fields #=> which returns "a b c d" > > You should note that: > s = class << self; self; end > > is returning the last value evaluated inside of the "class << self; > .... ; end" block. If you said: > s = class << self; 5; end > > then ''s'' would be equal to 5. Opening the class definition for the > current object just to return itself is silly in my opinion, and it > makes the code look more cryptic. I would suggest to keep it clean with: > s = self.class > > if you want to get the class of the current object. I hope this helps > more then it hurts. =) >It helped ... a little. But I tried some of the alternatives that you have with no luck for my case with sub-classes. From http://www.rubygarden.org/ruby?SingletonTutorial, this seems to explain it ... sort of ...: " But you can use it to define methods within that class, without using ''def'' which makes local variables drop out of scope."
Zach Dennis wrote:> class A > def self.set_fields( args ) > self.class.send( :define_method, "special_fields" ){ args } > end > end > > A.set_fields( "a b c d" ) > A.special_fields #=> which returns "a b c d"That''s sort of funny because then you can do Object.special_fields => "a b c d" ;-)
Zach Dennis wrote:> > You should note that: > s = class << self; self; end > > is returning the last value evaluated inside of the "class << self; > .... ; end" block. If you said: > s = class << self; 5; end > > then ''s'' would be equal to 5. Opening the class definition for the > current object just to return itself is silly in my opinion, and it > makes the code look more cryptic. I would suggest to keep it clean with: > s = self.class >nope, that''s different. In the above context "self" refers to the class A, which is an object having the class "Class". So "self.class" gives you "Object", which happens to be the parent class of "Class". That''s why your methods are available in all classes in this case. "class << self; self; end" does something different. It returns the "singleton class" (or meta-class, as why happens to call them) of the object representing class A, so that you can add class methods just to that class. Hope it helps, although it''s definitely a bit mind-boggling. Sebastian
Sebastian Kanthak wrote:> nope, that''s different. In the above context "self" refers to the > class A, which is an object having the class "Class". So "self.class" > gives you "Object", which happens to be the parent class of "Class". > That''s why your methods are available in all classes in this case. >sorry, that should have been: "self.class" gives you "Class", because this is the class of the object "A". That''s why your methods are available in all classes in this case. Sorry for the confusion, I get it wrong myself all the time... Sebastian
> "class << self; self; end" does something different. It returns the > "singleton class" (or meta-class, as why happens to call them) of the > object representing class A, so that you can add class methods just to > that class. >So is this the only way to add class methods to just one class dynamically (and not lose scope of variables)?> ... although it''s definitely a bit mind-boggling.Uh, slightly.
Steve Downey wrote:> >> "class << self; self; end" does something different. It returns the >> "singleton class" (or meta-class, as why happens to call them) of the >> object representing class A, so that you can add class methods just >> to that class. >> > So is this the only way to add class methods to just one class > dynamically (and not lose scope of variables)?hmm, at least I don''t know of any other. You could put a helper method into your Parent class, to hide this "magic" away into its own method. class Parent < ActiveRecord::Base def self.define_class_method(name, &blk) (class <<self; self; end).define_method(name,blk) end end Sebastian
Sebastian Kanthak wrote:> Steve Downey wrote: > >> >>> "class << self; self; end" does something different. It returns the >>> "singleton class" (or meta-class, as why happens to call them) of >>> the object representing class A, so that you can add class methods >>> just to that class. >>> >> So is this the only way to add class methods to just one class >> dynamically (and not lose scope of variables)? > > > hmm, at least I don''t know of any other. You could put a helper method > into your Parent class, to hide this "magic" away into its own method. > > class Parent < ActiveRecord::Base > def self.define_class_method(name, &blk) > (class <<self; self; end).define_method(name,blk) > end > endActually I looked at set_table_name: # File lib/active_record/base.rb, line 577 577: def set_table_name( value=nil, &block ) 578: define_attr_method :table_name, value, &block 579: end and descovered define_attr_method() which I now call. Probably not the best idea with it not being documented, but I guess I can always just implement what they have now if it gets removed: def define_attr_method(name, value=nil, &block) sing = class << self; self; end block = proc { value.to_s } if value sing.send( :alias_method, "original_#{name}", name ) sing.send( :define_method, name, &block ) end It was looking at this code that got me started on this thread in the first place.
Sebastian Kanthak wrote:> > "class << self; self; end" does something different. It returns the > "singleton class" (or meta-class, as why happens to call them) of the > object representing class A, so that you can add class methods just to > that class. >Ah yes, I stand corrected. Zach
On Tue, 2005-08-09 at 11:30 +0200, Sebastian Kanthak wrote:> Sorry for the confusion, I get it wrong myself all the time...You''re confused - I''ve been following the thread in the hope someone will explain what the "<<" actually does! Has anyone a link that can put me out of my misery (and into a new world of mind boggling) Thanks Tom SW ___________________________________________________________ Yahoo! Messenger - NEW crystal clear PC to PC calling worldwide with voicemail http://uk.messenger.yahoo.com
I''ve looked ahead, and I don''t see any other answers, so.. Tom Schutzer-Weissmann wrote:> On Tue, 2005-08-09 at 11:30 +0200, Sebastian Kanthak wrote: > > >>Sorry for the confusion, I get it wrong myself all the time... > > > You''re confused - I''ve been following the thread in the hope someone > will explain what the "<<" actually does! Has anyone a link that can put > me out of my misery (and into a new world of mind boggling) >The usual Ruby pattern is "class Blah < BlahParent", read as "Blah is a subclass of BlahParent". In this "singleton class" example, we''re leaving out the name of the class, because we don''t know it. Think of it as being "anonymous". What we do know, though, is that it''s going to be a subclass of ''self''. In the terms of other programming languages, this might be called an ''inner class''. As I understand it, Ruby uses "<<" instead of "<" in this scenario to make it easier to parse out. The Pickaxe book uses "writing an accessor for a class variable" as an example of when you would use this kind of thing. As an aside, people with Java and/or C++ experience routinely get "type" and "class" confused, when in reality they are different. Because Ruby arguably owes a good deal to Smalltalk, you will run into situations where they are not the same. The "Duck Typing" chapter of the Pickaxe book is a good example, though they gloss over it a bit. Here''s a quick Google hit, though there are probably better explanations out there (and certainly better ones than what I''ve just delivered..) http://www.acmqueue.org/modules.php?name=Content&pa=showpage&pid=205 I hope this helps. If I mangled anything, hopefully someone will correct me before I strike again. --Wilson.
On Thu, 2005-08-11 at 23:15 -0400, Wilson wrote:> In this "singleton class" example, we''re leaving out the name of the > class, because we don''t know it. Think of it as being "anonymous". > What we do know, though, is that it''s going to be a subclass of ''self''. > In the terms of other programming languages, this might be called an > ''inner class''. As I understand it, Ruby uses "<<" instead of "<" in this > scenario to make it easier to parse out.Thanks! That & the link is probably enought to get me started. Actually I''m going to stop thinking about it and do some work :) Tom ___________________________________________________________ To help you stay safe and secure online, we''ve developed the all new Yahoo! Security Centre. http://uk.security.yahoo.com