Factory Patterns in Ruby

L

Lyndon Samson

Factory is a very common pattern in the java world, in some places
it's almost considered 'Evil (TM)' to have any sort of knowledge of
object construction.

In the Ruby world, where Classes and Objects seem to be de-emphasised,
constructing an object with .new doesn't seem to be held as such a bad
thing.

I know there are a few IOC containers in the RubyWorld, but they dont
seem to be overly popular.

Why might this be so?

cheers
lyndon
 
J

Jim Weirich

I know there are a few IOC containers in the RubyWorld, but they dont
seem to be overly popular.

There is a joke going around the Ruby community that there are more DI/IoC
frameworks in Ruby than there are people actually using the frameworks.

<OSCON teaser>
BTW, this is a good lead in to my OSCON talk on dependency injection.
</OSCON teaser>
 
J

Jim Freeze

* Jim Weirich said:
There is a joke going around the Ruby community that there are more DI/IoC
frameworks in Ruby than there are people actually using the frameworks.

Yes, and aren't there only two DI/IoC frameworks that exist? ;)


Didn't I read somewhere that an IoC in Ruby was a way to make
something really easy very hard? (Yes, you read that correctly.)
 
K

Ken Kunz

Rails also uses an abstract factory approach in ActiveRecord to
establish a database connection at run-time using the correct database
adapter.

Take a look at the ActiveRecord::Base.establish_connection method:
http://tinyurl.com/7fybw
 
A

Austin Ziegler

Yes, and aren't there only two DI/IoC frameworks that exist? ;)
Didn't I read somewhere that an IoC in Ruby was a way to make
something really easy very hard? (Yes, you read that correctly.)

There's three. Joel Van Der Werf has made one, too. Copland certainly
fits your description; Needle and Joel's framework less so, as I
understand it.

-austin
--=20
Austin Ziegler * (e-mail address removed)
* Alternate: (e-mail address removed)
 
J

Joel VanderWerf

Jim said:
Yes, and aren't there only two DI/IoC frameworks that exist? ;)

Well, I account for one DI framework (MinDI [1]) and zero users.... I
still haven't been involved in a project that had the right kind of
complexity to justify DI.

But DI frameworks are fun to develop. Maybe we should have a ruby quiz
to develop DI frameworks, and then we will have 20 more frameworks and
no more users ;)


[1] http://www.ruby-talk.org/cgi-bin/scat.rb/ruby/ruby-talk/120297
 
J

Joel VanderWerf

Ara.T.Howard wrote:
...
class JobRunner
class AbstractJobRunner ...
end
class FTPJobRunner < AbstractJobRunner ...
end
class HTTPJobRunner < AbstractJobRunner ...
end
class SCPJobRunner < AbstractJobRunner ...
end
class << self
def new job
klass =
case job.input
when %r|^ftp://|
FTPJobRunner
when %r|^scp://|
SCPJobRunner
when %r|^http://|
HTTPJobRunner
end
klass::new job
end
end
end

In this kind of situation, I like to try to refactor so that the
switching is done in the subclasses rather than a big case (as I'm sure
you would have done if this had been a real example with a large number
of cases). That can be done, for example, by:

require 'subclass-keeper' # see below

class JobRunner
class AbstractJobRunner
extend SubclassKeeper
def initialize(*args); end
end
class FTPJobRunner < AbstractJobRunner
PAT = %r|^ftp://|
end
class HTTPJobRunner < AbstractJobRunner
PAT = %r|^http://|
end
class SCPJobRunner < AbstractJobRunner
PAT = %r|^scp://|
end
class << self
def new job
klass = AbstractJobRunner.proper_subclasses.find do |c|
c::pAT === job.input
end
klass::new job
end
end
end

job = Object.new
def job.input; "scp://foo.bar"; end

jr = JobRunner.new job
p jr.class # ==> JobRunner::SCPJobRunner

----- subclass-keeper.rb ----

# Extend a class by SubclassKeeper to record all subclasses (including
itself)
# and make the list available with the #subclasses method.
module SubclassKeeper
def inherited(sub)
super
add_subclass(sub)
end
def add_subclass(sub)
superclass.add_subclass(sub) if superclass.respond_to? :add_subclass
(@proper_subclasses ||= []) << sub
end
protected :add_subclass
def proper_subclasses
(@proper_subclasses ||= []).dup
end
def subclasses
proper_subclasses.unshift(self)
end
end

if __FILE__ == $0
class Base
extend SubclassKeeper
end

class Sub1 < Base; end
class Sub2 < Sub1; end

p Base.subclasses
p Sub1.subclasses
p Sub2.subclasses
end
 
J

Jim Weirich

Yes, and aren't there only two DI/IoC frameworks that exist? ;)

Here's the ones I know about:

* Copland -- Hivemind based from Jamis Buck

* DI -- The version I wrote about in response to Jamis's Copland talk. (see
http://onestepback.org/index.cgi/Tech/Ruby/DependencyInjectionInRuby.rdoc)

* Needle -- Again from Jamis, based DI.

* MinDI -- Minimal framework from Joel VanderWerf
(http://redshift.sourceforge.net/mindi)

* seep -- Inspired by Spring (i.e. lots of XML), by Gary Shea
(http://seep.rubyforge.org/index.html)

* DIM -- Dependency Injection, Minimal, 30 lines of Ruby Code, developed for
my OSCON talk (currently unreleased ... I'll post it after OSCON).
 
G

Gary Shea

Thought I'd poke my head up at this point. I signed on this list a
half-hour or so ago, intending to do a bit of Seep-publicizing, just in
time to see Jim Weirich take care of it for me! Crazy! Thanks!

I'm the author of Seep, which Jim has characterized perfectly...Spring
like, lots of XML. If you hate XML, you'll hate Seep :)

The beauty of Seep (and this is entirely stolen from Spring) is that it
is versatile enough to give you 1) all that DI stuff, and 2) a unifying
syntax for configuration. I can (and do) configure pretty much
everything in my applications, from ActiveRecord mappers to Log4r, using
Seep.

I'm a Ruby beginner, so I hope some of you hard-core Ruby folk take a
look at Seep. I could use some feedback on what would help it be more
useful.

Regards,

Gary
 
A

Ara.T.Howard

Ara.T.Howard wrote:
...

In this kind of situation, I like to try to refactor so that the
switching is done in the subclasses rather than a big case (as I'm sure
you would have done if this had been a real example with a large number
of cases). That can be done, for example, by:

<snip nice code>

i totally agree - defintely put the pattern in the class since it belongs
there... otth you could abort early quite easily with conflicting/poorly
written patterns (remembering that part of a framework like this would be to
allow others to plugin classes) and this bug would be very hard to find, eg

client code:

class FOOJobRunner < AbstractJobRunner
PAT = %r|foo|
end
class BARJobRunner < AbstractJobRunner
PAT = %r|bar|
end
class FOOBARJobRunner < AbstractJobRunner
PAT = %r|foobar|
end

now, depending on the order of classes given by proper_subclasses you may or
may not to the right thing so probably you'd need

class << self
def new job
scs = AbstractJobRunner.proper_subclasses
klass = nil
scs.each do |sc|
if sc::pAT === job.input
raise if klass
klass = sc
end
end
klass.first::new job
end
end

or similar in order to make sure that there is one, and only one, match
amongst subclasses...

cheers.

-a
--
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| My religion is very simple. My religion is kindness.
| --Tenzin Gyatso
===============================================================================
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,521
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top