maybeyoumeant 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
-