[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

[QUIZ] Method Auto Completion (#110

James Gray

1/19/2007 1:45:00 PM

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.rub...

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...

4 Answers

Krishna Dole

1/21/2007 4:00:00 PM

0

Last week I was kind of embarrassed that Bob chose to feature my late,
poorly commented, somewhat opaque solution, but I certainly appreciate
the inclusive spirit of Ruby Quiz. Here's a more timely submission for
the auto completion problem.

--------------------------------------------------------
class Object
def self.abbrev(*args)
module_eval <<-EOS
@@abbrevs ||= []
@@abbrevs += args

def method_missing(m)
# abbrev targets themselves are not supposed to be expanded
raise NoMethodError if @@abbrevs.include?(m)

# which abbrev targets could match m, and which of those
correspond to methods?
matches = @@abbrevs.select do |sym|
sym.to_s.index(m.to_s) == 0 && methods.include?(sym.to_s)
end

case matches.size
when 0
raise NoMethodError
when 1
self.send(matches.first)
else
# multiple matches, pass them back to the user
return matches if $TESTING
puts matches.join(" ")
end
end
EOS

end
end
--------------------------------------------------------

This code passes the supplied tests, and I also added another test
when an earlier version of my code was doing things it shouldn't have:

--------------------------------------------------------
# check for unintended effects on other classes
class Test3 < Test::Unit::TestCase
def setup
@foo_class = Class.new {
abbrev :start
def start; nil end
}
@bar_class = Class.new {
def start; nil end
}
end

def test1
f = @foo_class.new
b = @bar_class.new
assert_raise NoMethodError do
b.send(:sta)
end
end
end
--------------------------------------------------------


I don't feel very confident in the approach I've taken, so I'm eager
to hear critique and see other solutions.

Krishna



On 1/19/07, Ruby Quiz <james@grayproductions.net> 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.rub...
>
> 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...
>
>

Maël Clérambault

1/21/2007 4:24:00 PM

0

Here is my solution.
It does not pass the supplied tests since it uses a different interface when
there are multiple matches : It a raises a MultipleMethods exception with an
array of the possible matches.

There is an additional abbrev method in Module which defines the methods to be
abbreviated. If used with the single argument 'true' it enables abbreviations
for all methods of the object.
the 'abbreviated_methods' private method of Object does the intersection of
the defined object class's abbreviated methods and the current actual methods
of the object.
Then the abbreviation are caught with method_missing.


quiz110.rb :

class MultipleMethods < NoMethodError
attr_reader :methods
def initialize(methods)
@methods = methods
super("Multiple Choices : " + @methods.join(' '))
end
end

class Module
attr_reader :abbreviated_methods

private
# Defines a list of methods to be abbreviated.
# If auto = true, then all the methods are abbreviated
#
# class Test
# abbrev # All the methods of Test will be abbreviated
# end
#
# class Test2
# abbrev :first, :last # Only the methods first and last may be
abbreviated
# end
#
# If multiple choices are possible, a MultipleMethods exception is raised
which contains a list of the matches.
def abbrev(auto = true, *args)
if auto.respond_to? :to_sym
@abbreviated_methods ||= []
@abbreviated_methods += args.collect {|m| m.to_sym }.unshift auto.to_sym
elsif args.empty?
auto ? @abbreviated_methods = [] : @abbreviated_methods = nil
else
raise ArgumentError
end
end
end

class Object
alias :abbrev_method_missing :method_missing
def method_missing(sym, *args)
found = abbreviated_methods.select { |m| m.to_s =~ /^#{sym}/ }
if found.empty?
abbrev_method_missing(sym, *args)
elsif found.size == 1
send found.first, *args
else
raise MultipleMethods.new(found)
end
end

private
def abbreviated_methods
if self.class.abbreviated_methods.nil?
[]
elsif self.class.abbreviated_methods.empty?
methods
else
self.class.abbreviated_methods & methods.collect {|m| m.to_sym}
end
end
end

Michael Fellinger

1/21/2007 5:31:00 PM

0

On 1/19/07, Ruby Quiz <james@grayproductions.net> 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.rub...
>
> 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...
>
>

My Solution doesn't pass all tests, since i think that when a method
:aa is defined it should offer completion from :a to :aa (even when
the method doesn't exist in the first place but is defined later on)

http://pastie.cabo...

It's nothing fancy, just a quick 15 minutes-hack, was fun though :)

^manveru

Michael Fellinger

1/21/2007 5:34:00 PM

0

> My Solution doesn't pass all tests, since i think that when a method
> :aa is defined it should offer completion from :a to :aa (even when
> the method doesn't exist in the first place but is defined later on)
>
> http://pastie.cabo...

http://pastie.cabo... - forgot to remove the other stuff :| and
somehow it didn't set highlighting to ruby...

>
> It's nothing fancy, just a quick 15 minutes-hack, was fun though :)
>
> ^manveru
>