Including/selecting modules based on the methods they define

At http://spoofed.org/go.tar.gz I’ve put a simplified version of a
problem
I haven’t yet found a good way to solve. I’m looking for input as to
how
you’d solve the problem.

Basically I have a command line utility that takes three arguments – an
action, a vendor and a product. Only three actions (eat, drink, rest)
are
supported. Any number of vendors and products can be added by simply
creating a specially configured plugin.rb in the vendor/product
directory.

The issue is that not every vendor product combination will support all
three actions. When ‘go’ is run and an action is specified that the
given
vendor/product doesn’t support, I want to:

  1. Handle this gracefully
  2. Show all vendors + products that support this action

go is as simple as:

#!/usr/bin/env ruby

unless (ARGV.size == 3)
raise “Usage: $0 ”
end

(action, vendor, product) = ARGV

require File.join(“plugins”, vendor, product, “plugin.rb”)

case action
when /eat/
eat
when /rest/
rest
when /drink/
drink
else
raise “Unknown action #{action}”
end

And a given vendor + product, say Foo B., which lives in
plugins/foo/bar/plugin.rb contains:

module Go
module Foo
module Bar
def eat
puts “Foo::Bar eat!”
end
def rest
puts “Foo::Bar rest!”
end
end
end
end
include Go::Foo::Bar

Another vendor + product, Blaf Blarg is similarly implemented, but
supports
all three methods.

As it stands today, if you specify an action that the vendor product
does
not support (for example Foo::Bar.drink), an exception is thrown.
Again, I
want to handle that more gracefully (which is easy enough with
begin/rescue) and then show all the vendor products that do support
drink.

I feel like the answer lies somewhere around responds_to?, however I’d
need
to have access to the module name to call responds_to?, and as currently
implemented this code doesn’t know the module name.

Any feedback would be appreciated!

Thanks,

-jon

2012/1/4 Jon H. [email protected]:

As it stands today, if you specify an action that the vendor product does
not support (for example Foo::Bar.drink), an exception is thrown. Again, I
want to handle that more gracefully (which is easy enough with
begin/rescue) and then show all the vendor products that do support drink.

I feel like the answer lies somewhere around responds_to?, however I’d need
to have access to the module name to call responds_to?, and as currently
implemented this code doesn’t know the module name.

But you do in fact know the module name (as long as it’s consistent
with the file name):

irb(main):013:0> vendor, product = ‘foo’, ‘bar’
irb(main):019:0> module =
Go.const_get(vendor.capitalize).const_get(product.capitalize)
=> Go::Foo::Bar

I think you’ll be able to work from here :slight_smile:

– Matma R.

2012/1/4 Bartosz Dziewoński [email protected]

Interesting.

This gets me close, but for Go::Foo::Bar to be visible, I first have to
require that plugin. I’m looking to avoid loading every plugin unless
absolutely necessary, because I have this fear that there is a
performance
hit that I’ll incur by loading every plugin and including its namespace.
In my example, I only have two plugins, but in reality there can be
dozens
or hundreds.

Thanks,

-jon

On Wed, Jan 4, 2012 at 2:16 PM, Jon H. [email protected] wrote:

Interesting.

This gets me close, but for Go::Foo::Bar to be visible, I first have to
require that plugin. I’m looking to avoid loading every plugin unless
absolutely necessary, because I have this fear that there is a performance
hit that I’ll incur by loading every plugin and including its namespace.
In my example, I only have two plugins, but in reality there can be dozens
or hundreds.

I was able to solve this by removing the imports from each plugin.rb,
computing the module name as suggested, then including the module in go.
For the use case of listing what plugins support what or ensuring that
a
given plugin supports the method, I used method_defined?.

Thanks for your help.

-jon