Posts: 9 / Nickname: jbritt / Registered: March 24, 2003 4:10 PM
Modular Architectures with Ruby
October 9, 2005 8:03 PM
|
A modular architecture is one where the user can create modules that conform to well-described APIs and plug them into the application to extend the functionality. This article shows one way to create a modular API in Ruby.
Read this article by Jack Herrington, author of Code Generation in Action http://www.artima.com/rubycs/articles/modular_apis_with_ruby.html What did you think of Jack's article? |
Posts: 2 / Nickname: mwhart / Registered: October 10, 2005 2:41 PM
Re: Modular Architectures with Ruby
October 10, 2005 6:51 PM
|
I don't actually know very much about Ruby, but isn't there a cleaner way to retrieve a parser from a factory than the loop in the
ParserFactory.parser_for method?It seems to me that having to instanciate each factory and check if it matches the requested type is overkill - couldn't it be done in a hash of some sort (the factory could be added to the hash with the type as the key in the ParserFactory.inherited method), or even just checking a class variable/method (as opposed to an object one)?
|
Posts: 15 / Nickname: jcheng / Registered: October 16, 2002 8:08 AM
Re: Modular Architectures with Ruby
October 10, 2005 8:41 PM
|
>> It seems to me that having to instanciate each factory and check if it matches the requested type is overkill - couldn't it be done in a hash of some sort (the factory could be added to the hash with the type as the key in the ParserFactory.inherited method), or even just checking a class variable/method (as opposed to an object one)? <<
I agree. Factory classes are basically a necessity in Java, where interfaces can't specify static methods and classes aren't objects. With Ruby, the former doesn't apply and the latter isn't true. In fact, since all of the factories are essentially identical, a more Rubyish way to do it would be to create a module method that registers a parser without the need to write explicit factory code at all: class RDFParser < Parser That should be *all* the code you need to write to implement and register a parser. (I didn't bother with the functionality on page 4 but it should be a straightforward extension.) Here's the complete code for ParserFactory: class ParserFactory |
Posts: 15 / Nickname: jcheng / Registered: October 16, 2002 8:08 AM
Re: Modular Architectures with Ruby
October 10, 2005 8:48 PM
|
Whoops, I got (at least) this method wrong:
def ParserFactory.parser_for(type) |
Posts: 2 / Nickname: mwhart / Registered: October 10, 2005 2:41 PM
Re: Modular Architectures with Ruby
October 10, 2005 9:07 PM
|
I like the idea of searching for a more Ruby-ish way, but I guess one possible problem with your approach, Joe, is that each parser is then dependent on the
ParserFactory , which reduces their portability somewhat. The additional abstraction layer in the original design eliminates this dependency. It's probably up to your development needs whether this is acceptable or not.
|
Posts: 1 / Nickname: fosterg / Registered: October 11, 2005 5:57 AM
Re: Modular Architectures with Ruby
October 11, 2005 10:01 AM
|
Thanks for the informative article. Its rather a new way of thinking for me. How would your example change if you were to use Needle (or other IOC module).. I'm still trying to get my head around these concepts.
Graham |
Posts: 1 / Nickname: dws / Registered: May 9, 2003 7:02 AM
Re: Modular Architectures with Ruby
October 14, 2005 8:16 AM
|
I'm wondering if the separate Factory class hierarchy carries its weight. By keeping a Hash in a class variable in the base Parser class to index each subclass by the type it services, and suppyling a class method to populate that hash, subclasses could do something along the lines of
which has more declarative value than overriding inherited . It's a simple step from there to
This approach also opens the door for having a single parser class service multiple types, e.g.,
Dave Thomas does something similar in RubLog. |
Posts: 1 / Nickname: aabhijit / Registered: March 13, 2005 2:24 AM
Re: Modular Architectures with Ruby
November 6, 2005 6:59 AM
|
I am new to this Ruby language but while trying out the example I found a ridiculous problem. I am not sure if it actually exists or not. So if someone could verify it for me I would be grateful.
In the rss.rb file I wrote the class definition as, class RSSFactory < ParserFactory INFO=<<INFO type: RSS author: Abhijit description: An RSS Parser INFO ... end And the compiler gave me some error about not finding INFO...Then I rewrote this as, class RSSFactory < ParserFactory INFO=<<INFO type: RSS author: Abhijit description: An RSS Parser INFO ... end And it worked!! |
Posts: 1 / Nickname: p2 / Registered: November 14, 2005 9:40 PM
Re: Modular Architectures with Ruby
November 15, 2005 2:57 AM
|
I don't see any differencies in yor code snippets... But I have the same problem.
I also getthis error in my test.rb: undefined method `parse' for nil:NilClass (NoMethodError) |
Posts: 1 / Nickname: arton / Registered: November 15, 2005 8:18 AM
Re: Modular Architectures with Ruby
November 15, 2005 1:25 PM
|
It is using heredoc syntax:
http://en.wikipedia.org/wiki/Heredoc You don't want any whitespace preceding the closing INFO (or any other text between the INFOs you don't want to be indented). |
Posts: 1 / Nickname: jbonnar / Registered: November 22, 2005 8:46 PM
Re: Modular Architectures with Ruby
November 23, 2005 2:30 AM
|
Requiring factor methods to test and create a parser like this is a bit silly in Ruby. Defining a class method
handle? for each parser that will evaluate whether it can parse the specified data type would work just fine. Most of this could be automated as well, using the following parser class.class Parser Defining a parser class is then as easy as: class Parser::Atom < Parser Of course, if we decided we didn't actually want to inherit the Parser class, that's fine as well. class Parser::Rss Most times we'd want to group all of our parsers in seperate files in another directory. We can modify the Parser class to require these files automatically for us.class Parser After this, fetching a Parser class can be done via: Parser.for(:atom) If we put our plugins in the './plugins' directory of our project, the only thing we'd need to do after requiring the parser class is: Parser.for(:atom).parse(doc) The parser will look for plugins and then find one that parses atom and pass us that class so we can parse our feed. If you wanted to also register the plugin when inheriting, the Parser class can alsways be extended: class Parser |
Posts: 2 / Nickname: cyent / Registered: December 4, 2005 1:55 PM
Far too complex!
December 4, 2005 7:09 PM
|
Your version is far far too complex. Make it much much simpler.
File Parser.rb...
File RSSParser.rb
File RDFParser.rb
Ok, so lets test it.... File TC_Parser.rb Note this knows nothing about the concrete parsers...
So lets run the test...
Pretty boring, so plug in a plugin...
Plug in the other plug in...
Plug in both...
Test a plugin... File TC_RSSParser.rb
Run it...
|
Posts: 2 / Nickname: tiger60 / Registered: December 9, 2005 9:20 AM
Re: Far too complex!
December 9, 2005 2:22 PM
|
I can't understand the part:
@@klass = Hash.new do |hash,key| Just works in your example but i can't understand why. Can you explain it to me? Thanks |
Posts: 2 / Nickname: tiger60 / Registered: December 9, 2005 9:20 AM
Re: Far too complex!
December 9, 2005 2:33 PM
|
After some googling i know why it's working. Looks like a new ruby adition since 1.8 to add the value if it's not found in the hash, i didn't know about it.
|
Posts: 1 / Nickname: ged / Registered: September 27, 2005 6:03 PM
Re: Modular Architectures with Ruby
January 10, 2006 4:13 PM
|
There's also at least one module on the RAA that makes doing some of this stuff easier:
http://raa.ruby-lang.org/project/pluginfactory/ It comes in the form of a mixin that you can add to your base class to make it pluggable. |
Posts: 1 / Nickname: andresbube / Registered: January 18, 2006 10:47 AM
Re: Modular Architectures with Ruby
January 18, 2006 3:57 PM
|
Nice article. This kind of article lets me map concepts between what I know and Ruby. I have a Java background but I'm just starting with Ruby.
I understand the pattern you're trying to implement, but it seems a bit strange that there is no "Interface". Because of that you need to define an empty class returning nill on each method, something like an abstract class. It is very common to define an extensible architecture or and API based on Interfaces, it happens all the time in Java (i.e. JDBC, XML Parsers, etc...) and other OO languages. How is this supported by Ruby? |