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.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -1
  3. data/README.md +5 -5
  4. data/Rakefile +5 -5
  5. data/benchmark/memory_usage.rb +1 -18
  6. data/evaluation/calculator.rb +3 -22
  7. data/lib/did_you_mean.rb +1 -1
  8. data/lib/did_you_mean/experimental.rb +17 -0
  9. data/lib/did_you_mean/{extra_features → experimental}/initializer_name_correction.rb +1 -1
  10. data/lib/did_you_mean/{extra_features → experimental}/ivar_name_correction.rb +7 -3
  11. data/lib/did_you_mean/experimental/key_error_name_correction.rb +32 -0
  12. data/lib/did_you_mean/extra_features.rb +2 -15
  13. data/lib/did_you_mean/spell_checker.rb +54 -0
  14. data/lib/did_you_mean/spell_checkers/method_name_checker.rb +2 -3
  15. data/lib/did_you_mean/spell_checkers/name_error_checkers/class_name_checker.rb +2 -7
  16. data/lib/did_you_mean/spell_checkers/name_error_checkers/variable_name_checker.rb +4 -3
  17. data/lib/did_you_mean/version.rb +1 -1
  18. data/test/experimental/deprecated_features_test.rb +13 -0
  19. data/test/{extra_features → experimental}/initializer_name_correction_test.rb +0 -0
  20. data/test/experimental/key_error_test.rb +15 -0
  21. data/test/{extra_features → experimental}/method_name_checker_test.rb +1 -1
  22. data/test/spell_checker_test.rb +8 -16
  23. data/test/{correctable → spell_checking}/class_name_test.rb +0 -0
  24. data/test/{correctable → spell_checking}/method_name_test.rb +0 -0
  25. data/test/{correctable → spell_checking}/uncorrectable_name_test.rb +0 -0
  26. data/test/{correctable → spell_checking}/variable_name_test.rb +0 -0
  27. data/test/verbose_formatter_test.rb +1 -1
  28. metadata +23 -17
  29. 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: b69ea3a675f27d9da3419e086c21bd5930f16f90
4
- data.tar.gz: 56d723b6a3ab08a92e07412bc0efa2051920626f
3
+ metadata.gz: 28e1952e8b23b15341dd32e2b069ff5a1095c214
4
+ data.tar.gz: ab42a54b71d2ea36821f135af2182dbc42671abf
5
5
  SHA512:
6
- metadata.gz: 1aaf379cad209d36b9df5ed695a42a97bde164cb52619b6c47f1a2c1163ee3ebe1d040c906a46ba89cb3f6e78570f994cf357c08bb87044f7a46aadfbac70810
7
- data.tar.gz: 374348aefc081447d3e27f86feb1628ce6914140931e35738e3b230e66e077d245591671dc6c787798c8f4a06edad083051f92e4babfd882e386e051044006d3
6
+ metadata.gz: d91287f29b78c81341da7c6154272f25f8d9ca28b1d71599079746f24182830d1833493a270705fa3bdc20e003fb1566307772974b88fc6c7b904a7fe3b7a923
7
+ data.tar.gz: 36a5296b2b247ff3a8791623108e3518571f2d8ad4864bc3eddfb9e17cb648726ba7af9ab4f5dc26d1ad5b4fc47e66044a41e62e066ef4d68727fb64ad8bec59
@@ -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 [extra features](https://github.com/yuki24/did_you_mean#extra-features)
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
- ## Extra Features
55
+ ## Experimental Features
56
56
 
57
- Aside from the basic features above, the `did_you_mean` gem comes with 2 extra features. They can be enabled by calling `require 'did_you_mean/extra_features'`.
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 extra features should never be enabled in production as they impact Ruby's performance and uses an unstable Ruby API.**
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/extra_features'
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/extra_features'
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|extra_features)/ =~ path
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:extra_features") do |task|
23
+ Rake::TestTask.new("test:experimental") do |task|
24
24
  task.libs << "test"
25
- task.pattern = 'test/extra_features/**/*_test.rb'
25
+ task.pattern = 'test/experimental/**/*_test.rb'
26
26
  task.verbose = true
27
27
  task.warning = true
28
- task.ruby_opts << "-rdid_you_mean/extra_features"
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:extra_features)
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
@@ -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
@@ -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
 
@@ -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/spell_checkable"
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,7 +1,7 @@
1
1
  # -*- frozen-string-literal: true -*-
2
2
 
3
3
  module DidYouMean
4
- module ExtraFeatures
4
+ module Experimental
5
5
  module InitializerNameCorrection
6
6
  def method_added(name)
7
7
  super
@@ -1,5 +1,5 @@
1
1
  module DidYouMean
2
- module ExtraFeatures
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 candidates
16
- super.merge(receiver_name.to_s => @ivar_names)
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
- 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/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 candidates
13
- { method_name => method_names }
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 candidates
14
- {class_name => class_names}
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 candidates
20
- { name => (lvar_names + method_names + ivar_names + cvar_names) }
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
@@ -1,3 +1,3 @@
1
1
  module DidYouMean
2
- VERSION = "1.0.1"
2
+ VERSION = "1.0.2"
3
3
  end
@@ -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
@@ -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
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class MethodNameWithExtraFeaturesTest < Minitest::Test
3
+ class ExperimentalMethodNameCorrectionTest < Minitest::Test
4
4
  def test_corrects_incorrect_ivar_name
5
5
  @number = 1
6
6
  @nubmer = nil
@@ -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('product_path', ['proc']).corrections
47
- assert_empty SpellChecker.new('fooo', ['fork']).corrections
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("name123456", %w(
55
+ actual = DidYouMean::SpellChecker.new(dictionary: %w(
64
56
  name12
65
57
  name123
66
58
  name1234
67
59
  name12345
68
60
  name123456
69
- )).corrections
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('input', ['input']).corrections
76
- assert_empty SpellChecker.new('input', [:input]).corrections
77
- assert_empty SpellChecker.new(:input, ['input']).corrections
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(input, dictionary).corrections
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
@@ -2,7 +2,7 @@ require 'test_helper'
2
2
 
3
3
  class VerboseFormatterTest < Minitest::Test
4
4
  def setup
5
- @error = assert_raises(NameError){ self.inspectt }
5
+ @error = assert_raises(NoMethodError){ self.inspectt }
6
6
  end
7
7
 
8
8
  def test_message
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.1
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-05-15 00:00:00.000000000 Z
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/spell_checkable.rb
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/extra_features/initializer_name_correction_test.rb
104
- - test/extra_features/method_name_checker_test.rb
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/extra_features/initializer_name_correction_test.rb
140
- - test/extra_features/method_name_checker_test.rb
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