Plugin configuration style?

Courtenay : November 10th, 2008

I’m putting the final touches on a super-sweet versioning plugin, and I’ve discovered that we’re using several different metaphors for configuring the plugin options. I’d like to get some opinions/feedback on your preferred style.

The DSL

Using a DSL and passing blocks in which get instance evalled. I’m normally very scathing of DSLs; I think that they’re Yet Another Language for people to learn to use – it’s usually your very own write-only syntax – but it’s been super-fun implementing the backend to this.

class Monkey < ActiveRecord::Base
  versioning do
    author do
      name { user.current.name }
      message { "Commited via #{name}" }
    end
    repository "Joe's DataStore" 
  end

Hashes

This seems to be the Rails plugin default:

class Monkey < ActiveRecord::Base
  versioning :author => { :name => lambda{ |u| user.current.name } }, :repository => "Joe's DataStore" 
end

Class vars / methods

Easy to monkeypatch later

class Monkey < ActiveRecord::Base
   will_version
   @@version_repository = "Joe's DataStory" 
   def version_author
     current_name
   end
end

Are there others? Which do you prefer? Currently I’m using all three in this one plugin, and it’s very un-awesome.

7 Responses to “Plugin configuration style?”

  1. mateo Says:

    I think the hash is best for most configs, although a DSL can be more readable in more complex cases, especially when it means avoiding lambdas everywhere. The class vars just don't sit well with my conception of how a plugin should work, and it makes it hard to figure out at a glance what belongs to the plugin and what doesn't. Indeed, looking at it quickly, you'd think that the 3rd example simply doesn't have any configuration options...

  2. BJ Clark Says:

    Hashes ftw.

    Unless the hash gets out of control, then a graduating up to a DSL is better.

    But your example hash is perfect.

  3. Coda Hale Says:

    Hashes are for Perl programmers. Use objects:

    class Monkey < ActiveRecord::Base
      include AwesomeVersioning::ModelExtensions
    
      def self.repository_name
        return "Joe's DataStore"
      end
    
      def before_versioning(version)
        version.name = user.current.name
        version.message = "Committed via #{name}"
      end
    end
    
  4. Craig Buchek Says:

    I agree with Mateo and BJ completely.

    You could also do a hash plus some hooks:

    versioning :author => { :name => lambda{ |u| user.current.name } }, :repository => "Joe's DataStore"
    before_versioning {|version| version.message = "Committed via #{version.name}" }
    
  5. Ryan Bates Says:

    Ultimately it comes down to what is most readable. Generally I find block style syntax more readable than a complex hash, but not in this case.

    I have a hard time understanding DSLs when they mess with the current scope. What do the "name" and "message" methods do and what scope are they being called in? By the look of it they should be called on the class, but that's probably not true. Maybe instead pass an object to the block and call the methods on that?

  6. rick Says:

    Rein put it best in http://reinh.com/blog/2008/07/14/a-thinking-mans-sphinx.html.

  7. RSL Says:

    I'm personally fond of the block style but simply using it as a block with normal Ruby syntax for setting values, etc rather than adding another DSL to the platter. Would that be a fourth option or just a variant on your first?

Sorry, comments are closed for this article.