views:

54

answers:

1

I'd like a very basic example of a tiny base program, that reads in two plugins and registers them. These two plugins hook into the base program in the same way in a unconflicting manner.

I'm very new to metaprogramming in any programming language for that matter, I'm not sure where to start.

+1  A: 

i've been working on this very problem for a while now. i've tried a number of different ways to go about doing it and sought advice from a lot of people on it. i'm still not sure if what i have is 'the right way', but it works well and is easy to do.

in my case, i'm specifically looking at configuration and bringing in configuration plugins, but the principle is the same even if the terminology for mine is specific to cnfiguration.

at a very basic level, i have a Configuration class with nothing in it - it's empty. I also have a Configure method which returns the configuration class and lets you call methods on it:

# config.rb
class Configuration
end

class MySystem
  def self.configure
    @config ||= Configuration.new
    yield(@config) if block_given?
    @config
  end

  Dir.glob("plugins/**/*.rb").each{|f| require f}
end

MySystem.configure do |config|
  config.some_method
  config.some_value = "whatever"
  config.test = "that thing"
end

puts "some value is: #{MySystem.configure.some_value}"
puts "test #{MySystem.configure.test}"

to get the some_method and some_value on the configuration class, I have the plugins extend the configuration object via modules:

# plugins/myconfig.rb
module MyConfiguration
  attr_accessor :some_value

  def some_method
    puts "do stuff, here"
  end
end

class Configuration
  include MyConfiguration
end

and

# plugins/another.rb
module AnotherConfiguration
  attr_accessor :test
end

class Configuration
  include AnotherConfiguration
end

to load up the plugins, you only need one of code to look for the .rb files in a specific folder and 'require' them. this code can live anywhere as long as it's run right away when the file that contains it is loaded... i would probably put it in the class definition for MySystem or something like that to start with. maybe move it somewhere else when makes sense.

Dir.glob("plugins/**/*.rb").each{|f| require f}

run config.rb and you'll get output that looks like this:

do stuff, here 
some value is: whatever
test that thing

there are a lot of options for implementing the various parts of this, but this should get you down the path.

Derick Bailey