On Mon, 13 Nov 2006, jan aerts (RI) wrote:

> Hi all,
>
> I'm trying to create a little library for drawing my data using SVG. One
> of the inherent properties of the drawings that I have to make, is that
> each picture can contain one or more tracks with each track containing
> one or more features (see ASCII art below).
>
> +----------------------------picture-+
> | +----------------------track1----+ |
> | |                                | |
> | |  x          x                  | |
> | |         x               x      | |
> | |                                | |
> | |                                | |
> | +--------------------------------+ |
> |                                    |
> | +----------------------track2----+ |
> | |                                | |
> | |                     xx         | |
> | +--------------------------------+ |
> +------------------------------------+
>
> As a track can _only_ be defined within a picture, and a feature can
> _only_ be defined within a track, I have set up the classes as follows:
> class Picture
>   class Track
>     class Feature
>     end
>   end
> end
>
> The problem is that some of the properties of a Picture object have to
> be readable for its Track objects. This is _not_ simple inheritance,
> because Picture and Picture::Track are two completely different things.
> As I see it, there are several options:
> (A) either pass those properties as arguments every time you create a
> new Picture::Track object. Not optimal, because the same piece of data
> is copied over and over again.

this is not true - ruby __always__ passes references (unless you are
seializing an object over a wire or to file) so there's no harm in having a
reference to a 'parent' object.  in fact, given your spec, with all the
'_only_' clauses, it makes perfect sense to design the nested classes as a
factory chain, eg

   class Picture
     def new_track *a, &b
       Track.new self, *a, &b
     end

     class Track
       def initialize picture, *a, &b
         @picture = picture
       end

       def new_feature *a, &b
         Feature.new self, *a, &b
       end

       class Feature
         def initialize track, *a, &b
           @track = track
         end
       end
     end
   end


so

   picture = Picture.new

   track = picture.new_track :foo, :bar

   feature = track.new_feature :bar, :foo

this also has the nice feature that children prevent any required parents from
having the gc evaporate them - so long as we have a reference up the object
will not disappear.  in fact, i'd probably setup the association as a two-way:


   class Picture
     Tracks = []

     def new_track *a, &b
       t = Track.new self, *a, &b
     ensure
       Tracks << t
     end

     def each_track &b
       Tracks.each &b
     end

     class Track
       def initialize picture, *a, &b
         @picture = picture
       end

       Features = []

       def new_feature *a, &b
         f = Feature.new self, *a, &b
       ensure
         Features << f
       end

       def each_feature &b
         Features.each &b
       end

       class Feature
         def initialize track, *a, &b
           @track = track
         end
       end
     end
   end


etc.

-a
-- 
my religion is very simple.  my religion is kindness. -- the dalai lama