Reading SBPP has got me thinking about keyword parameters. Ruby doesn’t have keyword arguments, but it fakes them pretty well:
def explain(options={}) "the #{options[:the]} says #{options[:says]}" end explain the: "pig", says: "oink" # => "the pig says oink" explain the: "frog", says: "ribbit" # => "the frog says ribbit"
Which is fine, but it isn’t as declarative (and therefore not as self-documenting) as proper keyword arguments.
Also, when using keywords to construct English-like DSLs, as we are above, we often would like to assign different names to the parameters which are passed by keyword.
def explain2(options={}) animal = options[:the] sound = options[:says] "the #{animal} says #{sound}" end
And then there’s defaulting for missing paramters…
def explain3(options={}) animal = options.fetch(:the) { "cow" } sound = options.fetch(:says){ "moo" } "the #{animal} says #{sound}" end explain3 # => "the cow says moo"
Of course, it might be nice to offer a positional-argument version as well.
def explain4(*args) options = args.last.is_a?(Hash) ? args.pop : {} animal = args[0] || options.fetch(:the) { "cow" } sound = args[1] || options.fetch(:says){ "moo" } "the #{animal} says #{sound}" end explain4 "horse", "neigh" # => "the horse says neigh" explain4 "duck", says: "quack" # => "the duck says quack" explain4 the: "donkey", :says => "hee-haw" # => "the donkey says hee-haw"
Once we’ve written all this parameter-munging machinery, we then repeat it in the method’s documentation. (Assuming we document it at all). This seems a bit un-DRY.
Let’s see if we can improve on the situation.
$ gem install keyword_params Fetching: keyword_params-0.0.1.gem (100%) Successfully installed keyword_params-0.0.1 1 gem installed
require 'keyword_params' class BarnYard extend KeywordParams keyword(:the) { "cow" } keyword(:says) { "moo" } def explain(animal, sound) "the #{animal} says #{sound}" end end b = BarnYard.new b.explain "horse", "neigh" # => "the horse says neigh" b.explain "duck", says: "quack" # => "the duck says quack" b.explain the: "donkey", says: "hee-haw" # => "the donkey says hee-haw" b.explain the: "cat" # => "the cat says moo" b.explain # => "the cow says moo"
This is just an alpha-level library I banged out during RubyConf 2011, so I’m sure there are plenty of edge cases I haven’t handled. I’ll leave it to you to decide if the syntax above is an improvement or not. There’s a certain nasty “pre-ISO C functions” feel to declaring the keywords before the method definition. But I like that the acceptable parameters are obvious and not hidden in the method definition.
Of course, none of this is a substitute for real language-level keyword params, which I hear we’ll be getting in Ruby 2.0. But in the meantime, it’s something to play with.
The code is here: https://github.com/avdi/keyword_params
[ERROR: No "bytitle", "bypath" or "byid" arguments where provided with the boilerplate shortcode or the values provided did not match an existing boilerplate entry.]




