Tagged With   gem:name=thor , lib:name=irb , post:type=tutorial , gem:topic=parse , gem:topic=options , post:lang=ruby

Quicker Options For Irb Methods

Although irb does come with decent auto completion, I often prefer aliasing methods. To some degree I’ve come up with a decent solution to managing method aliases but what do you do when you want to alias a method’s options?

While working on a console-based rails app, I got tired of passing the same options hashes to an irb method:

# An irb method that wraps around an object I access often:
def tg(query, options={})
  TagGroup.new(query, options)
irb>> tg '=irb', :view=>:result
irb>> tg '=irb', :view=>:description_result
irb>> tg '=irb', :view=>:group

If I knew that tg()‘s second argument would always be a hash with certain keys and values, why couldn’t I just alias them in the same way a shell’s command has aliased options?

irb>> tg '=irb -v result'
# or possibly even
irb>> tg '=irb -v r'

Update: If you want a solution to this that just works, see my gem boson.
Handling aliasing for this simple case isn’t too hard. But what happens if certain options are boolean flags, if some options are required while other’s aren’t, if some options need default values … So rather than reinvent an inferior wheel, I remembered a simple yet powerful option parser embedded within thor.
A few examples:

# Parse a boolean and optional option
irb>> parser = Thor::Options.new(:foo=>:optional, :verbose=>:boolean)
irb>> parser.parse("some args -f fighter -v more args")
=>  {'foo'=>'fighter', 'verbose'=>true}
# Parse a numeric option and an option with a default. 
irb>> parser = Thor::Options.new(:foo=>'lish', :num=>:numeric)
irb>> parser.parse("some args --num 10")
=>  {'foo'=>'lish', :num=>10}

More examples can be found in thor’s tests.

Although thor’s option parser could handle aliasing option keys well, it didn’t do anything for aliasing option arguments. It also didn’t have a way of returning values as symbols. So I wrote a MethodOptionParser class to handle these needs. This class simply wraps around Thor::Options, adding the features I needed and provides one method, MethodOptionParser.parse() to do all the work. To update my previous definition of tg():

def tg(query, options={})
  # :view key contains values it expects and thus we can alias.
  args, options = MethodOptionParser.parse(query, :view=>[:result, :group, :count, :description_result])
  TagGroup.new(args.join(" "), options)

MethodOptionParser.parse() takes a string or array of arguments and a hash of expected options for the arguments and returns the optionless arguments along with the parsed options. Remember, the expected options can be any options which Thor::Options recognizes.

With this improved tg(), the first example can now be:

irb>> tg '=irb -v r'  # same as tg '=irb', :view=>:result
irb>> tg '=irb -v d', # same as tg '=irb', :view=>:description_result
irb>> tg '=irb -v g', # same as tg '=irb', :view=>:group

Much quicker! Although my fingers may be happy for now, the coder in me knows this solution can still be improved. I don’t want a method’s options lying far away from the method itself. If I start using these shortcuts on a larger scale I don’t want a whole bunch of MethodOptionParser.parse() calls lying around everywhere. Rather I plan to use some aop or metaprogramming techniques to cleanly abstract a method’s option aliases to a simple configuration file as I’ve done with my other aliasing needs.

Enjoyed this post? Tell others! hacker newsHacker News | twitterTwitter | DeliciousDelicious | redditReddit
blog comments powered by Disqus