On May 10, 2008, at 6:40 PM, David A. Black wrote:
>>
>> Hi all,
>>
>> What I'm trying to achieve: add a variable to a class. Fill it with
>> data. Every nstance of that class should have access to the data in  
>> that
>> variable. But I want every instance be able to modify that variable,
>> without modifying the original value of the variable.
>
> I'm not sure what you mean exactly. Do you mean each instance should
> have a copy of the object? If so, I would just do:
>
> class Tester
>
>  def self.vars
>    @vars ||= []
>  end
>
>  def self.add_var(var)
>    self.vars << var
>  end
>
>  def vars
>    @vars || self.class.vars
>  end
>
>  def add_var(var)
>    @vars ||= self.class.vars.dup
>    vars << var
>  end
> end
>
> That gives the results you expect in your test.
>



careful, any ruby code that uses 'dup' or clone has serious bugs 9 out  
of 10 times, in the case it doesn't meet the OP's *requirements*  
(although the simple test case passes) at all:

cfp:~ > cat a.rb
#
# doesn't let instance modify the var without modifying the class var
#

   Tester.add_var 'oops'
   t = Tester.new
   t.vars.first << ', this modifies the original'
   p Tester.vars  #=> "oops, this modifies the original"


#
# and doesn't take a copy either
#
   Tester.vars.clear
   Tester.add_var ['oops']
   t = Tester.new
   t.vars.first << ', this modifies the original'
   p Tester.vars  #=> [["oops", ", this modifies the original"]]


BEGIN {
   class Tester
    def self.vars
      @vars ||= []
    end

    def self.add_var(var)
      self.vars << var
    end

    def vars
      @vars || self.class.vars
    end

    def add_var(var)
      @vars ||= self.class.vars.dup
      vars << var
    end
   end
}


cfp:~ > ruby a.rb
["oops, this modifies the original"]
[["oops", ", this modifies the original"]]




you really need one of two things: a factory or a smarter copy  
algorithm:

using a factory:

cfp:~ > cat a.rb

class Shares
   Factory = lambda { |var|
     case var.to_s
       when 'a'
         'not shared'
       when 'b'
         'but created fresh for class and instance cases'
       else
     end
   }

   def Shares.a
     @a ||= Factory['a']
   end

   def a
     @a ||= Factory['a']
   end
end

p Shares.a

shares = Shares.new
shares.a << ", but it's own copy"

p Shares.a
p shares.a


cfp:~ > ruby a.rb
"not shared"
"not shared"
"not shared, but it's own copy"



or, using a smart copy method:

cfp:~ > cat a.rb
class Shares
   def Shares.a
     @a ||= 'not shared'
   end

   def a
     @a ||= Marshal.load(Marshal.dump(Shares.a))
   end
end

p Shares.a

shares = Shares.new
shares.a << ", but it's own copy"

p Shares.a
p shares.a


cfp:~ > ruby a.rb
"not shared"
"not shared"
"not shared, but it's own copy"


this is nicer, but only works for objects you can marshal - obvisouly.


a @ http://codeforpeople.com/
--
we can deny everything, except that we have the possibility of being  
better. simply reflect on that.
h.h. the 14th dalai lama