the all-thing | 2010-09-04 16:31:06 -0400 ========================================== Ditz 0.4, and the magic of Ruby DSLs ------------------------------------ Date: July 27, 2008 6:21pm Author: William Morgan Labels: ditz URL: http://all-thing.net/old26.txt I've just released Ditz 0.4. The big-ticket item in this release is the plugin system, which makes it very easy to tweak Ditz's models, views and controllers. There's an included git plugin which does some nice things like linking git commits and git branches to individual Ditz issues. The new bash completion is pretty nice too. The completion code has been reworked a bit and now ties in very nicely with the argument processing. Check out this code from the Ditz's controller (operator.rb [1], for those following along from your repo): operation :start, "Start work on an issue", :unstarted_issue def start project, config, issue ## ... end Just by calling the operation method, we get: * Argument checking. There must be one argument to 'ditz start', and it must be an unstarted issue. Any violations are handled nicely for us without having to invoke the method. * Help messages in 'ditz help' and 'ditz help start'. * Argument completion. Running 'ditz start ' outputs a list of possible completions for a command (in this case, all unstarted issues) and then exits. Shell completion scripts can parse this output and present it to you when you hit tab. So that's a little DSL that I think turned out well. Writing a plugin is also nicely DSLified. Here are some examples from plugin/git.rb: class Issue field :git_branch, :ask => false def git_commits ## ... end end Here we reopen the Issue class and add a field called @git_branch@, and we specify that the UI shouldn't ask for this field when an issue is created, since I decided that would be too annoying. (We'll see how we allow the user to explicitly set it below.) We also add a method that's responsible for actually getting the commits out of git. Since our configuration file is just a Ditz model object, we can do the same thing to add the configuration parameters we need: class Config field :git_commit_url_prefix, :prompt =>"URL prefix (if any) to link git commits to" field :git_branch_url_prefix, :prompt => "URL prefix (if any) to link git branches to" end We'll use those two fields to add some links when we generate HTML. Adding commands to Ditz's controller is just as easy. Just reopen the class: class Operator operation :set_branch, "Set the git feature branch of an issue", :issue, :maybe_string def set_branch project, config, issue, maybe_string ## ... end end So now we have a @set-branch@ command that takes an issue name, and an optional branch name. And it's a first-class citizen alongside every other command: shows up in the help page, has argument auto-completion, etc. Finally, let's see how we modify the views. One thing we'd like to see is the git branch for an issue, if it's been set. class ScreenView add_to_view :issue_summary do |issue, config| " Git branch: #{issue.git_branch || 'none'}\n" end end Here we've opened up the ScreenView class (which is used for generating the screen output, as opposed to the HTML output) and added a closure to the summary section, which prints out the value of the model field we added above. The HTML version is similar: class HtmlView add_to_view :issue_summary do |issue, config| next unless issue.git_branch [{ :issue => issue, :url_prefix => config.git_branch_url_prefix }, < Git branch: <%= url_prefix ? link_to([url_prefix, issue.git_branch].join, issue.git_branch) : h(issue.git_branch) %> EOS end end The HTML generation returns ERB, and a hash of variables necessary for resolving it. (In this case we could also have used string substitution, but that's not always the case--you might want to make use of variables that are only available at generation time.) Note that it also makes use of some of the convenient helper functions (like @link_to@ and @h@), which I've helpfully defined for you in html.rb. So that's how to modify ditz's models, views and controllers in one easy go. You can add fields and helper methods to model objects (including the configuration object), you can add commands to the controller, and you can add view elements to the screen and HTML output. For reference, the complete source code to the git plugin is here [2]. [1] http://gitorious.org/projects/ditz/repos/mainline/blobs/master/lib%2Foperator.rb [2] http://gitorious.org/projects/ditz/repos/mainline/blobs/master/lib%2Fplugins%2Fgit.rb%22 This delicious text version served up by Whisper .