Skip to content

Making your Plugin or Gem configurable

Recently I added a configuration mechanism to Webrat. It was surprisingly easy, and mainly copied from rails core. I would suggest adding somthing like this to any plugin that has more than a few features or ones that users have asked to have turned off.

First off you’re going to have to create the actual configuration object. There are a few good ways to do this. One is to use a config module, another is to create a configuration object that is accessible via a singleton method.

I’m going to go with the second one, a configuration object.

Toss this one in lib/configuration.rb (A simplification of Code | RDoc)

module Plugin
  
  # Configures Plugin.
  def self.configure(configuration = Plugin::Configuration.new)
    yield configuration if block_given?
    @@configuration = configuration
  end
      
  def self.configuration # :nodoc:
    @@configuration ||= Plugin::Configuration.new
  end

  # Plugin can be configured using the Plugin.configure method. For example:
  # 
  #   Plugin.configure do |config|
  #     config.show_whiny_errors = false
  #   end
  class Configuration
    
    # Should whiny error messages be shown?
    attr_writer :show_whiny_errors

    def initialize # :nodoc:
      # set your defaults in here
      self.show_whiny_errors = true
      # put as much as you want in here
    end
    
    # some syntactic sugar for you, the coder
    def show_whiny_errors? #:nodoc:
      @show_whiny_erorrs ? true : false
    end
   
  end
  
end

Okay, now we need to test the config object itself. This is why it’s nice to make an object just to house the config, it’s easy to test. What do we test? Well defaults and accessors for two!

(The following lifted from Code) (sorry this is in rspec, it’s not hard to do in test::unit)

require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
 
describe Plugin::Configuration do
  # define matchers for testing
  predicate_matchers[:show_whiny_errors] = :show_whiny_errors?

  it 'should show whiny errors by default' do
    config = Plugin::Configuration.new
    config.should show_whiny_errors?
  end
  
  it 'should be configurable with a block' do
    Plugin.configure do |config|
      config.show_whiny_errors = false
    end
    
    config = Plugin.configuration
    config.should_not show_whiny_errors?
  end
  
end

Now we need to do some stuff to make it nicer for our other users to test. Put the following in your test_helper or spec helper. It will allow you to clear your config after each test. Nice to have to to avoid messy test issues.

(The following lifted from Code)

module Plugin
  @@previous_config = nil
 
  def self.cache_config_for_test
    @@previous_config = Plugin.configuration.clone
  end
 
  def self.reset_for_test
    @@configuration = @@previous_config if @@previous_config
  end
end

# configure your test runner / spec runner to always clear the config
Spec::Runner.configure do |config|
  
  config.before :each do
    Plugin.cache_config_for_test
  end
  
  config.after :each do
    Plugin.reset_for_test
  end
end

This last bit is somewhat hard to do in test::unit as it is harder to hook into the setup (you only get one in the call chain). I’m willing to take some help on cleaning this one up for test::unit. Currently I have just been putting it in the setup / teardown for each test file.

Finally you need to make use of this in tests, fortunately that is quite easy. Just:

describe SomeObject do
    it 'it shouldn't do it when whiny nils are off' do
      Plugin.configure do |config|
        config.show_whiny_errors = false
      end
      object.should_not_receive(:log)
  
      object.do_somthing_that_usually_complains
    end
end

Finally, anywhere in your plugin that you think somthing is whiny, just check the config before using it like this:

log("you should really fix this") if Plugin.configuration.show_whiny_errors?

One Comment

  1. I rarely write responses, but i did a few searching and
    wound up here confabulus › Making your Plugin or Gem configurable.
    And I actually do have 2 questions for you if you usually do not mind.
    Is it only me or does it seem like a few of the remarks appear like they are coming from brain dead visitors?

    :-P And, if you are posting at additional online sites, I’d like to follow everything new you have to post.
    Would you make a list of the complete urls of all your communal
    pages like your linkedin profile, Facebook page or twitter feed?

    Monday, May 12, 2014 at 12:53 pm | Permalink

Post a Comment

Your email is never published nor shared.