James French wrote in post #1055131:
Its pretty simple really. I want to be able to call an API like this:
SourceControl.checkout
SourceControl.update
You better do
sc.checkout
sc.update
i.e. not use a constant but an instance variable.
I want to be able to plugin different source control systems that
conform to the API.
Well, in Ruby there are no interfaces so you can, but do not need to use inheritance.
My initial thought was just to go with a simple C++ style
wrapper/delegate approach:
module SourceControl
def self.checkout(repository, dest, options={})
@sourceControl.checkout(repository, dest, options) end
def self.update(path, options={})
@sourceControl.update(parth, options) end
class SourceControlAPI
def checkout(repository, dest, options={})
end
def update(path, options={})
end
end
end
But I bet there is a nicer way, perhaps without having to duplicate
the API?
Especially, what advantages does it have?
I'd probably simply do
class CVS
def checkout(dest, options={})
end
def update(path, options={})
end
end
class SVN
def checkout(dest, options={})
end
def update(path, options={})
end
end
class Perforce
def checkout(dest, options={})
end
def update(path, options={})
end
end
and then
# connection
sc = SVN.new("svn-repo.my.network.com", "James", "p@ssword")
# repository
sc.checkout("repo", "/tmp/work") do |repo|
repo.update("foo")
File.open(repo.path + "foo", "a") {|io| io.write("a change)}
repo.submit("foo")
end # auto commit
sc.close # needed?
You could even make SVN.new accept a block which receives "sc" and cleans up in ensure regardless how the block terminates.
http://blog.rubybestpractices.com/posts/rklemme/002_Writing_Block_Methods.html
Kind regards
robert
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
class SourceControlAPI
def checkout(repository, dest, options={})
end
def update(path, options={})
end
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')
···
-----Original Message-----
From: Robert Klemme [mailto:lists@ruby-forum.com]
Sent: 05 April 2012 14:20
To: ruby-talk ML
Subject: Re: Design pattern question