On Thu, Apr 5, 2012 at 4:25 PM, James French
<James.French / naturalmotion.com> wrote:

> Using =A0the Jay Fields link and slightly modifying I've got something I'=
m happy with. Thanks for the help Robert, as always :)
>
> module SourceControl
> =A0def self.init(subject)
> =A0 =A0subject.public_methods(false).each do |meth|
> =A0 =A0 =A0(class << self; self; end).class_eval do
> =A0 =A0 =A0 =A0define_method meth do |*args|
> =A0 =A0 =A0 =A0 =A0subject.send meth, *args
> =A0 =A0 =A0 =A0end
> =A0 =A0 =A0end
> =A0 =A0end
> =A0end
> 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
>
> =A0def checkout(repository, dest, options=3D{})
> =A0end
>
> =A0def update(path, options=3D{})
> =A0end

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.

> end
>
> class SVN < SourceControlAPI
>
> =A0def checkout(repository, dest, options=3D{})
> =A0 =A0puts "Checking out from SVN"
> =A0end
>
> =A0def update(path, options=3D{})
> =A0end
>
> 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.

Kind regards

robert

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/