Your version is far far too complex. Make it much much simpler.
File Parser.rb...
=begin
First off is you don't need Factory objects. You have got factory
objects. They are called classes. The Factor pattern is way too heavy
weight for most applications.
Secondly you don't need YAML, you have Ruby.
Thirdly your base component is too knowledgable. It knows
(ParserFactory.load) where to find the concrete definitions of the
Parsers. ie. you couldn't deploy and version the Parser's
independently.
Note this file 'Parser.rb' is completely ignorant of the existence of
RDFParser and RSSParser.
=end
class Parser
# A list of subclasses.
@@klass_list = []
# A Hash from type_name string to sub class of Parser.
@@klass = Hash.new do |hash,key|
hash[key] = @@klass_list.find{|klass| klass.type_name == key }
end
# More succinct than "parser_for"
def Parser.[]( type_name)
@@klass[type_name].new
end
# This is invoked too early. Namely when the class is created,
# not when the type_name class method is defined. Thus we do not
# know what the "type_name" is as opposed to the Class name.
def Parser.inherited( klass)
@@klass_list << klass
end
def Parser.each( &block)
@@klass_list.each( &block)
end
def parse( xml)
raise "Abstract class, please instantiate a concrete class"
end
end
File RSSParser.rb
require 'Parser'
# Note this is completely ignorant of RDFParser and can be deployed
# seperately or concurrently.
class RSSParser < Parser
def RSSParser.type_name
'RSS'
end
def RSSParser.author
'Dick'
end
def parse(xml)
end
end
File RDFParser.rb
require 'Parser'
class RDFParser < Parser
def RDFParser.type_name
'RDF'
end
# Why introduce _yet_ another language (yaml) when we have Ruby?
def RDFParser.author
'Tom'
end
def parse(xml)
end
end
Ok, so lets test it....
File TC_Parser.rbNote this knows nothing about the concrete parsers...
require 'test/unit'
require 'Parser'
class TC_Parser < Test::Unit::TestCase
def test_parser
Parser.each do |klass|
type_name = klass.type_name
puts "Testing #{type_name} "
p = Parser[ type_name]
assert_equal( type_name, p.class.type_name)
end
end
end
So lets run the test...
ruby -w TC_Parser.rb
Loaded suite TC_Parser
Started
.
Finished in 0.004999 seconds.
1 tests, 0 assertions, 0 failures, 0 errors
Pretty boring, so plug in a plugin...
ruby -w -rRSSParser TC_Parser.rb
Loaded suite TC_Parser
Started
Testing RSS
.
Finished in 0.00397 seconds.
1 tests, 1 assertions, 0 failures, 0 errors
Plug in the other plug in...
ruby -w -rRDFParser TC_Parser.rb
Loaded suite TC_Parser
Started
Testing RDF
.
Finished in 0.004042 seconds.
1 tests, 1 assertions, 0 failures, 0 errors
Plug in both...
ruby -w -rRSSParser -rRDFParser TC_Parser.rb
Loaded suite TC_Parser
Started
Testing RSS
Testing RDF
.
Finished in 0.005426 seconds.
1 tests, 2 assertions, 0 failures, 0 errors
Test a plugin...
File TC_RSSParser.rb
require 'test/unit'
require 'RSSParser'
class TC_RSSParser < Test::Unit::TestCase
def test_info
puts "Do we need YAML?"
assert( 'Dick', Parser['RSS'].class.author)
end
end
Run it...
ruby -w TC_RSSParser.rb
Loaded suite TC_RSSParser
Started
Do we need YAML?
.
Finished in 0.007161 seconds.
1 tests, 1 assertions, 0 failures, 0 errors