# Method Auto Completion (#112)

**URL:** <https://www.ruby-forum.com/t/method-auto-completion-112/83345>\
**Category:** Ruby\
**Created:** [January 25, 2007, 1:25pm UTC](https://www.ruby-forum.com/t/method-auto-completion-112/83345 "2007-01-25T13:25:41Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![bbazzarrakk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/47e85d/32.png) [@bbazzarrakk](https://www.ruby-forum.com/u/bbazzarrakk)\
**Post date:** [January 25, 2007, 1:25pm UTC](https://www.ruby-forum.com/t/method-auto-completion-112/83345/1 "2007-01-25T13:25:41Z")

</div>

by Robert D.

First of all I would like to thank all submitters.

One of the best features of the Ruby Q. is it tolerance brings up new  
ideas so  
often.

In order to honor this feature I will first present Daniel F.'s  
solution. It  
just abbreviates all defined methods. This very useful a feature which I  
will  
demonstrate after discussion of the code.

class Object  
Â Â Â def method\_missing(method, \*args, &blk)  
Â Â Â Â Â Â # Gather all possible methods it could be.  
Â Â Â Â Â Â possibleMethods = self.methods.select {|x|  
x =~ /^#{Regexp.escape(method.to\_s)}/  
}  
Â Â Â Â Â Â  
Â Â Â Â Â Â case possibleMethods.size  
Â Â Â Â Â Â # No matching method.  
Â Â Â Â Â Â when 0  
Â Â Â Â Â Â Â Â Â raise NoMethodError.new(  
"undefined method `#{method}’ for " +  
“#{self.inspect}:#{self.class.name}”  
)  
Â Â Â Â Â Â  
Â Â Â Â Â Â # One matching method, call it.  
Â Â Â Â Â Â when 1  
Â Â Â Â Â Â Â Â Â method = possibleMethods.first  
Â Â Â Â Â Â Â Â Â send(method, \*args, &blk)  
Â Â Â Â Â Â  
Â Â Â Â Â Â # Multiple possibilities, return an array of the  
possibilities.  
Â Â Â Â Â Â else  
Â Â Â Â Â Â Â Â Â "Ambigous abbreviation #{method} -\>Â " +  
“#{ possibleMethods.join(”, “)}”  
Â Â Â Â Â Â end  
Â Â Â end  
end

Nothing very complicated there, just define method\_missing in Object as  
a catch  
all for undefined methods in any object. Than he creates an array of all  
methods  
which are legal completions of a potential abbreviation. In case there  
are none  
an original NoMethodError is mimicked. In case there is exactly one it  
is  
executed via send, please note the (method, \*args, &blk) syntax, the  
&blk part  
has been forgotten in some solutions but is vital in #method\_missing.  
And  
eventually if there are more Daniel returned an array of all completions  
for  
testing. I will discuss this later.

I have adapted this to return a message explaining what completions  
exist for  
the abbreviation. Why? Well I just fired up my irb and requested  
Daniel’s  
solution, see what I got, much less typing for free. Here are some  
excerpts of  
my irb session.

irb(main):001:0\> require ‘sol2’  
=\> true  
irb(main):002:0\> “a”.le  
=\> 1  
irb(main):003:0\> “abba”.le  
=\> 4  
irb(main):004:0\> “Hello World”.spl  
=\> [“Hello”, “World”]  
irb(main):005:0\> “Hi there Daniel”.sp  
=\> [“Hi”, “there”, “Daniel”]  
irb(main):006:0\> “Hi there Daniel”.s  
=\> “Ambigous abbreviation s -\>Â select, slice, sub!, squeeze, send,  
split,  
size, strip, succ!, squeeze!, sub, slice!, scan, sort, swapcase,  
swapcase!,  
sum, singleton\_methods, succ, sort\_by, strip!”  
irb(main):007:0\> 12.x  
NoMethodError: undefined method `x' for 12:Fixnum Â Â Â Â Â Â Â Â Â Â Â Â from ./sol2.rb:9:in`method\_missing’  
Â Â Â Â Â Â Â Â Â Â Â Â from (irb):7

Quite nice as a side product, no?

Let us turn towards solutions which respected the idea of defining  
certain  
abbreviations, being interpreted in Command Line Interfaces for example.  
It was  
extremely difficult to chose a solution because most of the solutions  
had their  
strong parts. I eventually decided to comment on Donald B.'s solution  
as it  
was maybe the most readable solution for myself. I had discussed this  
with James  
who favored other solutions for other reasons and I will mention these  
reasons  
shortly. As always there is something in every solution so take your  
time and  
read them.

Ok here is Donald’s code - slightly modified again.

require ‘set’

module AutoComplete  
Â Â Â module ClassMethods  
Â Â Â Â Â Â attr\_reader :abbrs  
Â Â Â Â Â Â def abbrev(\*args)  
Â Â Â Â Â Â Â Â Â # TODO abbrs might be better implemented as a sorted set  
Â Â Â Â Â Â Â Â Â @abbrs ||= Set.new  
Â Â Â Â Â Â Â Â Â @abbrs += args  
Â Â Â Â Â Â end  
Â Â Â end  
Â Â Â module ObjectMethods  
Â Â Â Â Â Â def method\_missing(id, \*args, &blk)  
Â Â Â Â Â Â Â Â Â # if it is an exact match, there is no corresponding  
method  
# or else it would have been called  
Â Â Â Â Â Â Â Â Â if self.class.abbrs.include?(id)  
Â Â Â Â Â Â Â Â Â Â Â Â super  
Â Â Â Â Â Â Â Â Â end  
Â Â Â Â Â Â Â Â Â s = id.to\_s  
Â Â Â Â Â Â Â Â Â len = s.length  
Â Â Â Â Â Â Â Â Â # find all abbreviations which begin with id and have  
# active methods  
Â Â Â Â Â Â Â Â Â matches = self.class.abbrs.select { |abbr|  
abbr.to\_s[0,len] == s && respond\_to?(abbr)  
}  
Â Â Â Â Â Â Â Â Â if matches.length == 0  
Â Â Â Â Â Â Â Â Â Â Â Â super  
Â Â Â Â Â Â Â Â Â elsif matches.length == 1  
Â Â Â Â Â Â Â Â Â Â Â Â send(matches[0], \*args, &blk)  
Â Â Â Â Â Â Â Â Â else  
Â Â Â Â Â Â Â Â Â Â Â Â matches  
Â Â Â Â Â Â Â Â Â end  
Â Â Â Â Â Â end  
Â Â Â end  
end

class Object  
Â Â Â extend AutoComplete::ClassMethods  
Â Â Â include AutoComplete::ObjectMethods  
end

Although this can be done more concisely I eventually started to like  
the  
explicit way.

Lots of little details can be changed and they were in other solutions.  
Not  
everybody wanted a NoMethodError thrown in case an abbreviation target  
was an  
abbreviation of a different method and was not there.

Ken B. was the first to point out that it was a bad idea to return an  
array  
of abbreviations in case of ambiguities. I completely agree, that was  
only for  
the test code anyway.

A great majority of the solutions follow this idea which is certainly a  
must  
under some circumstances. I imagine a DSL which is not interactive and  
where the  
interpreter has no choice than to throw an Exception, good thinking  
here.

Ken’s solution has three features noteworthy, first he added the list of  
possible completions as an attribute of the exception he throws,  
secondly he  
just used the abbrev Standard Library Module and thirdly he used #super  
in  
#method\_missing to raise a NoMethodError. super in that case calls  
Kernel#method\_missing. This took me some time to figure out. I guess the  
road to  
Ruby mastery is not answering quizzes but submitting quizzes and  
understanding  
the solutions. But you will find some of these features in other  
solutions too.

Let us finish the summary with his code, another astonishing example of  
how much  
can be done with so little code in Ruby.

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

Many thanx to everyone…

---

<div class="post-metadata">

**Author:** ![bbazzarrakk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/47e85d/32.png) [@bbazzarrakk](https://www.ruby-forum.com/u/bbazzarrakk)\
**Post date:** [January 26, 2007, 2:47pm UTC](https://www.ruby-forum.com/t/method-auto-completion-112/83345/2 "2007-01-26T14:47:26Z")

</div>

For those keeping score at home, this message had a bad subject. It  
was the summary to quiz 110, not 112. I fat-fingered the launch. My  
apologies.

James Edward G. II
