From: James French Date: 2012-04-06T01:16:09+09:00 Subject: Re: Design pattern question -----Original Message----- From: Robert Klemme [mailto:shortcutter@googlemail.com] Sent: 05 April 2012 16:08 To: ruby-talk ML Subject: Re: Design pattern question On Thu, Apr 5, 2012 at 4:25 PM, James French wrote: > Using  the Jay Fields link and slightly modifying I've got something > I'm happy with. Thanks for the help Robert, as always :) > > module SourceControl >  def self.init(subject) >    subject.public_methods(false).each do |meth| >      (class << self; self; end).class_eval do >        define_method meth do |*args| >          subject.send meth, *args >        end >      end >    end >  end > end That's just a mechanism to generate delegation. And you redefine methods all the time. I don't think meta programming is necessary at all here. > class SourceControlAPI > >  def checkout(repository, dest, options={}) >  end > >  def update(path, options={}) >  end Those are not really needed. And if you want to have them then I'd make them either contain a default implementation if there exists one or throw an exception which explains that this method must be implemented for the class. True, but I want to document the API somewhere central. I raise exceptions saying the method must be implement. > end > > class SVN < SourceControlAPI > >  def checkout(repository, dest, options={}) >    puts "Checking out from SVN" >  end > >  def update(path, options={}) >  end > > end > > SourceControl.init(SVN.new) > SourceControl.checkout('foo', 'bar') You are hiding specific state in a constant. I don't like that because it will prevent accessing multiple different source control systems in the same program or from multiple threads. I find that requirement to be able to invoke all the methods through the constant leads to a situation where you severely cripple modularity and reusability without really gaining something. Also true, if I wanted to do that, but I don't. I just need to initialise it at startup and use the source control system that was automatically determined from then on, without knowing which one it is. I think this API is working really well for me... I also just like the API of SourceControl.checkout etc. Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/