maybeyoumeant 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- gem 'rainbow', '~> 1.1.1'
3
+ gem 'paint', '~> 0.8.3'
4
4
 
5
5
  # Add dependencies to develop your gem here.
6
6
  # Include everything needed to run rake, tests, features, etc.
@@ -0,0 +1,9 @@
1
+ 0.3.0
2
+ - Working for Ruby 1.9
3
+ - Improved on Levenshtein space complexity
4
+ 0.2.0 Merged in janlelis changes:
5
+ - Rainbow replaced with Paint
6
+ - ask_user feature
7
+ - Fixes for Ruby 1.9
8
+ 0.1.0 Initial release. Broken for Ruby 1.9
9
+
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.0
@@ -1,44 +1,55 @@
1
1
  module MaybeYouMeant; end
2
2
 
3
3
  require 'rubygems'
4
- require 'rainbow'
4
+ require 'paint'
5
5
 
6
- require 'maybeyoumeant/matrix'
6
+ require 'maybeyoumeant/config'
7
7
  require 'maybeyoumeant/levenshtein'
8
8
  require 'maybeyoumeant/object_extensions'
9
9
  require 'maybeyoumeant/nil_logger'
10
10
  require 'maybeyoumeant/std_err_logger'
11
- require 'maybeyoumeant/config'
12
11
 
13
12
  module MaybeYouMeant
14
- @@logger = StdErrLogger.new
13
+ @logger = StdErrLogger.new
15
14
  def self.logger=(logger)
16
- @@logger = logger
15
+ @logger = logger
17
16
  end
18
17
 
18
+ # Logs a message to the current logger.
19
+ # The current logger is either STDOUT (be default), or a
20
+ # nil logger if debug is disabled.
19
21
  def self.log(msg = nil, &block)
20
- # msg ||= yield if block_given?
21
- @@logger.log(msg, &block)
22
+ @logger.log(msg, &block)
22
23
  end
23
24
 
24
-
25
- def self.tweak_history(method, nearby)
25
+ # Returns true if in an IRB session, false if not.
26
+ def self.irb_session?
26
27
  begin
27
- @@irb ||= Kernel.const_get('IRB') && Kernel.const_get('Readline') && Readline.const_defined?('HISTORY')
28
+ @irb ||= Kernel.const_get('IRB') && Kernel.const_get('Readline') && Readline.const_defined?('HISTORY')
28
29
  rescue NameError
29
- @@irb = false
30
+ @irb = false
30
31
  end
31
- return unless @@irb
32
+ return @irb
33
+ end
32
34
 
33
- line = Readline::HISTORY[-1]
35
+ # Updates IRB history to include the fixed command.
36
+ # For example if:
37
+ # 'hello'.ucase
38
+ # is executed, IRB history will be update with
39
+ # 'hello'.upcase
40
+ def self.tweak_history(method, nearby)
41
+ return unless irb_session? && !Readline::HISTORY.empty?
42
+
43
+ line = Readline::HISTORY[Readline::HISTORY.size - 1]
34
44
  Readline::HISTORY.pop if Config::remove_from_history
35
45
 
36
- if Config.add_to_history
37
- # Try to match .#{method}\W before replacing all occurences of method.
38
- line.gsub!(/(\W|^)#{method}((?=\W)|$)/, "\\1#{nearby}")
39
- log("Maybe you meant: #{line}".foreground(:black).bright)
40
- Readline::HISTORY.push line
41
- end
46
+ # Try to match .#{method}\W before replacing all occurrences of method.
47
+ line.gsub!(/(\W|^)#{method.to_s}((?=\W)|$)/, "\\1#{nearby.to_s}")
48
+ log((Paint["Maybe you meant: ", :red]) + line.to_s)
49
+
50
+ Readline::HISTORY.push line if Config.add_to_history
42
51
  end
52
+
53
+ MaybeYouMeant::ObjectExtentions.install_instance_methods
43
54
  end
44
55
 
@@ -15,19 +15,19 @@ module MaybeYouMeant::Config
15
15
  MaybeYouMeant::StdErrLogger === MaybeYouMeant.logger
16
16
  end
17
17
 
18
- @@call_nearby = true
18
+ @call_nearby = true
19
19
 
20
20
  # When true if a nearby method is found it is automatically called.
21
21
  # Defaults to true.
22
22
  def self.call_nearby=(enabled)
23
- @@call_nearby = enabled
23
+ @call_nearby = enabled
24
24
  end
25
25
 
26
26
  def self.call_nearby
27
- @@call_nearby
27
+ @call_nearby
28
28
  end
29
29
 
30
- @@add_to_history = true
30
+ @add_to_history = true
31
31
 
32
32
  # When true and a nearby method is called the history is manipulated to
33
33
  # have the nearby method name. Defaults to true.
@@ -36,24 +36,37 @@ module MaybeYouMeant::Config
36
36
  # Say object foo has a method 'foob' you will get the following in your history:
37
37
  # foo.foo -> foob.foob
38
38
  def self.add_to_history=(enabled)
39
- @@add_to_history = true
39
+ @add_to_history = true
40
40
  end
41
41
 
42
42
  def self.add_to_history
43
- @@add_to_history
43
+ @add_to_history
44
44
  end
45
45
 
46
- @@remove_from_history = false
46
+ @remove_from_history = false
47
47
 
48
48
  # When true and a nearby method is called the history is manipulated to
49
49
  # have the line with the incorrect method name removed.
50
50
  # Defaults to false.
51
51
  def self.remove_from_history(enabled)
52
- @@remove_from_history = enabled
52
+ @remove_from_history = enabled
53
53
  end
54
54
 
55
55
  def self.remove_from_history
56
- @@remove_from_history
56
+ @remove_from_history
57
+ end
58
+
59
+ @ask_user = false
60
+
61
+ # When true, the nearby method is not called directly, but the user
62
+ # can decide if he wants to call it
63
+ # Defaults to false
64
+ def self.ask_user=(enabled)
65
+ @ask_user = enabled
66
+ end
67
+
68
+ def self.ask_user
69
+ @ask_user
57
70
  end
58
71
 
59
72
  end
@@ -7,35 +7,43 @@ class MaybeYouMeant::Levenshtein
7
7
  # care about a threshold distance we only need to calculate
8
8
  # a diagonal instead of the full distance. This could be
9
9
  # further optimized to be evaluated lazily.
10
- def self.distance(s, t)
10
+ #
11
+ # If max is provided the return value is the Levenshtein distance if it
12
+ # is less than max, otherwise it is any value greater than or equal to
13
+ # max.
14
+ def self.distance(s, t, max = nil)
11
15
  m = s.length
12
16
  n = t.length
13
17
 
14
- d = ::Matrix.rows(Array.new(m + 1) { Array.new(n + 1, 0) }, false)
18
+ # If the string lengths differ by more than max return immediately.
19
+ return max if max && (m - n).abs >= max
15
20
 
16
- 0.upto m do |i|
17
- d[i, 0] = i
18
- end
21
+ cur = Array.new(n + 1, 0)
22
+ nxt = Array.new(n + 1, 0)
19
23
 
20
24
  0.upto n do |j|
21
- d[0, j] = j
25
+ cur[j] = j
22
26
  end
23
27
 
24
28
  1.upto m do |i|
29
+ nxt[0] = i
25
30
  1.upto n do |j|
26
31
  # This is not unicode safe.
27
32
  if s[i - 1] == t[j - 1]
28
- d[i, j] = d[i - 1, j - 1]
33
+ nxt[j] = cur[j - 1]
29
34
  else
30
- d[i, j] = [
31
- d[i - 1, j] + 1, # deletion
32
- d[i, j - 1] + 1, # insertion
33
- d[i - 1, j - 1] + 1 # substitution
35
+ nxt[j] = [
36
+ cur[j] + 1, #deletion
37
+ nxt[j - 1] + 1, #insertion
38
+ cur[j - 1] + 1, #substitution
34
39
  ].min
35
40
  end
36
41
  end
42
+ tmp = cur
43
+ cur = nxt
44
+ nxt = tmp
37
45
  end
38
46
 
39
- return d[m, n]
47
+ return cur[n]
40
48
  end
41
49
  end
@@ -1,17 +1,45 @@
1
1
  # Extends Object to call a method similar to the one called when the
2
2
  # method has not been defined on the object.
3
3
  module MaybeYouMeant::ObjectExtentions
4
+ # Not 100% sure what the problem is, but if you start mucking about
5
+ # with the following methods in Ruby 1.9 things go horrible wrong,
6
+ # so we just ignore them. They're likely to be correct anyway.
7
+ IGNORE_LIST = [
8
+ :to_str,
9
+ :to_int,
10
+ :to_ary,
11
+ :to_hash,
12
+ :to_a
13
+ ]
14
+
15
+ def self.user_confirmation(nearby)
16
+ Paint["Do you want to call ", :green] +
17
+ Paint[nearby, :green, :bright] +
18
+ Paint[" instead?", :green] +
19
+ " [Y,n]: "
20
+ end
4
21
 
5
22
  module InstanceMethods
6
23
  # Calls a nearby method if one is found. If no nearby method is
7
24
  # found the original method_missing is called, which raises a
8
25
  # NoMethodError.
9
26
  def method_missing(method, *args, &block)
27
+ # Don't handle methods on the ignore list.
28
+ return super if IGNORE_LIST.include?(method)
29
+
10
30
  nearby = nearby_method(method)
11
- # MaybeYouMeant.log { "Maybe you meant to call #{nearby}?" } if nearby
31
+
12
32
  return super unless MaybeYouMeant::Config.call_nearby && nearby
33
+
34
+ if MaybeYouMeant::Config.ask_user
35
+ print MaybeYouMeant::ObjectExtentions.user_confirmation(nearby)
36
+ choice = gets
37
+ return super if !choice || choice =~ /^n/i
38
+ end
39
+
13
40
  MaybeYouMeant.tweak_history(method, nearby)
14
- return send(nearby, *args, &block)
41
+
42
+ send(nearby, *args, &block)
15
43
  end
16
44
 
17
45
  # Returns the closest matching method to methods already defined on the object.
@@ -21,7 +49,7 @@ module MaybeYouMeant::ObjectExtentions
21
49
 
22
50
  distance = {}
23
51
  nearby_methods = self.methods.select do |method|
24
- d = MaybeYouMeant::Levenshtein.distance(name.to_s, method.to_s)
52
+ d = MaybeYouMeant::Levenshtein.distance(name.to_s, method.to_s, max_distance + 1)
25
53
  distance[method] = d if d <= max_distance
26
54
  d <= max_distance
27
55
  end
@@ -34,7 +62,9 @@ module MaybeYouMeant::ObjectExtentions
34
62
 
35
63
  end
36
64
 
37
- # Add the instance methods to the base object.
38
- Object.send(:include, InstanceMethods)
65
+ def self.install_instance_methods
66
+ # Add the instance methods to the base object.
67
+ Object.send(:include, InstanceMethods)
68
+ end
39
69
  end
40
70
 
@@ -0,0 +1,82 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{maybeyoumeant}
8
+ s.version = "0.3.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Liehann Loots"]
12
+ s.date = %q{2011-07-18}
13
+ s.description = %q{
14
+ If you misspell a method in IRB this plugin searches through methods
15
+ defined on the object and calls the closest method to the one you entered.
16
+ For example lets say you typed:
17
+ 'hello world'.capitalze
18
+ Instead of raising a NoMethodError 'hello world'.capitalize would automatically
19
+ be called.
20
+ }
21
+ s.email = %q{liehannl@gmail.com}
22
+ s.extra_rdoc_files = [
23
+ "LICENSE.txt",
24
+ "README.rdoc"
25
+ ]
26
+ s.files = [
27
+ ".document",
28
+ "Gemfile",
29
+ "HISTORY.txt",
30
+ "LICENSE.txt",
31
+ "README.rdoc",
32
+ "Rakefile",
33
+ "VERSION",
34
+ "lib/maybeyoumeant.rb",
35
+ "lib/maybeyoumeant/config.rb",
36
+ "lib/maybeyoumeant/levenshtein.rb",
37
+ "lib/maybeyoumeant/nil_logger.rb",
38
+ "lib/maybeyoumeant/object_extensions.rb",
39
+ "lib/maybeyoumeant/std_err_logger.rb",
40
+ "maybeyoumeant.gemspec",
41
+ "spec/.helper.rb.swo",
42
+ "spec/helper.rb",
43
+ "spec/lib/foo.rb",
44
+ "spec/maybeyoumeant/.matrix_spec.rb.swo",
45
+ "spec/maybeyoumeant/levenshtein_spec.rb",
46
+ "spec/maybeyoumeant/object_extensions_spec.rb"
47
+ ]
48
+ s.homepage = %q{http://github.com/liehann/maybeyoumeant}
49
+ s.licenses = ["MIT"]
50
+ s.require_paths = ["lib"]
51
+ s.rubygems_version = %q{1.3.7}
52
+ s.summary = %q{IRB plugin that suggests corrections for misspelled method names.}
53
+
54
+ if s.respond_to? :specification_version then
55
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
56
+ s.specification_version = 3
57
+
58
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
59
+ s.add_runtime_dependency(%q<paint>, ["~> 0.8.3"])
60
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
61
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
62
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
63
+ s.add_development_dependency(%q<rcov>, [">= 0"])
64
+ s.add_development_dependency(%q<rspec>, ["~> 1.3.2"])
65
+ else
66
+ s.add_dependency(%q<paint>, ["~> 0.8.3"])
67
+ s.add_dependency(%q<shoulda>, [">= 0"])
68
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
69
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
70
+ s.add_dependency(%q<rcov>, [">= 0"])
71
+ s.add_dependency(%q<rspec>, ["~> 1.3.2"])
72
+ end
73
+ else
74
+ s.add_dependency(%q<paint>, ["~> 0.8.3"])
75
+ s.add_dependency(%q<shoulda>, [">= 0"])
76
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
77
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
78
+ s.add_dependency(%q<rcov>, [">= 0"])
79
+ s.add_dependency(%q<rspec>, ["~> 1.3.2"])
80
+ end
81
+ end
82
+
@@ -12,5 +12,9 @@ describe Levenshtein do
12
12
  it "calculates a correct distance between two strings" do
13
13
  Levenshtein.distance('kitten', 'sitting').should == 3
14
14
  end
15
+
16
+ it "calculates correct distance between match and to_path" do
17
+ d = MaybeYouMeant::Levenshtein.distance(:to_path.to_s, :match.to_s, 3).should >= 3
18
+ end
15
19
  end
16
20
 
@@ -2,11 +2,11 @@ require 'helper'
2
2
 
3
3
  describe ObjectExtentions do
4
4
  it 'finds a nearby method' do
5
- Foo.new.nearby_method(:boo).should == 'foo'
5
+ Foo.new.nearby_method(:boo).to_s.should == 'foo'
6
6
  end
7
7
 
8
8
  it 'has a threshold of 2' do
9
- Foo.new.nearby_method(:foobr).should == 'foo'
9
+ Foo.new.nearby_method(:foobr).to_s.should == 'foo'
10
10
  end
11
11
 
12
12
  it 'returns nil if there are no nearby methods' do
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: maybeyoumeant
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 19
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 2
8
+ - 3
9
9
  - 0
10
- version: 0.2.0
10
+ version: 0.3.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Liehann Loots
@@ -19,26 +19,23 @@ date: 2011-07-18 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
- type: :runtime
23
- prerelease: false
24
- name: rainbow
25
- version_requirements: &id001 !ruby/object:Gem::Requirement
22
+ requirement: &id001 !ruby/object:Gem::Requirement
26
23
  none: false
27
24
  requirements:
28
25
  - - ~>
29
26
  - !ruby/object:Gem::Version
30
- hash: 17
27
+ hash: 57
31
28
  segments:
32
- - 1
33
- - 1
34
- - 1
35
- version: 1.1.1
36
- requirement: *id001
37
- - !ruby/object:Gem::Dependency
38
- type: :development
29
+ - 0
30
+ - 8
31
+ - 3
32
+ version: 0.8.3
33
+ type: :runtime
34
+ name: paint
39
35
  prerelease: false
40
- name: shoulda
41
- version_requirements: &id002 !ruby/object:Gem::Requirement
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ requirement: &id002 !ruby/object:Gem::Requirement
42
39
  none: false
43
40
  requirements:
44
41
  - - ">="
@@ -47,12 +44,12 @@ dependencies:
47
44
  segments:
48
45
  - 0
49
46
  version: "0"
50
- requirement: *id002
51
- - !ruby/object:Gem::Dependency
52
47
  type: :development
48
+ name: shoulda
53
49
  prerelease: false
54
- name: bundler
55
- version_requirements: &id003 !ruby/object:Gem::Requirement
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ requirement: &id003 !ruby/object:Gem::Requirement
56
53
  none: false
57
54
  requirements:
58
55
  - - ~>
@@ -63,12 +60,12 @@ dependencies:
63
60
  - 0
64
61
  - 0
65
62
  version: 1.0.0
66
- requirement: *id003
67
- - !ruby/object:Gem::Dependency
68
63
  type: :development
64
+ name: bundler
69
65
  prerelease: false
70
- name: jeweler
71
- version_requirements: &id004 !ruby/object:Gem::Requirement
66
+ version_requirements: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ requirement: &id004 !ruby/object:Gem::Requirement
72
69
  none: false
73
70
  requirements:
74
71
  - - ~>
@@ -79,12 +76,12 @@ dependencies:
79
76
  - 6
80
77
  - 4
81
78
  version: 1.6.4
82
- requirement: *id004
83
- - !ruby/object:Gem::Dependency
84
79
  type: :development
80
+ name: jeweler
85
81
  prerelease: false
86
- name: rcov
87
- version_requirements: &id005 !ruby/object:Gem::Requirement
82
+ version_requirements: *id004
83
+ - !ruby/object:Gem::Dependency
84
+ requirement: &id005 !ruby/object:Gem::Requirement
88
85
  none: false
89
86
  requirements:
90
87
  - - ">="
@@ -93,12 +90,12 @@ dependencies:
93
90
  segments:
94
91
  - 0
95
92
  version: "0"
96
- requirement: *id005
97
- - !ruby/object:Gem::Dependency
98
93
  type: :development
94
+ name: rcov
99
95
  prerelease: false
100
- name: rspec
101
- version_requirements: &id006 !ruby/object:Gem::Requirement
96
+ version_requirements: *id005
97
+ - !ruby/object:Gem::Dependency
98
+ requirement: &id006 !ruby/object:Gem::Requirement
102
99
  none: false
103
100
  requirements:
104
101
  - - ~>
@@ -109,7 +106,10 @@ dependencies:
109
106
  - 3
110
107
  - 2
111
108
  version: 1.3.2
112
- requirement: *id006
109
+ type: :development
110
+ name: rspec
111
+ prerelease: false
112
+ version_requirements: *id006
113
113
  description: "\n If you misspell a method in IRB this plugin searches through methods\n defined on the object and calls the closest method to the one you entered.\n For example lets say you typed:\n 'hello world'.capitalze\n Instead of raising a NoMethodError 'hello world'.capitalize would automatically\n be called.\n "
114
114
  email: liehannl@gmail.com
115
115
  executables: []
@@ -122,6 +122,7 @@ extra_rdoc_files:
122
122
  files:
123
123
  - .document
124
124
  - Gemfile
125
+ - HISTORY.txt
125
126
  - LICENSE.txt
126
127
  - README.rdoc
127
128
  - Rakefile
@@ -129,16 +130,15 @@ files:
129
130
  - lib/maybeyoumeant.rb
130
131
  - lib/maybeyoumeant/config.rb
131
132
  - lib/maybeyoumeant/levenshtein.rb
132
- - lib/maybeyoumeant/matrix.rb
133
133
  - lib/maybeyoumeant/nil_logger.rb
134
134
  - lib/maybeyoumeant/object_extensions.rb
135
135
  - lib/maybeyoumeant/std_err_logger.rb
136
+ - maybeyoumeant.gemspec
136
137
  - spec/.helper.rb.swo
137
138
  - spec/helper.rb
138
139
  - spec/lib/foo.rb
139
140
  - spec/maybeyoumeant/.matrix_spec.rb.swo
140
141
  - spec/maybeyoumeant/levenshtein_spec.rb
141
- - spec/maybeyoumeant/matrix_spec.rb
142
142
  - spec/maybeyoumeant/object_extensions_spec.rb
143
143
  has_rdoc: true
144
144
  homepage: http://github.com/liehann/maybeyoumeant
@@ -1,15 +0,0 @@
1
- require 'matrix'
2
-
3
- class MaybeYouMeant::Matrix
4
-
5
- module InstanceMethods
6
- def []=(i, j, v)
7
- @rows[i][j] = v
8
- end
9
- end
10
-
11
- # Add matrix methods if this is ruby 1.8 and they're not present.
12
- unless ::Matrix.instance_methods.include?(:[]=)
13
- ::Matrix.send(:include, InstanceMethods)
14
- end
15
- end
@@ -1,14 +0,0 @@
1
- require 'helper'
2
-
3
- describe Matrix do
4
- it "adds an index setter to ::Matrix" do
5
- ::Matrix.instance_methods.should include '[]='
6
- end
7
-
8
- it "should set values in a ::Matrix" do
9
- m = ::Matrix[[0, 0, 0], [0, 0, 0]]
10
- m[1, 2] = 3
11
- m[1, 2].should == 3
12
- end
13
- end
14
-