On Fri, 30 Aug 2002, Gavin Sinclair wrote:
> >     class LogLine
> >         attr_reader :month, :day, :hour, :minute, :second,
> >                 :host, :program, :pid, :message
> >         [...]
> >     end
> 
> I'd use a Time object instead of :month, :day, etc.

of course

> > But from there, I have two questions:
> >
> > 1) Is it possible (or even sensible) to override LogLine.new so that it
> > returns an instance of the appropriate subclass? I've never liked the
> > Java-style LogLine.getInstance(args); it seems unfair to make
> > programmers  keep track of whether you're using a Factory internally or
> > not.
> 
> There's no such method as LogLine.new, I'm afraid.  When you define the
> class LogLine, you are creating a constant called LogLine which is of type
> class.  When you call LogLine.new, it is the new method in class Class
> that you are calling.  It, of course, calls LogLine.init, and the rest is
                                                      ^^^^ialize
> history.

He can add a singleton method
def LogLine.new(logline_string)
  # return subclass instance if apropriate
  # if not, create a plain LogLine:
  super(logline_string)
end

> So creating a (static) method LogLine.create or something like that is
> probably the way to go.

This is better than overiding new because programmers expect
SomeClass.new.class == SomeClass

> > The obvious OO way seems to be that each subclass would, on loading,
> > register itself with LogLine.

Sounds sensible. Just add to your logline class:
class LogLine 
  @@subclasses = [LogLine]
  def LogLine.inherited(subclass)
    @@subclasses << subclass
  end
  def LogLine.create(logline_string)
    # parse the date
    ratings = @@subclasses.collect{|subclass|
      subclass.rate(string_after_date)
    }
    best_subclass = @@subclasses[ratings.index(ratings.max)]
    best_subclass.new(date, string_after_date)
  end
end

and implement the classmethod rate for LogLine and all its subclasses to
return a number that indicates the likelyhood that it is responsible for
this logline. All classes that inherit from LogLine will automatically be
added to the class variable @@subclasses.

> > Really, the parsed data is best represented as a LogLine, no?
> > So it
> > would  make sense to instantiate a LogLine with the base data, and then
> > pass that  to the subclasses. But when instantiating the subclass, the
> > subclass has to  copy over all the data and throw out the copy of the
> > superclass, which  seems a little wasteful.

You want a "become" method:

d = LogLine.new(...)
old_id = d.id
puts d.class                => LogLine
d.become(LogLine_Subclass)
puts d.class                => LogLine_Subclass
puts (d.id == old_id)       => true

To my knowledge, ruby does not have this functionality. I'd like to be
proven wrong on this. Maybe its possible to implement this in a C
extension that does some tricks with ruby's object representation?

> conclusion that you're on the wrong track.

No. Apart from wanting to use the new method, his aproach looks fairly 
sensible to me. He presented refreshing ideas and showed that he 
understands OO programming fairly well. He's just a newby to the ruby 
and needs help in mapping his ideas to the language.

> Basically, I think you should put all the logic of what subclass best
> represents the line into LogLine, like:

The logic of the subclass should be part of the subclass. Or => 
maintainance nightmare.

> It may be a bit awkward for the client of LogLine to know what to do with
> the return value - it'll probably have to type-check it

Why? It is_a LogLine, that's for sure. The client got what it asked for.

  Tobias