On Fri, 19 Jan 2007 22:45:05 +0900, Ruby Quiz wrote:

> The three rules of Ruby Quiz:
> 
> 1.  Please do not post any solutions or spoiler discussion for this quiz until
> 48 hours have passed from the time on this message.
> 
> 2.  Support Ruby Quiz by submitting ideas as often as you can:
> 
> http://www.rubyquiz.com/
> 
> 3.  Enjoy!
> 
> Suggestion:  A [QUIZ] in the subject of emails about the problem helps everyone
> on Ruby Talk follow the discussion.  Please reply to the original quiz message,
> if you can.
> 
> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
> 
> by Robert Dober
> 
> Command Line Interfaces very often support command abbreviations The purpose of
> this quiz is to automatically dispatch to methods on unambiguous abbreviations,
> ask the user for clarification in case of ambiguous abbreviations and raise a
> NoMethodError in case of an abbreviation that cannot be matched to any command.
> 
> Behavior of other methods defined in a class shall not be altered.
> 
> Be creative about the interface and about behavior. I have OTOH defined a small
> test suite that makes assumptions about the interface and behavior. But the test
> suite is only there for your convenience.
> 
> What is said below applies to the test suite and shall in no way inhibit any
> alternative ideas.
> 
> 	class Mine
> 	  abbrev :step, :next, :stop
> 	  abbrev :exit
> 	end
> 	
> 	Mine.new.e  # should resolve to exit
> 	Mine.new.st # should prompt the user 
> 	Mine.new.a  # should still raise a NoMethodError
> 
> Abbreviation targets themselves are not expanded.
> 
> 	class Nine
> 	  abbrev  :hash
> 	  abbrev  :has
> 	end
> 	
> 	Nine.new.ha  # => [:hash, :has] 
> 	Nine.new.has # => NoMethodError
> 	
> 	class Nine
> 	  def has; 42; end
> 	end
> 	Nine.new.has # => 42
> 
> In order to allow for automated testing the test code shall not prompt the user
> in case of an ambiguous abbreviation but return an array containing all (and
> only all) possible completions as symbols. Note that the test suite sets the
> global variable $TESTING to a true value for your convenience.
> 
> 	http://rubyquiz.com/test-abbrev.rb

Returning an array when the answer is ambiguous is a very bad way to do
this. Instead, I throw an exception (you can get the candidates from the
#candidates attribute of the exception).

I also saw no reason to specifically name the methods that get abbreviated
-- rather, abbreviation works on all methods in the object and its super
classes.

require 'abbrev'

class AmbiguousExpansionError < StandardError
   attr_accessor :candidates
   def initialize(name,possible_methods)
      super("Ambiguous abbreviaton: #{name}\n"+
            "Candidates: #{possible_methods.join(", ")}")
      @candidates=possible_methods
   end
end

module Abbreviator
   def method_missing name,*args
      abbrevs=methods.abbrev
      return send(abbrevs[name.to_s],*args) if abbrevs[name.to_s]
      meths=abbrevs.reject{|key,value| key!~/^#{name}/}.values.uniq
      raise AmbiguousExpansionError.new(name, meths) if meths.length>1
      return super(name,*args)
   end
end


-- 
Ken Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu/~kbloom1/