Joel VanderWerf <vjoel / PATH.Berkeley.EDU> wrote in message news:<40BF7269.3050807 / path.berkeley.edu>...
> Alex Gutteridge wrote:
> > Hi,
> > 
> > I'm no great OO expert (or Ruby expert) so maybe the answer to this is
> > obvious or maybe it's impossible.
> > 
> > I currently have a bunch of classes which I use to parse a data file.
> > Essentially there are fve layers of containers:
> > 
> > PDB -> Model -> Chain -> Residue -> Atom
> > 
> > A PDB object contains one or more Model objects each of which contain
> > one or more Chain objects each of which contain... etc down to Atoms.
> > Note that Model doesn't inherit from PDB or Chain from Model - each
> > class is just a container for the next one down.
> > 
> > The problem I have is that sometimes I have extra data associated with
> > the Atom and/or Residue objects. This extra data always comes later
> > (from a different data file) and usually won't be present. when I need
> > to, I'd like to add this data to the (already created data structure)
> > with the minimum amount of work/fuss.
> > 
> > As far as I can see I have the following options:
> > 
> > 1. Modify the Atom and Residue classes to include the extra data, set
> > to nil originally and then filled in when needed. I'd rather not do
> > this because the code is part of a bigger project which I don't have
> > direct control over, and it seems rather inelegant to have these extra
> > fields which hardly ever get used.
> 
> Probably the caffeine hasn't hit me yet, but I'll suggest this anyway: 
> why not define the extra accessors you might need and assign to them 
> only when needed? No extra memory is used until you assign, as the 
> following shows:
> 
> class Atom
>    attr_accessor :x, :y, :extra1, :extra2
>    def initialize x, y
>      @x, @y = x, y
>    end
> end
> 
> atom = Atom.new(1,2)
> 
> p atom
> p atom.instance_variables
> 
> atom.extra1 = "extra stuff"
> 
> p atom
> p atom.instance_variables
> 
> __END__
> 
> Output:
> 
> #<Atom:0x401c68e0 @y=2, @x=1>
> ["@y", "@x"]
> #<Atom:0x401c68e0 @y=2, @x=1, @extra1="extra stuff">
> ["@y", "@x", "@extra1"]

Yes, this works as well, I obviously hadn't realised quite how dynamic
Ruby's OO system is. My code essentially looks like this now:

class Atom
    attr_accessor :id
    def initialize id
        @id = id
    end
end

atom = Atom.new('foo')
puts atom.id

class Atom
    attr_accessor :extra
end

atom.extra = 'bar'
puts atom.extra

__END__

Output:
foo
bar

Though the second class definition for Atom is in a different file. If
I understand correctly, when this second definition is pulled in,
every Atom object is magically extended to include accessors for the
@extra variable. This allows me to extend Atom objects without
fiddling with the original Atom definition (which is part of a larger
project and can't be easily editted). This almost seems too simple to
be true!