Skip to content

cjbottaro/configuration_dsl

Repository files navigation

configuration_dsl

Easily configure classes and objects using a DSL.

Description

configuration_dsl encapsulates the pattern of using a DSL to “configure” objects and/or classes:

class MyAwesomeClass
  ... some setup code here ...
  configure do
    greeting "Hello!"
    count 5
  end
end

MyAwesomeClass.configuration.greeting
# => "Hello!"

MyAwesomeClass.configuration.count
# => 5

Usage

Bet you’re wondering what goes in that “some setup code here” placeholder. It’s nothing too complicated. Here’s a complete example.

module MyConfiguration
  def greeting(s)
    s
  end

  def count(n)
    n
  end
end

require "configuration_dsl"

class MyAwesomeClass
  extend ConfigurationDsl
  configure_with(MyConfiguration)
  configure do
    greeting "Hello!"
    count 1
  end
end

MyAwesomeClass.configuration.greeting
# => "Hello!"

MyAwesomeClass.configuration.count
# => 1

The basic idea is that you define a module with your configuration options, then you configure your class/object with it.

Why a module?

Why are the configuration options stored in a module? It makes for pretty documentation! Just run rdoc on your configuration module.

Default values, lazily evaluated values and modified values.

Default values are supported in an intuative way. If you specify a block for a value, then it is lazily evaluated when you try to access the value for the first time.

class MyClass
  extend ConfigurationDsl
  configure_with Module.new {
    def name(s = "Christopher")
      s
    end
    def time(t)
      t
    end
    def age(n)
      n - 1
    end
    def callback(proc)
      proc
    end
  }
  configure do
    puts Time.now # => 2011-08-02 01:11:50 -0400
    time{ Time.now }
    age 31
    greeter Proc.new{ |name| "Hello, #{name}" }
  end
end

sleep(2)
MyClass.configuration.time                  # => 2011-08-02 01:11:52 -0400
MyClass.configuration.age                   # => 30
MyClass.configuration.name                  # => "Christopher"
MyClass.configuration.greeter.call("Chris") # => "Hello, Chris"

Make sense?

Working with objects

configuration_dsl works with plain objects (in addition to classes). Given the module MyConfiguration from our previous examples:

foo = Foo.new
foo.extend(ConfigurationDsl)
foo.configure_with(MyConfiguration)
foo.configure do
  greeting "What up?"
  count 2
end
foo.configuration.greeting
# => "What up?"
foo.configuration.count
# => 2

Working with classes

If you use configuration_dsl with classes, then derived classes should inherit the configuration in a sane and predictable way.

Callback

You can set a callback to be called after each time configure is called. Just pass a block to configure_with.

class MyClass
  extend ConfigurationDsl
  configure_with(SomeConfigurationModule) do
    @configure_count ||= 0
    @configure_count += 1
  end

  configure do
    some_option "something"
  end
end

MyClass.configure do
  another_option "something else"
end

MyClass.instance_variable_get(:@configure_count)
# => 2

This is useful if you need to run some kind of initialization code after your class or object has been configured.

Configuring the configure and configuration methods

You can use different methods for #configure and #configuration.

class MyClass
  extend ConfigurationDsl
  configure_with(SomeModule, :method => :setup, :storage => :settings)
  setup do
    setting1 "blah"
    setting2 "bleh"
  end
end

MyClass.settings.setting1 # => "blah"
MyClass.settings.setting2 # => "bleh"

Multiple Configurations

configuration_dsl supports multiple configurations for a single object.

module PersonalConfig
  def name(s)
    s.to_s
  end
  def age(n)
    n.to_i
  end
end

module AccountsConfig
  def twitter(name)
    name.to_s
  end
  def email(email)
    email.to_s
  end
end

class MyClass
  extend ConfigurationDsl
  configure_with(PersonalConfig, :method => :configure_personal, :storage => :personal_configuration)
  configure_with(AccountsConfig, :method => :configure_accounts, :storage => :accounts_configuration)
  configure_personal do
    name "Christopher"
    age 31
  end
  configure_accounts do
    twitter "cjbottaro"
    email "cjbottaro@alumni.cs.utexas.edu"
  end
end

MyClass.personal_configuration.name    # => "Christopher"
MyClass.personal_configuration.age     # => 31
MyClass.accounts_configuration.twitter # => "cjbottaro"
MyClass.accounts_configuration.email   # => "cjbottaro@alumni.cs.utexas.edu"

Contributing to configuration_dsl

  • Check out the latest master to make sure the feature hasn’t been implemented or the bug hasn’t been fixed yet

  • Check out the issue tracker to make sure someone already hasn’t requested it and/or contributed it

  • Fork the project

  • Start a feature/bugfix branch

  • Commit and push until you are happy with your contribution

  • Make sure to add tests for it. This is important so I don’t break it in a future version unintentionally.

  • Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.

Copyright © 2011 Christopher J Bottaro. See LICENSE.txt for further details.

About

Configure classes and objects using a DSL.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages