"David A. Black" <dblack / wobblini.net> schrieb im Newsbeitrag
news:Pine.LNX.4.61.0504111508240.7304 / wobblini...
> Hi --
>
> On Tue, 12 Apr 2005, Claus Spitzer wrote:
>
> > Greetings!
> > A friend of mine has recently started using Ruby, and has run into a
> > little problem. He is trying to create different objects depending on
> > the contents of a string. His intuition is to use factory design for
> > this, and he'd like to know if there is a Ruby Way to do this.
> >
> > Below is his original e-mail.
> > Regards...
> > -CWS
> >
> > ----8<----
> >
> > In any case, I have an identifier on my log file that looks like
"2005-01-04
> > 23:34:12 begin_phase".  If I see this, I want to create a "Phase"
object.  If
> > it says "2005-01-04 23:52:16 begin_interruption", then I want to
create an
> > interruption instead.
> >
> > My intuition is that this is a typical Factory Design Pattern, so I
would
> > create a Ruby class method that creates the appropriate type based on
the
> > results of  the string and returns it.  However, someone familiar with
Ruby
> > told me that Ruby's dynamic typing and duck typing is such that this
kind of
> > solution "feels incorrect".
> >
> > Does anyone have suggestions as to what I can do?  Thanks!
>
> I wouldn't worry about the matter of duck typing here.  The concept of
> duck typing, as I understand it, is essentially an explanatory tool
> for getting people to understand, visualize, and make use of the fact
> that class and type are not the same as each other in Ruby (a fact
> that can be summed up very quickly but that in fact has huge
> ramifications).  Duck typing doesn't mean you never instantiate
> objects of a particular class, nor that you never parse a string :-)
>
> For this project, I don't think any (webbed) toes will be stepped on
> if you do something like:
>
>    require 'scanf'
>
>    File.open("input.dat") do |fh|
>      fh.scanf("%d-%d-%d %d:%d:%d begin_%s") do |y,mo,d,h,mi,s,klass|
>        c = Object.const_get(klass.capitalize).new
>        # etc.
>      end
>    end
>
> (to illustrate with a simple line-by-line treatment).

If one needs more flexibility (for example because several tags should
create instances of the same class or whatever) then a hash in between
serves well:

FACTORIES = {
  "phase" => Phase,
  "interruption" => Interruption,
  # ...
}

if /begin_(\w+)/ =~ line
  obj = FACTORIES[$1].new
end

Or, even more flexible

FACTORIES = {
  "phase" => lambda {|line| Phase.new line},
  "interruption" => lambda {|*| Interruption.new},
  # ...
}

if /begin_(\w+)/ =~ line
  obj = FACTORIES[$1].call line
end

Kind regards

    robert