On Nov 28, 2007, at 2:28 AM, Sharon Phillips wrote:

> Here's the code snippet in question. It works, but is extremely  
> ugly with its constant usage of instance_variable_get and set.
>
> child_list_name= ('@'+(child.to_s)+"_list")
> self_method= (self.name.downcase+'=').to_sym
> method_name= ('add_'+child.to_s).to_sym
>
> define_method method_name do |new_child|
>   instance_variable_set(child_list_name, []) if  
> instance_variable_get(child_list_name).nil?
>   unless instance_variable_get(child_list_name).include? new_child
>     instance_variable_set(child_list_name, (instance_variable_get 
> (child_list_name) << new_child))
>     if new_child.respond_to? self_method
>       new_child.send self_method, self
>     end
>   end
> end
>
>
> This is what I'd really like the new method to look like (for  
> child== :personnel):
>
> def add_personnel (new_personnel)
>   unless (@personnel_list||=[]).include? new_personnel
>     @personnel_list << new_personnel
>     self_method= (self.name.downcase+'=').to_sym
>     if new_personnel.respond_to? self_method
>       new_personnel.send self_method, self
>     end
>   end
> end
>
>
> Any help appreciated.

eval strings, it's faster to debug by light years since you can dump  
it out to the screen.  it also lets you use blocks.  the cool kids  
use 'define_method', but then their methods cease to take blocks,  
enclose scope which cannot be freed, and are a pain in the butt to  
debug.  starting with your sample method, which is the best way to  
start of course, i'd do

cfp:~ > cat a.rb
module Adder
   def attr_adder *names
     names.each do |name|
       code = <<-code
         def add_#{ name } (new_#{ name })
           unless (@#{ name }||=[]).include? new_#{ name }
             @#{ name } << new_#{ name }
             self_method= (self.name.downcase+'=').to_sym
             if new_#{ name }.respond_to? self_method
               new_#{ name }.send self_method, self
             end
           end
         end
       code
       puts code if $DEBUG
       module_eval code
     end
   end
   def self.included other
     other.extend self
   end
end

class C
   include Adder
   attr_adder :personnel, :foobar
end

obviously writing this is quite easy: just start with your template  
and do some string substitution ;-)  being able to dump the code out  
is HUGE when it comes to metaprogramming.  i've even had libs that  
dumped it out so it could be, gasp, rdoc'd.

define_method is quite useful at times, but i'd say this isn't it.

kind regards.



a @ http://codeforpeople.com/
--
it is not enough to be compassionate.  you must act.
h.h. the 14th dalai lama