Victor "Zverok" Shepelev wrote:
> Hi all.
> 
> I have some huge class with aspects of functionality spreaded in several
> source files.
> 
> And in some of those aspects there is the same picture:
> ---
> class MyClass
>   def push_something(obj)
>     @something_list ||= []
>     @something_list << obj
>   end
> 
>   def use_something(i)
>     (@something_list ||= [])[i]
>   end
> end
> ---
> 
> Then I note (through profiler) various push_XXX spend too much time in
> checking is @XXX_list initialized. Then I change it:
> 
> ---
> class MyClass
>   alias :initialize_without_something :initialize
> 
>   def initialize(*arg)
>     initialize_without_something(*arg)
>     @something_list = []
>   end
> 
>   def push_something(obj)
>     @something_list << obj
>   end
> 
>   def use_something(i)
>     @something_list[i]
>   end
> end
> ---
> 
> Now push_XXX and use_XXX work cleaner and faster, but all those initialize
> aliases (now I have 5 or 6) don't seem to be very elegant.
> 
> Is there better solution?
> 
> (to be clear, all those push_XXX are NOT similar - some of them push object
> to hashes, others to arrays, params count differ and so on - so, they can't
> be generated at once through metaprogramming)
> 
> Thanks.
> 
> V.
> 

I don't know how this will profile--it has the disadvantage of 
generating more singletons than you might want, and there is the extra 
overhead of an attr_reader rather than just @something_list.

   class MyClass
     def method_missing(m,*)
       if m == :something_list
         @something_list = []
         class << self
           attr_reader :something_list
         end
         something_list
       else
         super
       end
     end

     def push_something(obj)
       something_list << obj
     end

     def use_something(i)
       something_list[i]
     end
   end

   mc = MyClass.new

   mc.push_something 3
   p mc  # ==> #<MyClass:0xb7d02114 @something_list=[3]>

Also, the method_missing def would need to know about each such attr, 
which seems to contradict your goal of distributing that information to 
lots of files. A little metaprogramming would help with that, since with 
this approach you only need to metaprogram the accessors, and not all 
the push_, pop_ etc. methods. Define a class method that registers 
things like "something_list", and the method_missing can lookup in the 
registered methods.

If you can tolerate a register method as well as the accessor overhead, 
then this gives me another idea, which doesn't generate singletons:

   class MyClass
     @reg_methods_defined = false
     @reg = {}

     class << self
       attr_reader :reg
       def define_reg_methods
         unless @reg_methods_defined
           @reg.each do |m,|
             attr_reader m
           end
           @reg_methods_defined = true
         end
       end
     end

     def initialize
       self.class.define_reg_methods

       self.class.reg.each do |m, (iv, bl)|
         instance_variable_set(iv, bl.call)
       end
     end

     def self.register m, &bl
       @reg[m] = ["@#{m}", bl]
     end
   end

   class MyClass
     register :something_list do
       []
     end

     def push_something(obj)
       something_list << obj
     end

     def use_something(i)
       something_list[i]
     end
   end

   mc = MyClass.new

   mc.push_something 3
   p mc # ==> #<MyClass:0xb7d65a7c @something_list=[3]>

Getting this to work for subclasses as well is left as an exercise to 
the reader ;)

-- 
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407