did_you_mean 1.0.1 → 1.0.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -1
- data/README.md +5 -5
- data/Rakefile +5 -5
- data/benchmark/memory_usage.rb +1 -18
- data/evaluation/calculator.rb +3 -22
- data/lib/did_you_mean.rb +1 -1
- data/lib/did_you_mean/experimental.rb +17 -0
- data/lib/did_you_mean/{extra_features → experimental}/initializer_name_correction.rb +1 -1
- data/lib/did_you_mean/{extra_features → experimental}/ivar_name_correction.rb +7 -3
- data/lib/did_you_mean/experimental/key_error_name_correction.rb +32 -0
- data/lib/did_you_mean/extra_features.rb +2 -15
- data/lib/did_you_mean/spell_checker.rb +54 -0
- data/lib/did_you_mean/spell_checkers/method_name_checker.rb +2 -3
- data/lib/did_you_mean/spell_checkers/name_error_checkers/class_name_checker.rb +2 -7
- data/lib/did_you_mean/spell_checkers/name_error_checkers/variable_name_checker.rb +4 -3
- data/lib/did_you_mean/version.rb +1 -1
- data/test/experimental/deprecated_features_test.rb +13 -0
- data/test/{extra_features → experimental}/initializer_name_correction_test.rb +0 -0
- data/test/experimental/key_error_test.rb +15 -0
- data/test/{extra_features → experimental}/method_name_checker_test.rb +1 -1
- data/test/spell_checker_test.rb +8 -16
- data/test/{correctable → spell_checking}/class_name_test.rb +0 -0
- data/test/{correctable → spell_checking}/method_name_test.rb +0 -0
- data/test/{correctable → spell_checking}/uncorrectable_name_test.rb +0 -0
- data/test/{correctable → spell_checking}/variable_name_test.rb +0 -0
- data/test/verbose_formatter_test.rb +1 -1
- metadata +23 -17
- data/lib/did_you_mean/spell_checkable.rb +0 -56
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28e1952e8b23b15341dd32e2b069ff5a1095c214
|
4
|
+
data.tar.gz: ab42a54b71d2ea36821f135af2182dbc42671abf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d91287f29b78c81341da7c6154272f25f8d9ca28b1d71599079746f24182830d1833493a270705fa3bdc20e003fb1566307772974b88fc6c7b904a7fe3b7a923
|
7
|
+
data.tar.gz: 36a5296b2b247ff3a8791623108e3518571f2d8ad4864bc3eddfb9e17cb648726ba7af9ab4f5dc26d1ad5b4fc47e66044a41e62e066ef4d68727fb64ad8bec59
|
data/CHANGELOG.md
CHANGED
@@ -5,7 +5,7 @@ _<sup>released on 2015-12-25 05:13:04 UTC</sup>_
|
|
5
5
|
#### Features
|
6
6
|
|
7
7
|
- Introduced a [verbose formatter](https://github.com/yuki24/did_you_mean#verbose-formatter)
|
8
|
-
- Introduced an easy way to enabling [
|
8
|
+
- Introduced an easy way to enabling [experimental features](https://github.com/yuki24/did_you_mean#experimental-features)
|
9
9
|
|
10
10
|
#### Bug Fixes
|
11
11
|
|
data/README.md
CHANGED
@@ -52,16 +52,16 @@ full_name.starts_with?("Y")
|
|
52
52
|
# Did you mean? start_with?
|
53
53
|
```
|
54
54
|
|
55
|
-
##
|
55
|
+
## Experimental Features
|
56
56
|
|
57
|
-
Aside from the basic features above, the `did_you_mean` gem comes with
|
57
|
+
Aside from the basic features above, the `did_you_mean` gem comes with experimental features. They can be enabled by calling `require 'did_you_mean/experimental'`.
|
58
58
|
|
59
|
-
**Keep in mind that these
|
59
|
+
**Keep in mind that these experimental features should never be enabled in production as they would impact Ruby's performance and uses an unstable Ruby API.**
|
60
60
|
|
61
61
|
### Correcting an Instance Variable When It's Incorrectly Typed
|
62
62
|
|
63
63
|
```ruby
|
64
|
-
require 'did_you_mean/
|
64
|
+
require 'did_you_mean/experimental'
|
65
65
|
|
66
66
|
@full_name = "Yuki Nishijima"
|
67
67
|
@full_anme.split(" ")
|
@@ -71,7 +71,7 @@ require 'did_you_mean/extra_features'
|
|
71
71
|
|
72
72
|
### Displaying a Warning When `initialize` is Incorrectly Typed
|
73
73
|
```ruby
|
74
|
-
require 'did_you_mean/
|
74
|
+
require 'did_you_mean/experimental'
|
75
75
|
|
76
76
|
class Person
|
77
77
|
def intialize
|
data/Rakefile
CHANGED
@@ -5,7 +5,7 @@ Rake::TestTask.new do |task|
|
|
5
5
|
task.libs << "test"
|
6
6
|
|
7
7
|
task.test_files = Dir['test/**/*_test.rb'].reject do |path|
|
8
|
-
/(verbose_formatter|
|
8
|
+
/(verbose_formatter|experimental)/ =~ path
|
9
9
|
end
|
10
10
|
|
11
11
|
task.verbose = true
|
@@ -20,16 +20,16 @@ Rake::TestTask.new("test:verbose_formatter") do |task|
|
|
20
20
|
task.ruby_opts << "-rdid_you_mean/verbose_formatter"
|
21
21
|
end
|
22
22
|
|
23
|
-
Rake::TestTask.new("test:
|
23
|
+
Rake::TestTask.new("test:experimental") do |task|
|
24
24
|
task.libs << "test"
|
25
|
-
task.pattern = 'test/
|
25
|
+
task.pattern = 'test/experimental/**/*_test.rb'
|
26
26
|
task.verbose = true
|
27
27
|
task.warning = true
|
28
|
-
task.ruby_opts << "-rdid_you_mean/
|
28
|
+
task.ruby_opts << "-rdid_you_mean/experimental"
|
29
29
|
end
|
30
30
|
|
31
31
|
if RUBY_ENGINE != 'jruby'
|
32
|
-
task default: %i(test test:verbose_formatter test:
|
32
|
+
task default: %i(test test:verbose_formatter test:experimental)
|
33
33
|
else
|
34
34
|
task default: %i(test test:verbose_formatter)
|
35
35
|
end
|
data/benchmark/memory_usage.rb
CHANGED
@@ -7,26 +7,9 @@ require 'did_you_mean'
|
|
7
7
|
# error = (self.fooo rescue $!)
|
8
8
|
# executable = -> { error.to_s }
|
9
9
|
|
10
|
-
class SpellChecker
|
11
|
-
include DidYouMean::SpellCheckable
|
12
|
-
|
13
|
-
def initialize(words)
|
14
|
-
@words = words
|
15
|
-
end
|
16
|
-
|
17
|
-
def correct(input)
|
18
|
-
@corrections, @input = nil, input
|
19
|
-
corrections
|
20
|
-
end
|
21
|
-
|
22
|
-
def candidates
|
23
|
-
{ @input => @words }
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
10
|
METHODS = ''.methods
|
28
11
|
INPUT = 'start_with?'
|
29
|
-
collection = SpellChecker.new(METHODS)
|
12
|
+
collection = DidYouMean::SpellChecker.new(dictionary: METHODS)
|
30
13
|
executable = proc { collection.correct(INPUT) }
|
31
14
|
|
32
15
|
GC.disable
|
data/evaluation/calculator.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# -*- frozen-string-literal: true -*-
|
2
2
|
|
3
3
|
require 'benchmark'
|
4
|
+
require 'did_you_mean'
|
4
5
|
|
5
6
|
def report(message, &block)
|
6
7
|
time = 1000 * Benchmark.realtime(&block)
|
@@ -21,7 +22,7 @@ def report(message, &block)
|
|
21
22
|
time
|
22
23
|
end
|
23
24
|
|
24
|
-
puts "\n"
|
25
|
+
puts "did_you_mean version: #{DidYouMean::VERSION}\n\n"
|
25
26
|
|
26
27
|
report "loading program" do
|
27
28
|
require 'yaml'
|
@@ -37,25 +38,6 @@ report "loading program" do
|
|
37
38
|
end
|
38
39
|
rescue LoadError, NameError
|
39
40
|
end
|
40
|
-
|
41
|
-
class SpellChecker
|
42
|
-
include DidYouMean::SpellCheckable
|
43
|
-
|
44
|
-
def initialize(words)
|
45
|
-
@words = words
|
46
|
-
end
|
47
|
-
|
48
|
-
def correct(input)
|
49
|
-
@corrections, @input = nil, input
|
50
|
-
corrections
|
51
|
-
end
|
52
|
-
|
53
|
-
def candidates
|
54
|
-
{ @input => @words }
|
55
|
-
end
|
56
|
-
|
57
|
-
private def normalize(str); str; end
|
58
|
-
end
|
59
41
|
end
|
60
42
|
|
61
43
|
report "loading dictionary" do
|
@@ -66,7 +48,7 @@ report "loading dictionary" do
|
|
66
48
|
end
|
67
49
|
|
68
50
|
report "loading corrent/incorrect words" do
|
69
|
-
SPELL_CHECKER = SpellChecker.new(DICTIONARY)
|
51
|
+
SPELL_CHECKER = DidYouMean::SpellChecker.new(dictionary: DICTIONARY)
|
70
52
|
INCORRECT_WORDS = YAML.load(open("evaluation/incorrect_words.yaml").read)
|
71
53
|
end
|
72
54
|
|
@@ -78,7 +60,6 @@ filename = "log/words_not_corrected_#{Time.now.to_i}.yml"
|
|
78
60
|
puts <<-MSG
|
79
61
|
|
80
62
|
Total number of test data: #{INCORRECT_WORDS.size}
|
81
|
-
did_you_mean version: #{DidYouMean::VERSION}
|
82
63
|
|
83
64
|
MSG
|
84
65
|
|
data/lib/did_you_mean.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require "did_you_mean/version"
|
2
2
|
require "did_you_mean/core_ext/name_error"
|
3
3
|
|
4
|
-
require "did_you_mean/
|
4
|
+
require "did_you_mean/spell_checker"
|
5
5
|
require 'did_you_mean/spell_checkers/name_error_checkers'
|
6
6
|
require 'did_you_mean/spell_checkers/method_name_checker'
|
7
7
|
require 'did_you_mean/spell_checkers/null_checker'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'did_you_mean'
|
2
|
+
|
3
|
+
module DidYouMean
|
4
|
+
TRACE = TracePoint.trace(:raise) do |tp|
|
5
|
+
e = tp.raised_exception
|
6
|
+
|
7
|
+
if SPELL_CHECKERS.include?(e.class.to_s) && !e.instance_variable_defined?(:@frame_binding)
|
8
|
+
e.instance_variable_set(:@frame_binding, tp.binding)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
NameError.send(:attr, :frame_binding)
|
13
|
+
end
|
14
|
+
|
15
|
+
require 'did_you_mean/experimental/initializer_name_correction'
|
16
|
+
require 'did_you_mean/experimental/ivar_name_correction'
|
17
|
+
require 'did_you_mean/experimental/key_error_name_correction'
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module DidYouMean
|
2
|
-
module
|
2
|
+
module Experimental
|
3
3
|
module IvarNameCorrection
|
4
4
|
REPLS = {
|
5
5
|
"(irb)" => -> { Readline::HISTORY.to_a.last }
|
@@ -12,8 +12,12 @@ module DidYouMean
|
|
12
12
|
@ivar_names = no_method_error.frame_binding.receiver.instance_variables
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
16
|
-
super
|
15
|
+
def corrections
|
16
|
+
super + ivar_name_corrections
|
17
|
+
end
|
18
|
+
|
19
|
+
def ivar_name_corrections
|
20
|
+
@ivar_name_corrections ||= SpellChecker.new(dictionary: @ivar_names).correct(receiver_name.to_s)
|
17
21
|
end
|
18
22
|
|
19
23
|
private
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module DidYouMean
|
2
|
+
module Experimental
|
3
|
+
module KeyErrorWithNameAndKeys
|
4
|
+
FILE_REGEXP = %r"#{Regexp.quote(__FILE__)}"
|
5
|
+
|
6
|
+
def fetch(name, *)
|
7
|
+
super
|
8
|
+
rescue KeyError => e
|
9
|
+
e.instance_variable_set(:@name, name)
|
10
|
+
e.instance_variable_set(:@keys, keys)
|
11
|
+
$@.delete_if { |s| FILE_REGEXP =~ s } if $@
|
12
|
+
|
13
|
+
raise e
|
14
|
+
end
|
15
|
+
end
|
16
|
+
Hash.prepend KeyErrorWithNameAndKeys
|
17
|
+
|
18
|
+
class KeyNameChecker
|
19
|
+
def initialize(key_error)
|
20
|
+
@name = key_error.instance_variable_get(:@name)
|
21
|
+
@keys = key_error.instance_variable_get(:@keys)
|
22
|
+
end
|
23
|
+
|
24
|
+
def corrections
|
25
|
+
@corrections ||= SpellChecker.new(dictionary: @keys).correct(@name).map(&:inspect)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
SPELL_CHECKERS["KeyError"] = KeyNameChecker
|
30
|
+
KeyError.prepend DidYouMean::Correctable
|
31
|
+
end
|
32
|
+
end
|
@@ -1,16 +1,3 @@
|
|
1
|
-
require 'did_you_mean'
|
1
|
+
warn "The file 'did_you_mean/extra_features.rb' has been moved to 'did_you_mean/experimental.rb'. Please `require 'did_you_mean/experimental'` instead."
|
2
2
|
|
3
|
-
|
4
|
-
TRACE = TracePoint.trace(:raise) do |tp|
|
5
|
-
e = tp.raised_exception
|
6
|
-
|
7
|
-
if SPELL_CHECKERS.include?(e.class.to_s) && !e.instance_variable_defined?(:@frame_binding)
|
8
|
-
e.instance_variable_set(:@frame_binding, tp.binding)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
NameError.send(:attr, :frame_binding)
|
13
|
-
end
|
14
|
-
|
15
|
-
require 'did_you_mean/extra_features/initializer_name_correction'
|
16
|
-
require 'did_you_mean/extra_features/ivar_name_correction'
|
3
|
+
require 'did_you_mean/experimental'
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# -*- frozen-string-literal: true -*-
|
2
|
+
|
3
|
+
require "did_you_mean/levenshtein"
|
4
|
+
require "did_you_mean/jaro_winkler"
|
5
|
+
|
6
|
+
module DidYouMean
|
7
|
+
class SpellChecker
|
8
|
+
def initialize(dictionary: )
|
9
|
+
@dictionary = dictionary
|
10
|
+
end
|
11
|
+
|
12
|
+
def correct(input)
|
13
|
+
input = normalize(input)
|
14
|
+
threshold = input.length > 3 ? 0.834 : 0.77
|
15
|
+
|
16
|
+
seed = @dictionary.select {|candidate| JaroWinkler.distance(normalize(candidate), input) >= threshold }
|
17
|
+
seed.reject! {|candidate| input == candidate.to_s }
|
18
|
+
seed.sort_by! {|candidate| JaroWinkler.distance(candidate.to_s, input) }
|
19
|
+
seed.reverse!
|
20
|
+
|
21
|
+
# Correct mistypes
|
22
|
+
threshold = (input.length * 0.25).ceil
|
23
|
+
has_mistype = seed.rindex {|c| Levenshtein.distance(normalize(c), input) <= threshold }
|
24
|
+
|
25
|
+
corrections = if has_mistype
|
26
|
+
seed.take(has_mistype + 1)
|
27
|
+
else
|
28
|
+
# Correct misspells
|
29
|
+
seed.select do |candidate|
|
30
|
+
candidate = normalize(candidate)
|
31
|
+
length = input.length < candidate.length ? input.length : candidate.length
|
32
|
+
|
33
|
+
Levenshtein.distance(candidate, input) < length
|
34
|
+
end.first(1)
|
35
|
+
end
|
36
|
+
|
37
|
+
corrections
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def normalize(str_or_symbol) #:nodoc:
|
43
|
+
str = if str_or_symbol.is_a?(String)
|
44
|
+
str_or_symbol.dup
|
45
|
+
else
|
46
|
+
str_or_symbol.to_s
|
47
|
+
end
|
48
|
+
|
49
|
+
str.downcase!
|
50
|
+
str.tr!("@", "")
|
51
|
+
str
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module DidYouMean
|
2
2
|
class MethodNameChecker
|
3
|
-
include SpellCheckable
|
4
3
|
attr_reader :method_name, :receiver
|
5
4
|
|
6
5
|
def initialize(exception)
|
@@ -9,8 +8,8 @@ module DidYouMean
|
|
9
8
|
@has_args = !exception.args&.empty?
|
10
9
|
end
|
11
10
|
|
12
|
-
def
|
13
|
-
|
11
|
+
def corrections
|
12
|
+
@corrections ||= SpellChecker.new(dictionary: method_names).correct(method_name)
|
14
13
|
end
|
15
14
|
|
16
15
|
def method_names
|
@@ -3,15 +3,14 @@ require 'delegate'
|
|
3
3
|
|
4
4
|
module DidYouMean
|
5
5
|
class ClassNameChecker
|
6
|
-
include SpellCheckable
|
7
6
|
attr_reader :class_name
|
8
7
|
|
9
8
|
def initialize(exception)
|
10
9
|
@class_name, @receiver = exception.name, exception.receiver
|
11
10
|
end
|
12
11
|
|
13
|
-
def
|
14
|
-
|
12
|
+
def corrections
|
13
|
+
@corrections ||= SpellChecker.new(dictionary: class_names).correct(class_name).map(&:full_name)
|
15
14
|
end
|
16
15
|
|
17
16
|
def class_names
|
@@ -22,10 +21,6 @@ module DidYouMean
|
|
22
21
|
end
|
23
22
|
end
|
24
23
|
|
25
|
-
def corrections
|
26
|
-
super.map(&:full_name)
|
27
|
-
end
|
28
|
-
|
29
24
|
def scopes
|
30
25
|
@scopes ||= @receiver.to_s.split("::").inject([Object]) do |_scopes, scope|
|
31
26
|
_scopes << _scopes.last.const_get(scope)
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
module DidYouMean
|
4
4
|
class VariableNameChecker
|
5
|
-
include SpellCheckable
|
6
5
|
attr_reader :name, :method_names, :lvar_names, :ivar_names, :cvar_names
|
7
6
|
|
8
7
|
def initialize(exception)
|
@@ -16,8 +15,10 @@ module DidYouMean
|
|
16
15
|
@cvar_names += receiver.class_variables if receiver.kind_of?(Module)
|
17
16
|
end
|
18
17
|
|
19
|
-
def
|
20
|
-
|
18
|
+
def corrections
|
19
|
+
@corrections ||= SpellChecker
|
20
|
+
.new(dictionary: (lvar_names + method_names + ivar_names + cvar_names))
|
21
|
+
.correct(name)
|
21
22
|
end
|
22
23
|
end
|
23
24
|
end
|
data/lib/did_you_mean/version.rb
CHANGED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class DeprecatedExtraFeaturesTest < Minitest::Test
|
4
|
+
def test_message
|
5
|
+
message = "The file 'did_you_mean/extra_features.rb' has been moved to " \
|
6
|
+
"'did_you_mean/experimental.rb'. Please `require 'did_you_mean/experimental'` " \
|
7
|
+
"instead.\n"
|
8
|
+
|
9
|
+
assert_output nil, message do
|
10
|
+
require 'did_you_mean/extra_features'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
File without changes
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class ExperimentalKeyErrorNameCorrectionTest < Minitest::Test
|
4
|
+
def test_corrects_hash_key_name
|
5
|
+
hash = { "foo" => 1, bar: 2 }
|
6
|
+
|
7
|
+
error = assert_raises(KeyError) { hash.fetch(:bax) }
|
8
|
+
assert_correction ":bar", error.corrections
|
9
|
+
assert_match "Did you mean? :bar", error.to_s
|
10
|
+
|
11
|
+
error = assert_raises(KeyError) { hash.fetch("fooo") }
|
12
|
+
assert_correction %("foo"), error.corrections
|
13
|
+
assert_match %(Did you mean? "foo"), error.to_s
|
14
|
+
end
|
15
|
+
end
|
data/test/spell_checker_test.rb
CHANGED
@@ -1,14 +1,6 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class SpellCheckerTest < Minitest::Test
|
4
|
-
SpellChecker = Struct.new(:input, :words) do
|
5
|
-
include DidYouMean::SpellCheckable
|
6
|
-
|
7
|
-
def candidates
|
8
|
-
{ input => words }
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
4
|
def test_spell_checker_corrects_mistypes
|
13
5
|
assert_spell 'foo', input: 'doo', dictionary: ['foo', 'fork']
|
14
6
|
assert_spell 'email', input: 'meail', dictionary: ['email', 'fail', 'eval']
|
@@ -43,8 +35,8 @@ class SpellCheckerTest < Minitest::Test
|
|
43
35
|
names = %w(first_name_change first_name_changed? first_name_will_change!)
|
44
36
|
assert_spell names, input: 'first_name_change!', dictionary: names
|
45
37
|
|
46
|
-
assert_empty SpellChecker.new(
|
47
|
-
assert_empty SpellChecker.new(
|
38
|
+
assert_empty DidYouMean::SpellChecker.new(dictionary: ['proc']).correct('product_path')
|
39
|
+
assert_empty DidYouMean::SpellChecker.new(dictionary: ['fork']).correct('fooo')
|
48
40
|
end
|
49
41
|
|
50
42
|
def test_spell_checker_corrects_misspells
|
@@ -60,27 +52,27 @@ class SpellCheckerTest < Minitest::Test
|
|
60
52
|
name123
|
61
53
|
)
|
62
54
|
|
63
|
-
actual = SpellChecker.new(
|
55
|
+
actual = DidYouMean::SpellChecker.new(dictionary: %w(
|
64
56
|
name12
|
65
57
|
name123
|
66
58
|
name1234
|
67
59
|
name12345
|
68
60
|
name123456
|
69
|
-
)).
|
61
|
+
)).correct('name123456')
|
70
62
|
|
71
63
|
assert_equal expected, actual
|
72
64
|
end
|
73
65
|
|
74
66
|
def test_spell_checker_excludes_input_from_dictionary
|
75
|
-
assert_empty SpellChecker.new(
|
76
|
-
assert_empty SpellChecker.new(
|
77
|
-
assert_empty SpellChecker.new(:
|
67
|
+
assert_empty DidYouMean::SpellChecker.new(dictionary: ['input']).correct('input')
|
68
|
+
assert_empty DidYouMean::SpellChecker.new(dictionary: [:input]).correct('input')
|
69
|
+
assert_empty DidYouMean::SpellChecker.new(dictionary: ['input']).correct(:input)
|
78
70
|
end
|
79
71
|
|
80
72
|
private
|
81
73
|
|
82
74
|
def assert_spell(expected, input: , dictionary: )
|
83
|
-
corrections = SpellChecker.new(
|
75
|
+
corrections = DidYouMean::SpellChecker.new(dictionary: dictionary).correct(input)
|
84
76
|
assert_equal Array(expected), corrections, "Expected to suggest #{expected}, but got #{corrections.inspect}"
|
85
77
|
end
|
86
78
|
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: did_you_mean
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yuki Nishijima
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-06-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -80,13 +80,15 @@ files:
|
|
80
80
|
- evaluation/incorrect_words.yaml
|
81
81
|
- lib/did_you_mean.rb
|
82
82
|
- lib/did_you_mean/core_ext/name_error.rb
|
83
|
+
- lib/did_you_mean/experimental.rb
|
84
|
+
- lib/did_you_mean/experimental/initializer_name_correction.rb
|
85
|
+
- lib/did_you_mean/experimental/ivar_name_correction.rb
|
86
|
+
- lib/did_you_mean/experimental/key_error_name_correction.rb
|
83
87
|
- lib/did_you_mean/extra_features.rb
|
84
|
-
- lib/did_you_mean/extra_features/initializer_name_correction.rb
|
85
|
-
- lib/did_you_mean/extra_features/ivar_name_correction.rb
|
86
88
|
- lib/did_you_mean/formatter.rb
|
87
89
|
- lib/did_you_mean/jaro_winkler.rb
|
88
90
|
- lib/did_you_mean/levenshtein.rb
|
89
|
-
- lib/did_you_mean/
|
91
|
+
- lib/did_you_mean/spell_checker.rb
|
90
92
|
- lib/did_you_mean/spell_checkers/method_name_checker.rb
|
91
93
|
- lib/did_you_mean/spell_checkers/name_error_checkers.rb
|
92
94
|
- lib/did_you_mean/spell_checkers/name_error_checkers/class_name_checker.rb
|
@@ -95,14 +97,16 @@ files:
|
|
95
97
|
- lib/did_you_mean/verbose_formatter.rb
|
96
98
|
- lib/did_you_mean/version.rb
|
97
99
|
- test/core_ext/name_error_extension_test.rb
|
98
|
-
- test/correctable/class_name_test.rb
|
99
|
-
- test/correctable/method_name_test.rb
|
100
|
-
- test/correctable/uncorrectable_name_test.rb
|
101
|
-
- test/correctable/variable_name_test.rb
|
102
100
|
- test/edit_distance/jaro_winkler_test.rb
|
103
|
-
- test/
|
104
|
-
- test/
|
101
|
+
- test/experimental/deprecated_features_test.rb
|
102
|
+
- test/experimental/initializer_name_correction_test.rb
|
103
|
+
- test/experimental/key_error_test.rb
|
104
|
+
- test/experimental/method_name_checker_test.rb
|
105
105
|
- test/spell_checker_test.rb
|
106
|
+
- test/spell_checking/class_name_test.rb
|
107
|
+
- test/spell_checking/method_name_test.rb
|
108
|
+
- test/spell_checking/uncorrectable_name_test.rb
|
109
|
+
- test/spell_checking/variable_name_test.rb
|
106
110
|
- test/test_helper.rb
|
107
111
|
- test/verbose_formatter_test.rb
|
108
112
|
homepage: https://github.com/yuki24/did_you_mean
|
@@ -131,13 +135,15 @@ specification_version: 4
|
|
131
135
|
summary: '"Did you mean?" experience in Ruby'
|
132
136
|
test_files:
|
133
137
|
- test/core_ext/name_error_extension_test.rb
|
134
|
-
- test/correctable/class_name_test.rb
|
135
|
-
- test/correctable/method_name_test.rb
|
136
|
-
- test/correctable/uncorrectable_name_test.rb
|
137
|
-
- test/correctable/variable_name_test.rb
|
138
138
|
- test/edit_distance/jaro_winkler_test.rb
|
139
|
-
- test/
|
140
|
-
- test/
|
139
|
+
- test/experimental/deprecated_features_test.rb
|
140
|
+
- test/experimental/initializer_name_correction_test.rb
|
141
|
+
- test/experimental/key_error_test.rb
|
142
|
+
- test/experimental/method_name_checker_test.rb
|
141
143
|
- test/spell_checker_test.rb
|
144
|
+
- test/spell_checking/class_name_test.rb
|
145
|
+
- test/spell_checking/method_name_test.rb
|
146
|
+
- test/spell_checking/uncorrectable_name_test.rb
|
147
|
+
- test/spell_checking/variable_name_test.rb
|
142
148
|
- test/test_helper.rb
|
143
149
|
- test/verbose_formatter_test.rb
|
@@ -1,56 +0,0 @@
|
|
1
|
-
# -*- frozen-string-literal: true -*-
|
2
|
-
|
3
|
-
require "did_you_mean/levenshtein"
|
4
|
-
require "did_you_mean/jaro_winkler"
|
5
|
-
|
6
|
-
module DidYouMean
|
7
|
-
module SpellCheckable
|
8
|
-
def corrections
|
9
|
-
@corrections ||= candidates.flat_map do |input, candidates|
|
10
|
-
input = normalize(input)
|
11
|
-
threshold = input.length > 3 ? 0.834 : 0.77
|
12
|
-
|
13
|
-
seed = candidates.select {|candidate| JaroWinkler.distance(normalize(candidate), input) >= threshold }
|
14
|
-
seed.reject! {|candidate| input == candidate.to_s }
|
15
|
-
seed.sort_by! {|candidate| JaroWinkler.distance(candidate.to_s, input) }
|
16
|
-
seed.reverse!
|
17
|
-
|
18
|
-
# Correct mistypes
|
19
|
-
threshold = (input.length * 0.25).ceil
|
20
|
-
has_mistype = seed.rindex {|c| Levenshtein.distance(normalize(c), input) <= threshold }
|
21
|
-
|
22
|
-
corrections = if has_mistype
|
23
|
-
seed.take(has_mistype + 1)
|
24
|
-
else
|
25
|
-
# Correct misspells
|
26
|
-
seed.select do |candidate|
|
27
|
-
candidate = normalize(candidate)
|
28
|
-
length = input.length < candidate.length ? input.length : candidate.length
|
29
|
-
|
30
|
-
Levenshtein.distance(candidate, input) < length
|
31
|
-
end.first(1)
|
32
|
-
end
|
33
|
-
|
34
|
-
corrections
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def candidates
|
39
|
-
raise NotImplementedError
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def normalize(str_or_symbol) #:nodoc:
|
45
|
-
str = if str_or_symbol.is_a?(String)
|
46
|
-
str_or_symbol.dup
|
47
|
-
else
|
48
|
-
str_or_symbol.to_s
|
49
|
-
end
|
50
|
-
|
51
|
-
str.downcase!
|
52
|
-
str.tr!("@", "")
|
53
|
-
str
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|