From: Ara.T.Howard@... Date: 2005-05-05T05:44:49+09:00 Subject: Re: [RCR] Object#inside_metaclass? On Thu, 5 May 2005, David A. Black wrote: > Hi -- > >> it's sort hard to show in a little code but __logically__ we end up >> with something like (greatly simplified) >> >> class C >> >> @trait_defaults = { >> 'class' => { 'a' => 'default_value' }, >> 'instance' => { 'a' => 'default_value' }, >> } >> >> def C::a > > (Just out of curiosity: do you mean to depart from the usual C.a here? > And why? :-) i've got a couple of coding conventions i use including: - collections are plural - class methods get called with :: they help me know things like p configs #=> this is an array of configs x::send('method', *args) #=> x is a class they are just habbits. > >> @a = @trait_defaults['class']['a'] unless defined? @a >> @a >> end >> >> def a >> @a = @trait_defaults['instance']['a'] unless defined? @a >> @a >> end >> end >> >> so i need to know, at the point of definition if we're inside a >> metaclass to generate the code slightly differently. all the above >> is for explanation only and is nothing like real code. > > I understand the not real code point, but still, it's showing something I > can't quite follow, namely the @trait_defaults instance variable in the > instance method definition (def a). Do you mean this to refer to the > class's instance variable? yes - sorry. both class methods AND instance methods must look up there respective defaults in a class instance var. you can read the real code at http://codeforpeople.com/lib/ruby/traits/traits-0.0.0/ > I'm also not sure where inside_metaclass? would go here. Can you rewrite it > into pseudo-code looking how it would look if that method existed? class Class def trait(*args) if inside_metaclass? define_class_traits(*args) else define_instance_traits(*args) end end def class_trait(*args) class << self trait(*args) end end end make sense? obviously this would be easy if traits were like 'attr' and just eval'd some code - but the defaults thing makes it hard since the defaults must be stored somewhere in the case of instance traits and looked up later - therefore the method definition of the trait itself must dynamically differ. this is unlike attr_ methods. another reason for inside_metaclass? is that traits works like jib:~ > cat a.rb require 'traits' class C class_trait 'a' => 42 class << self trait 'b' => 'forty-two' end trait 'a' => 42.0 end p C::reader_traits p C::class_reader_traits jib:~ > ruby a.rb ["a"] ["a", "b"] now, 'reader_traits' and 'class_reader_traits' are also implemented like def reader_traits(*args) ... end def class_reader_traits(*args) class << self reader_traits(*args) end end eg. the __return__ value of reader_traits is context sensitive to being in/out of a metaclass. reason three: jib:~ > cat a.rb class C p ancestors class << self p ancestors end end jib:~ > ruby a.rb [C, Object, Kernel] [Class, Module, Object, Kernel] now imagine you want to implement 'inheritence' for traits that use class @vars (not @@vars) for default values (for the obvious reason). you need to look up the chain of ancestors to find you defaults. problem: your ancestors vary according to scope. i solve this by klass = if inside_metaclass? pop_up_to_instance_klass else self end klass.ancestors.each{|a| look_for_default a } the problem all boils down to this : attr_ and friends work exactly the same whether called at a class or metaclass level. adding features like having default values, inheritence of stuff, etc. makes the distinction of where you are (class or metaclass) suddenly very important. i hope i'm making myself clear now - i never meant for this to end up like this! ;-) cheers. -a -- =============================================================================== | email :: ara [dot] t [dot] howard [at] noaa [dot] gov | phone :: 303.497.6469 | renunciation is not getting rid of the things of this world, but accepting | that they pass away. --aitken roshi ===============================================================================