guessmethod 0.0.8 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +8 -0
- data/README.txt +4 -4
- data/Rakefile +1 -1
- data/lib/guessmethod.rb +112 -103
- data/lib/guessmethod/version.rb +2 -2
- data/spec/guessmethod_spec.rb +10 -6
- data/website/index.html +6 -6
- data/website/index.txt +4 -4
- metadata +2 -11
data/History.txt
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
== 0.1.0 2007-09-23
|
2
|
+
|
3
|
+
* Moved GuessConstant to inside GuessMethod
|
4
|
+
* Cleaned up Formatter (a little, it should still be redone)
|
5
|
+
* One more test for GuessConstant
|
6
|
+
* Renamed Outputter, Formatter, and Options to have GuessMethod as a prefix to avoid name conflicts
|
7
|
+
* Removed the dependency on HighLine
|
8
|
+
|
1
9
|
== 0.0.8 2007-08-07
|
2
10
|
|
3
11
|
* enhancements
|
data/README.txt
CHANGED
@@ -16,10 +16,10 @@ If you accidentally try to access <tt>File::RDWr</tt>, you'll get <tt>File::RDWR
|
|
16
16
|
|
17
17
|
<tt>GuessMethod::Options</tt> is a hash with configuration values.
|
18
18
|
|
19
|
-
* <code>
|
20
|
-
* <code>
|
21
|
-
* <code>
|
22
|
-
* <code>
|
19
|
+
* <code>GuessMethodOptions[:insert_weight]</code>, <code>GuessMethodOptions[:delete_weight]</code>, and <code>GuessMethodOptions[:substitution_weight]</code> change how the levenshtein distance is calculated between method and constant names. The default values are all 1.
|
20
|
+
* <code>GuessMethodOptions[:threshold]</code> determines what levenshtein distance a method or constant must be within to count as a possible match. Values over 2 can give you unpredictable results, especially for short names. The default value is 2.
|
21
|
+
* <code>GuessMethodOptions[:max_inspect_length]</code> is, for now, the longest an object's inspect value can be before it's not displayed in messages, and is replaced with simply the standard #<Object:0x142100c>. The default value is 25.
|
22
|
+
* <code>GuessMethodOptions[:active]</code> determines whether or not GuessMethod does its thing. If set to false (or nil) it'll step aside. Useful for when it gets in the way of something going off correctly (which happens sometimes).
|
23
23
|
|
24
24
|
= Warning
|
25
25
|
|
data/Rakefile
CHANGED
@@ -78,7 +78,7 @@ hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
|
78
78
|
|
79
79
|
# == Optional
|
80
80
|
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
81
|
-
p.extra_deps = [['
|
81
|
+
p.extra_deps = [['rake', '>=0.7']] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
|
82
82
|
#p.spec_extras = {} # A hash of extra values to set in the gemspec.
|
83
83
|
end
|
84
84
|
|
data/lib/guessmethod.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'string/levenshtein'
|
2
|
-
require 'highline'
|
3
2
|
|
4
3
|
# The GuessMethod module aliases out method_missing and
|
5
4
|
# replaces it with its own, which attempts to find a
|
@@ -10,7 +9,7 @@ require 'highline'
|
|
10
9
|
# gets called.
|
11
10
|
module GuessMethod
|
12
11
|
|
13
|
-
|
12
|
+
GuessMethodOptions = {
|
14
13
|
:insert_weight => 1,
|
15
14
|
:delete_weight => 1,
|
16
15
|
:substitution_weight => 1,
|
@@ -32,18 +31,18 @@ module GuessMethod
|
|
32
31
|
end
|
33
32
|
|
34
33
|
def guess_method_missing(meth, *args, &block)
|
35
|
-
if
|
36
|
-
possible_methods =
|
34
|
+
if GuessMethodOptions[:active]
|
35
|
+
possible_methods = GuessMethodGuesser.find_closest(self.methods, meth)
|
37
36
|
case possible_methods.size
|
38
37
|
when 1
|
39
38
|
call_method = possible_methods.first
|
40
|
-
$stderr.puts
|
39
|
+
$stderr.puts GuessMethodOutputter.replacing_method(meth, call_method, self)
|
41
40
|
self.send(call_method, *args, &block)
|
42
41
|
when 0
|
43
|
-
$stderr.puts
|
42
|
+
$stderr.puts GuessMethodOutputter.no_method_in_threshold(meth, self)
|
44
43
|
old_method_missing(meth, *args, &block)
|
45
44
|
else
|
46
|
-
$stderr.puts
|
45
|
+
$stderr.puts GuessMethodOutputter.ambiguous_method(meth, possible_methods, self)
|
47
46
|
old_method_missing(meth, *args, &block)
|
48
47
|
end
|
49
48
|
else
|
@@ -51,143 +50,153 @@ module GuessMethod
|
|
51
50
|
end
|
52
51
|
end
|
53
52
|
|
54
|
-
#
|
53
|
+
# The GuessConstant module aliases out const_missing and
|
54
|
+
# replaces it with its own, which attempts to find a
|
55
|
+
# similarly named constant for the object at hand.
|
56
|
+
# If it finds one, it returns that instead, and prints
|
57
|
+
# a message to stderr explaining as much. If it doesn't
|
58
|
+
# find a suitable constant, the orignial const_missing
|
59
|
+
# gets called.
|
60
|
+
module GuessConstant
|
61
|
+
def self.extended(base) #:nodoc:
|
62
|
+
base.class_eval do
|
63
|
+
unless respond_to? :const_missing
|
64
|
+
def self.const_missing(sym); super; end
|
65
|
+
end
|
66
|
+
class << self
|
67
|
+
alias_method :old_const_missing, :const_missing
|
68
|
+
alias_method :const_missing, :guess_const_missing
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def guess_const_missing(sym)
|
74
|
+
if GuessMethodOptions[:active]
|
75
|
+
possible_consts = GuessMethodGuesser.find_closest(self.constants, sym)
|
76
|
+
case possible_consts.size
|
77
|
+
when 1
|
78
|
+
call_const = possible_consts.first
|
79
|
+
$stderr.puts GuessMethodOutputter.replacing_const(sym, call_const, self)
|
80
|
+
self.const_get(call_const)
|
81
|
+
when 0
|
82
|
+
$stderr.puts GuessMethodOutputter.no_const_in_threshold(sym, self)
|
83
|
+
old_const_missing(sym)
|
84
|
+
else
|
85
|
+
$stderr.puts GuessMethodOutputter.ambigious_const(sym, possible_consts, self)
|
86
|
+
old_const_missing(sym)
|
87
|
+
end
|
88
|
+
else
|
89
|
+
old_const_missing(sym)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# GuessMethodGuesser uses map, min, and levensthtein to find the closest
|
55
95
|
# match(es) in an array of strings
|
56
|
-
class
|
96
|
+
class GuessMethodGuesser
|
57
97
|
def self.find_closest(haystack, needle)
|
58
98
|
closest_distance = haystack.map {|x| x.to_s.downcase.levenshtein(needle.to_s.downcase,
|
59
|
-
|
60
|
-
|
61
|
-
if closest_distance <=
|
99
|
+
GuessMethodOptions[:insert_weight], GuessMethodOptions[:delete_weight],
|
100
|
+
GuessMethodOptions[:substitution_weight])}.min
|
101
|
+
if closest_distance <= GuessMethodOptions[:threshold]
|
62
102
|
haystack.find_all {|x| x.to_s.downcase.levenshtein(needle.to_s.downcase,
|
63
|
-
|
64
|
-
|
103
|
+
GuessMethodOptions[:insert_weight], GuessMethodOptions[:delete_weight],
|
104
|
+
GuessMethodOptions[:substitution_weight]) == closest_distance}
|
65
105
|
else
|
66
106
|
[]
|
67
107
|
end
|
68
108
|
end
|
69
109
|
end
|
70
110
|
|
71
|
-
#
|
72
|
-
|
73
|
-
class Outputter
|
111
|
+
# GuessMethodOutputter uses a little Formatter class for colorization
|
112
|
+
class GuessMethodOutputter
|
74
113
|
|
75
|
-
Formatter
|
114
|
+
class Formatter
|
115
|
+
ColorCodes = {
|
116
|
+
:bold => '1',
|
117
|
+
:red => '31',
|
118
|
+
:green => '32',
|
119
|
+
:cyan => '36'
|
120
|
+
}
|
121
|
+
|
122
|
+
# Returns an ANSI colorized string (for a limited set of options, see ColorCodes)
|
123
|
+
def self.color(text, *colors)
|
124
|
+
format = colors.map {|color| ColorCodes[color]}.join(';')
|
125
|
+
"\e[#{format}m#{text}\e[0m"
|
126
|
+
end
|
127
|
+
end
|
76
128
|
|
77
129
|
def self.object(obj) #:nodoc:
|
78
130
|
inspected = obj.inspect
|
79
|
-
if obj.inspect.length >
|
131
|
+
if obj.inspect.length > GuessMethodOptions[:max_inspect_length]
|
80
132
|
Formatter.color("#<#{obj.class}:0x#{(obj.object_id*2).to_s(16)}>", :green)
|
81
133
|
else
|
82
|
-
|
83
|
-
message << ':'
|
84
|
-
message << Formatter.color(obj.class, :green)
|
134
|
+
Formatter.color(obj.inspect, :green, :bold) << ':' << Formatter.color(obj.class, :green)
|
85
135
|
end
|
86
136
|
end
|
87
137
|
|
88
138
|
def self.ambiguous_method(meth, possibilities, obj) #:nodoc:
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
139
|
+
Formatter.color('ambigious method:', :red) <<
|
140
|
+
' ' <<
|
141
|
+
Formatter.color(meth, :green) <<
|
142
|
+
' possible matches ' <<
|
143
|
+
possibilities.map {|m| Formatter.color(m, :cyan)}.join(', ') <<
|
144
|
+
' for ' <<
|
145
|
+
GuessMethodOutputter.object(obj)
|
96
146
|
end
|
97
147
|
|
98
148
|
def self.no_method_in_threshold(meth, obj) #:nodoc:
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
149
|
+
Formatter.color('no method in threshold:', :red) <<
|
150
|
+
' for ' <<
|
151
|
+
Formatter.color(meth, :green) <<
|
152
|
+
', sending to ' <<
|
153
|
+
GuessMethodOutputter.object(obj) <<
|
154
|
+
"'s method_missing"
|
105
155
|
end
|
106
156
|
|
107
157
|
def self.replacing_method(meth, call_method, obj) #:nodoc:
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
158
|
+
Formatter.color('attention:', :red) <<
|
159
|
+
' sending ' <<
|
160
|
+
Formatter.color(call_method, :cyan) <<
|
161
|
+
' instead of ' <<
|
162
|
+
Formatter.color(meth, :cyan) <<
|
163
|
+
' to ' <<
|
164
|
+
GuessMethodOutputter.object(obj)
|
115
165
|
end
|
116
166
|
|
117
167
|
def self.ambigious_const(sym, possibilities, obj) #:nodoc:
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
168
|
+
Formatter.color('ambigious constant:', :red) <<
|
169
|
+
' ' <<
|
170
|
+
Formatter.color(sym, :green) <<
|
171
|
+
' possible matches ' <<
|
172
|
+
possibilities.map {|m| Formatter.color(m, :cyan)}.join(', ') <<
|
173
|
+
' for ' <<
|
174
|
+
GuessMethodOutputter.object(obj)
|
125
175
|
end
|
126
176
|
|
127
177
|
def self.no_const_in_threshold(sym, obj) #:nodoc:
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
178
|
+
Formatter.color('no constant in threshold:', :red) <<
|
179
|
+
' for ' <<
|
180
|
+
Formatter.color(sym, :green) <<
|
181
|
+
', sending to ' <<
|
182
|
+
Formatter.color(obj, :green, :bold) <<
|
183
|
+
"'s const_missing"
|
134
184
|
end
|
135
185
|
|
136
186
|
def self.replacing_const(sym, call_const, obj) #:nodoc:
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
187
|
+
Formatter.color('attention:', :red) <<
|
188
|
+
' replacing non-existant constant ' <<
|
189
|
+
Formatter.color(sym, :cyan) <<
|
190
|
+
' with ' <<
|
191
|
+
Formatter.color(call_const, :cyan) <<
|
192
|
+
' for ' <<
|
193
|
+
Formatter.color(obj, :green, :bold)
|
144
194
|
end
|
145
195
|
|
146
196
|
end
|
147
197
|
|
148
198
|
end
|
149
199
|
|
150
|
-
# The GuessConstant module aliases out const_missing and
|
151
|
-
# replaces it with its own, which attempts to find a
|
152
|
-
# similarly named constant for the object at hand.
|
153
|
-
# If it finds one, it returns that instead, and prints
|
154
|
-
# a message to stderr explaining as much. If it doesn't
|
155
|
-
# find a suitable constant, the orignial const_missing
|
156
|
-
# gets called.
|
157
|
-
module GuessConstant
|
158
|
-
def self.extended(base) #:nodoc:
|
159
|
-
base.class_eval do
|
160
|
-
unless respond_to? :const_missing
|
161
|
-
def self.const_missing(sym); super; end
|
162
|
-
end
|
163
|
-
class << self
|
164
|
-
alias_method :old_const_missing, :const_missing
|
165
|
-
alias_method :const_missing, :guess_const_missing
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
def guess_const_missing(sym)
|
171
|
-
if Options[:active]
|
172
|
-
possible_consts = GuessMethod::Guesser.find_closest(self.constants, sym)
|
173
|
-
case possible_consts.size
|
174
|
-
when 1
|
175
|
-
call_const = possible_consts.first
|
176
|
-
$stderr.puts GuessMethod::Outputter.replacing_const(sym, call_const, self)
|
177
|
-
self.const_get(call_const)
|
178
|
-
when 0
|
179
|
-
$stderr.puts GuessMethod::Outputter.no_const_in_threshold(sym, self)
|
180
|
-
old_const_missing(sym)
|
181
|
-
else
|
182
|
-
$stderr.puts GuessMethod::Outputter.ambigious_const(sym, possible_consts, self)
|
183
|
-
old_const_missing(sym)
|
184
|
-
end
|
185
|
-
else
|
186
|
-
old_const_missing(sym)
|
187
|
-
end
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
200
|
require 'guessmethod/version'
|
192
201
|
|
193
202
|
class Object; include GuessMethod; end
|
data/lib/guessmethod/version.rb
CHANGED
data/spec/guessmethod_spec.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
2
|
require 'lib/guessmethod.rb'
|
3
3
|
|
4
|
-
describe
|
4
|
+
describe 'GuessMethod naturally' do
|
5
5
|
|
6
6
|
it "should define guess_method_missing on Object" do
|
7
7
|
Object.should.respond_to? :guess_method_missing
|
8
8
|
end
|
9
9
|
|
10
|
+
it 'should define guess_const_missing on Object' do
|
11
|
+
Object.should.respond_to? 'guess_const_missing'
|
12
|
+
end
|
13
|
+
|
10
14
|
it "should figure out toi means to_i" do
|
11
15
|
'1'.toi.should == 1
|
12
16
|
end
|
@@ -24,15 +28,15 @@ describe "GuessMethod naturally" do
|
|
24
28
|
end
|
25
29
|
|
26
30
|
it "should be off if it gets turned off" do
|
27
|
-
|
31
|
+
GuessMethodOptions[:active] = false
|
28
32
|
lambda{Class.nw}.should raise_error(NoMethodError)
|
29
33
|
lambda{Cass == Class}.should raise_error(NameError)
|
30
|
-
|
34
|
+
GuessMethodOptions[:active] = true
|
31
35
|
end
|
32
36
|
|
33
37
|
it "should be on if it gets turned on" do
|
34
|
-
|
35
|
-
|
38
|
+
GuessMethodOptions[:active] = false
|
39
|
+
GuessMethodOptions[:active] = true
|
36
40
|
lambda{Class.nw}.should_not raise_error
|
37
41
|
Cass.should == Class
|
38
42
|
end
|
@@ -68,4 +72,4 @@ describe "On a method_missing-defining class, GuessMethod" do
|
|
68
72
|
lambda{A.new.not_a_method}.should raise_error(NoMethodError)
|
69
73
|
end
|
70
74
|
|
71
|
-
end
|
75
|
+
end
|
data/website/index.html
CHANGED
@@ -33,7 +33,7 @@
|
|
33
33
|
<h1>Guess Method</h1>
|
34
34
|
<div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/guessmethod"; return false'>
|
35
35
|
<p>Get Version</p>
|
36
|
-
<a href="http://rubyforge.org/projects/guessmethod" class="numbers">0.0
|
36
|
+
<a href="http://rubyforge.org/projects/guessmethod" class="numbers">0.1.0</a>
|
37
37
|
</div>
|
38
38
|
<h1>→ ‘guessmethod’</h1>
|
39
39
|
|
@@ -87,10 +87,10 @@ attention: sending exit instead of eixt to main:Object
|
|
87
87
|
|
88
88
|
|
89
89
|
<ul>
|
90
|
-
<li><code>
|
91
|
-
<li><code>
|
92
|
-
<li><code>
|
93
|
-
<li><code>
|
90
|
+
<li><code>GuessMethodOptions[:insert_weight]</code>, <code>GuessMethodOptions[:delete_weight]</code>, <code>GuessMethodOptions[:substitution_weight]</code> change how the levenshtein distance is calculated between method and constant names. The default values are all 1.</li>
|
91
|
+
<li><code>GuessMethodOptions[:threshold]</code> determines what levenshtein distance a method or constant must be within to count as a possible match. Values over 2 can give you unpredictable results, especially for short names. The default value is 2.</li>
|
92
|
+
<li><code>GuessMethodOptions[:max_inspect_length]</code> is, for now, the longest an object’s inspect value can be before it’s not displayed in messages, and is replaced with simply the standard #<Object:0×142100c>. The default value is 25.</li>
|
93
|
+
<li><code>GuessMethodOptions[:active]</code> determines whether or not GuessMethod does its thing. If set to false (or nil) it’ll step aside. Useful for when it gets in the way of something going off correctly (which happens sometimes).</li>
|
94
94
|
</ul>
|
95
95
|
|
96
96
|
|
@@ -125,7 +125,7 @@ attention: sending exit instead of eixt to main:Object
|
|
125
125
|
|
126
126
|
<p>Comments are welcome. Send an email to chris @@ tie-rack .. org.</p>
|
127
127
|
<p class="coda">
|
128
|
-
website generated via <a href="mailto:drnicwilliams@gmail.com">Dr Nic</a>'s <a href="http://newgem.rubyforge.org/">newgem</a>, on
|
128
|
+
website generated via <a href="mailto:drnicwilliams@gmail.com">Dr Nic</a>'s <a href="http://newgem.rubyforge.org/">newgem</a>, on 23rd September 2007<br>
|
129
129
|
Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
|
130
130
|
</p>
|
131
131
|
</div>
|
data/website/index.txt
CHANGED
@@ -43,10 +43,10 @@ attention: sending exit instead of eixt to main:Object
|
|
43
43
|
|
44
44
|
There are a number of options available which affect how GuessMethod works.
|
45
45
|
|
46
|
-
* <code>
|
47
|
-
* <code>
|
48
|
-
* <code>
|
49
|
-
* <code>
|
46
|
+
* <code>GuessMethodOptions[:insert_weight]</code>, <code>GuessMethodOptions[:delete_weight]</code>, <code>GuessMethodOptions[:substitution_weight]</code> change how the levenshtein distance is calculated between method and constant names. The default values are all 1.
|
47
|
+
* <code>GuessMethodOptions[:threshold]</code> determines what levenshtein distance a method or constant must be within to count as a possible match. Values over 2 can give you unpredictable results, especially for short names. The default value is 2.
|
48
|
+
* <code>GuessMethodOptions[:max_inspect_length]</code> is, for now, the longest an object's inspect value can be before it's not displayed in messages, and is replaced with simply the standard #<Object:0x142100c>. The default value is 25.
|
49
|
+
* <code>GuessMethodOptions[:active]</code> determines whether or not GuessMethod does its thing. If set to false (or nil) it'll step aside. Useful for when it gets in the way of something going off correctly (which happens sometimes).
|
50
50
|
|
51
51
|
h2. How to submit patches
|
52
52
|
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: guessmethod
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.0
|
7
|
-
date: 2007-09-
|
6
|
+
version: 0.1.0
|
7
|
+
date: 2007-09-23 00:00:00 -06:00
|
8
8
|
summary: an aggressive spell checker for irb
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -64,15 +64,6 @@ extensions: []
|
|
64
64
|
requirements: []
|
65
65
|
|
66
66
|
dependencies:
|
67
|
-
- !ruby/object:Gem::Dependency
|
68
|
-
name: highline
|
69
|
-
version_requirement:
|
70
|
-
version_requirements: !ruby/object:Gem::Version::Requirement
|
71
|
-
requirements:
|
72
|
-
- - ">="
|
73
|
-
- !ruby/object:Gem::Version
|
74
|
-
version: 1.2.7
|
75
|
-
version:
|
76
67
|
- !ruby/object:Gem::Dependency
|
77
68
|
name: rake
|
78
69
|
version_requirement:
|