did_you_mean 1.5.0 → 1.6.1
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/.github/workflows/ruby.yml +1 -1
- data/CHANGELOG.md +37 -2
- data/README.md +7 -15
- data/documentation/tree_spell_checker_api.md +1 -1
- data/lib/did_you_mean/core_ext/name_error.rb +10 -3
- data/lib/did_you_mean/formatter.rb +44 -0
- data/lib/did_you_mean/formatters/plain_formatter.rb +3 -32
- data/lib/did_you_mean/formatters/verbose_formatter.rb +6 -46
- data/lib/did_you_mean/spell_checker.rb +9 -9
- data/lib/did_you_mean/spell_checkers/method_name_checker.rb +3 -0
- data/lib/did_you_mean/spell_checkers/name_error_checkers/variable_name_checker.rb +3 -0
- data/lib/did_you_mean/spell_checkers/pattern_key_name_checker.rb +20 -0
- data/lib/did_you_mean/spell_checkers/require_path_checker.rb +5 -1
- data/lib/did_you_mean/verbose.rb +2 -4
- data/lib/did_you_mean/version.rb +1 -1
- data/lib/did_you_mean.rb +51 -8
- data/test/core_ext/test_name_error_extension.rb +4 -3
- data/test/helper.rb +4 -0
- data/test/spell_checking/test_pattern_key_name_check.rb +20 -0
- data/test/spell_checking/test_uncorrectable_name_check.rb +1 -1
- data/test/test_ractor_compatibility.rb +102 -0
- data/test/test_spell_checker.rb +1 -0
- data/test/tree_spell/test_change_word.rb +1 -1
- metadata +12 -8
- data/test/test_verbose_formatter.rb +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5179422bf1ff107c7189cb5e75e44f1cd8d44c2e305cbd46f1c262011fe46add
|
4
|
+
data.tar.gz: ea8103ee404f2bed7e002efb615b9a1c26b8080284fac57929276b72fa5cb0c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45ee6a7e79a463743a5529f38b503c78266458b07fe2e8a85d8f4e0ece2c65dbc40baf0aaa96c4c6592bca868c4a99f9d6001f4b5b9c033bf504aedb34ba5340
|
7
|
+
data.tar.gz: f259d9fef544f4071733007277c672c16f95bbe0e7d303bc6bf52fa0d7fa7108dcf615d6502e7950d2b48e4ce720034cc2d23096d52bee6f03e7206eab02569b
|
data/.github/workflows/ruby.yml
CHANGED
@@ -13,7 +13,7 @@ jobs:
|
|
13
13
|
runs-on: ubuntu-latest
|
14
14
|
strategy:
|
15
15
|
matrix:
|
16
|
-
ruby: [ '2.5
|
16
|
+
ruby: [ '2.5', '2.6', '2.7', '3.0', 'ruby-head', 'jruby-9.2', 'jruby-head' ]
|
17
17
|
steps:
|
18
18
|
- uses: actions/checkout@v1
|
19
19
|
- uses: ruby/setup-ruby@v1
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,41 @@
|
|
1
|
-
## v1.
|
1
|
+
## v1.6.1
|
2
2
|
|
3
|
-
-
|
3
|
+
_<sup>released at 2020-12-22 13:22:35 UTC</sup>_
|
4
|
+
|
5
|
+
#### Deprecations
|
6
|
+
|
7
|
+
- Deprecate custom formatters to reduce complexity for Ractor support.
|
8
|
+
- Deprecate access to the `DidYouMean::SPELL_CHECEKRS` constant for Ractor support.
|
9
|
+
|
10
|
+
#### Features
|
11
|
+
|
12
|
+
- The `did_you_mean` gem is now Ractor-compatible (`8faba54b`)
|
13
|
+
- Suggest keys on NoMatchingPatternKeyError (#159, @k-tsj)
|
14
|
+
- Make the same name check case-sensitive (#164, @pocke)
|
15
|
+
|
16
|
+
Before:
|
17
|
+
```ruby
|
18
|
+
DidYouMean::SpellChecker.new(dictionary: ['Method', 'MEthod']).correct("MEthod")
|
19
|
+
# => ['Method', 'method']
|
20
|
+
```
|
21
|
+
|
22
|
+
After:
|
23
|
+
```ruby
|
24
|
+
DidYouMean::SpellChecker.new(dictionary: ['Method', 'MEthod']).correct("MEthod")
|
25
|
+
# => ['Method']
|
26
|
+
```
|
27
|
+
|
28
|
+
## v1.6.0 (yanked)
|
29
|
+
|
30
|
+
_This version has been yanked due to significant and unexpected breaking changes._
|
31
|
+
|
32
|
+
## [v1.5.0](https://github.com/ruby/did_you_mean/tree/v1.5.0)
|
33
|
+
|
34
|
+
_<sup>released at 2020-12-22 05:47:21 UTC</sup>_
|
35
|
+
|
36
|
+
#### Features
|
37
|
+
|
38
|
+
- Suggest require paths on LoadError ([#143](https://github.com/ruby/did_you_mean/pull/143))
|
4
39
|
|
5
40
|
## [v1.4.0](https://github.com/ruby/did_you_mean/tree/v1.4.0)
|
6
41
|
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# did_you_mean [](https://rubygems.org/gems/did_you_mean) [](https://rubygems.org/gems/did_you_mean) [](https://github.com/ruby/did_you_mean/actions/workflows/ruby.yml)
|
2
2
|
|
3
3
|
## Installation
|
4
4
|
|
@@ -69,21 +69,13 @@ require 'net-http'
|
|
69
69
|
# Did you mean? net/http
|
70
70
|
```
|
71
71
|
|
72
|
-
|
73
|
-
|
74
|
-
This verbose formatter changes the error message format to take more lines/spaces so it'll be slightly easier to read the suggestions. This formatter can totally be used in any environment including production.
|
72
|
+
### NoMatchingPatternKeyError
|
75
73
|
|
76
74
|
```ruby
|
77
|
-
|
78
|
-
|
79
|
-
#
|
80
|
-
|
81
|
-
require 'did_you_mean/verbose'
|
82
|
-
OBject
|
83
|
-
# => NameError: uninitialized constant OBject
|
84
|
-
#
|
85
|
-
# Did you mean? Object
|
86
|
-
#
|
75
|
+
hash = {foo: 1, bar: 2, baz: 3}
|
76
|
+
hash => {fooo:}
|
77
|
+
# => NoMatchingPatternKeyError: key not found: :fooo
|
78
|
+
# Did you mean? :foo
|
87
79
|
```
|
88
80
|
|
89
81
|
## Using the `DidYouMean::SpellChecker`
|
@@ -107,7 +99,7 @@ $ ruby --disable-did_you_mean -e "1.zeor?"
|
|
107
99
|
-e:1:in `<main>': undefined method `zeor?' for 1:Integer (NameError)
|
108
100
|
```
|
109
101
|
|
110
|
-
When you do not have direct access to the `ruby` command (e.g. `rails console`, `irb`), you could
|
102
|
+
When you do not have direct access to the `ruby` command (e.g. `rails console`, `irb`), you could apply options using the
|
111
103
|
`RUBYOPT` environment variable:
|
112
104
|
|
113
105
|
```bash
|
@@ -11,7 +11,7 @@ where
|
|
11
11
|
* that are used to correct a misspelling
|
12
12
|
* The dictionary must be tree structured with a single character separator
|
13
13
|
* e.g 'spec/models/goals_spec_rb'.
|
14
|
-
####separator: A single
|
14
|
+
####separator: A single character. Cannot be cannot be alphabetical, '@' or '.'.
|
15
15
|
####augment: When set to true, the checker will used the standard ```SpellChecker``` to find possible suggestions.
|
16
16
|
## Methods
|
17
17
|
```
|
@@ -1,14 +1,21 @@
|
|
1
1
|
module DidYouMean
|
2
2
|
module Correctable
|
3
|
+
SKIP_TO_S_FOR_SUPER_LOOKUP = true
|
4
|
+
private_constant :SKIP_TO_S_FOR_SUPER_LOOKUP
|
5
|
+
|
3
6
|
def original_message
|
4
|
-
method(:to_s)
|
7
|
+
meth = method(:to_s)
|
8
|
+
while meth.owner.const_defined?(:SKIP_TO_S_FOR_SUPER_LOOKUP)
|
9
|
+
meth = meth.super_method
|
10
|
+
end
|
11
|
+
meth.call
|
5
12
|
end
|
6
13
|
|
7
14
|
def to_s
|
8
15
|
msg = super.dup
|
9
16
|
suggestion = DidYouMean.formatter.message_for(corrections)
|
10
17
|
|
11
|
-
msg << suggestion if !msg.
|
18
|
+
msg << suggestion if !msg.include?(suggestion)
|
12
19
|
msg
|
13
20
|
rescue
|
14
21
|
super
|
@@ -19,7 +26,7 @@ module DidYouMean
|
|
19
26
|
end
|
20
27
|
|
21
28
|
def spell_checker
|
22
|
-
|
29
|
+
DidYouMean.spell_checkers[self.class.to_s].new(self)
|
23
30
|
end
|
24
31
|
end
|
25
32
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module DidYouMean
|
4
|
+
# The +DidYouMean::Formatter+ is the basic, default formatter for the
|
5
|
+
# gem. The formatter responds to the +message_for+ method and it returns a
|
6
|
+
# human readable string.
|
7
|
+
class Formatter
|
8
|
+
|
9
|
+
# Returns a human readable string that contains +corrections+. This
|
10
|
+
# formatter is designed to be less verbose to not take too much screen
|
11
|
+
# space while being helpful enough to the user.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
#
|
15
|
+
# formatter = DidYouMean::Formatter.new
|
16
|
+
#
|
17
|
+
# # displays suggestions in two lines with the leading empty line
|
18
|
+
# puts formatter.message_for(["methods", "method"])
|
19
|
+
#
|
20
|
+
# Did you mean? methods
|
21
|
+
# method
|
22
|
+
# # => nil
|
23
|
+
#
|
24
|
+
# # displays an empty line
|
25
|
+
# puts formatter.message_for([])
|
26
|
+
#
|
27
|
+
# # => nil
|
28
|
+
#
|
29
|
+
def self.message_for(corrections)
|
30
|
+
corrections.empty? ? "" : "\nDid you mean? #{corrections.join("\n ")}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def message_for(corrections)
|
34
|
+
warn "The instance method #message_for has been deprecated. Please use the class method " \
|
35
|
+
"DidYouMean::Formatter.message_for(...) instead."
|
36
|
+
|
37
|
+
self.class.message_for(corrections)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
PlainFormatter = Formatter
|
42
|
+
|
43
|
+
deprecate_constant :PlainFormatter
|
44
|
+
end
|
@@ -1,33 +1,4 @@
|
|
1
|
-
|
1
|
+
require_relative '../formatter'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
# gem. The formatter responds to the +message_for+ method and it returns a
|
6
|
-
# human readable string.
|
7
|
-
class PlainFormatter
|
8
|
-
|
9
|
-
# Returns a human readable string that contains +corrections+. This
|
10
|
-
# formatter is designed to be less verbose to not take too much screen
|
11
|
-
# space while being helpful enough to the user.
|
12
|
-
#
|
13
|
-
# @example
|
14
|
-
#
|
15
|
-
# formatter = DidYouMean::PlainFormatter.new
|
16
|
-
#
|
17
|
-
# # displays suggestions in two lines with the leading empty line
|
18
|
-
# puts formatter.message_for(["methods", "method"])
|
19
|
-
#
|
20
|
-
# Did you mean? methods
|
21
|
-
# method
|
22
|
-
# # => nil
|
23
|
-
#
|
24
|
-
# # displays an empty line
|
25
|
-
# puts formatter.message_for([])
|
26
|
-
#
|
27
|
-
# # => nil
|
28
|
-
#
|
29
|
-
def message_for(corrections)
|
30
|
-
corrections.empty? ? "" : "\nDid you mean? #{corrections.join("\n ")}"
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
3
|
+
warn "`require 'did_you_mean/formatters/plain_formatter'` is deprecated. Please `require 'did_you_mean/formatter'` " \
|
4
|
+
"instead."
|
@@ -1,49 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
module DidYouMean
|
4
|
-
# The +DidYouMean::VerboseFormatter+ uses extra empty lines to make the
|
5
|
-
# suggestion stand out more in the error message.
|
6
|
-
#
|
7
|
-
# In order to activate the verbose formatter,
|
8
|
-
#
|
9
|
-
# @example
|
10
|
-
#
|
11
|
-
# OBject
|
12
|
-
# # => NameError: uninitialized constant OBject
|
13
|
-
# # Did you mean? Object
|
14
|
-
#
|
15
|
-
# require 'did_you_mean/verbose'
|
16
|
-
#
|
17
|
-
# OBject
|
18
|
-
# # => NameError: uninitialized constant OBject
|
19
|
-
# #
|
20
|
-
# # Did you mean? Object
|
21
|
-
# #
|
22
|
-
#
|
23
|
-
class VerboseFormatter
|
1
|
+
warn "`require 'did_you_mean/formatters/verbose_formatter'` is deprecated and falls back to the default formatter. "
|
24
2
|
|
25
|
-
|
26
|
-
# formatter is designed to be less verbose to not take too much screen
|
27
|
-
# space while being helpful enough to the user.
|
28
|
-
#
|
29
|
-
# @example
|
30
|
-
#
|
31
|
-
# formatter = DidYouMean::PlainFormatter.new
|
32
|
-
#
|
33
|
-
# puts formatter.message_for(["methods", "method"])
|
34
|
-
#
|
35
|
-
#
|
36
|
-
# Did you mean? methods
|
37
|
-
# method
|
38
|
-
#
|
39
|
-
# # => nil
|
40
|
-
#
|
41
|
-
def message_for(corrections)
|
42
|
-
return "" if corrections.empty?
|
3
|
+
require_relative '../formatter'
|
43
4
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
end
|
5
|
+
# frozen-string-literal: true
|
6
|
+
module DidYouMean
|
7
|
+
# For compatibility:
|
8
|
+
VerboseFormatter = Formatter
|
49
9
|
end
|
@@ -10,25 +10,25 @@ module DidYouMean
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def correct(input)
|
13
|
-
|
14
|
-
threshold =
|
13
|
+
normalized_input = normalize(input)
|
14
|
+
threshold = normalized_input.length > 3 ? 0.834 : 0.77
|
15
15
|
|
16
|
-
words = @dictionary.select { |word| JaroWinkler.distance(normalize(word),
|
17
|
-
words.reject! { |word| input == word.to_s }
|
18
|
-
words.sort_by! { |word| JaroWinkler.distance(word.to_s,
|
16
|
+
words = @dictionary.select { |word| JaroWinkler.distance(normalize(word), normalized_input) >= threshold }
|
17
|
+
words.reject! { |word| input.to_s == word.to_s }
|
18
|
+
words.sort_by! { |word| JaroWinkler.distance(word.to_s, normalized_input) }
|
19
19
|
words.reverse!
|
20
20
|
|
21
21
|
# Correct mistypes
|
22
|
-
threshold = (
|
23
|
-
corrections = words.select { |c| Levenshtein.distance(normalize(c),
|
22
|
+
threshold = (normalized_input.length * 0.25).ceil
|
23
|
+
corrections = words.select { |c| Levenshtein.distance(normalize(c), normalized_input) <= threshold }
|
24
24
|
|
25
25
|
# Correct misspells
|
26
26
|
if corrections.empty?
|
27
27
|
corrections = words.select do |word|
|
28
28
|
word = normalize(word)
|
29
|
-
length =
|
29
|
+
length = normalized_input.length < word.length ? normalized_input.length : word.length
|
30
30
|
|
31
|
-
Levenshtein.distance(word,
|
31
|
+
Levenshtein.distance(word, normalized_input) < length
|
32
32
|
end.first(1)
|
33
33
|
end
|
34
34
|
|
@@ -6,6 +6,7 @@ module DidYouMean
|
|
6
6
|
|
7
7
|
NAMES_TO_EXCLUDE = { NilClass => nil.methods }
|
8
8
|
NAMES_TO_EXCLUDE.default = []
|
9
|
+
Ractor.make_shareable(NAMES_TO_EXCLUDE) if defined?(Ractor)
|
9
10
|
|
10
11
|
# +MethodNameChecker::RB_RESERVED_WORDS+ is the list of reserved words in
|
11
12
|
# Ruby that take an argument. Unlike
|
@@ -36,6 +37,8 @@ module DidYouMean
|
|
36
37
|
yield
|
37
38
|
)
|
38
39
|
|
40
|
+
Ractor.make_shareable(RB_RESERVED_WORDS) if defined?(Ractor)
|
41
|
+
|
39
42
|
def initialize(exception)
|
40
43
|
@method_name = exception.name
|
41
44
|
@receiver = exception.receiver
|
@@ -8,6 +8,7 @@ module DidYouMean
|
|
8
8
|
|
9
9
|
NAMES_TO_EXCLUDE = { 'foo' => [:fork, :for] }
|
10
10
|
NAMES_TO_EXCLUDE.default = []
|
11
|
+
Ractor.make_shareable(NAMES_TO_EXCLUDE) if defined?(Ractor)
|
11
12
|
|
12
13
|
# +VariableNameChecker::RB_RESERVED_WORDS+ is the list of all reserved
|
13
14
|
# words in Ruby. They could be declared like methods are, and a typo would
|
@@ -62,6 +63,8 @@ module DidYouMean
|
|
62
63
|
__ENCODING__
|
63
64
|
)
|
64
65
|
|
66
|
+
Ractor.make_shareable(RB_RESERVED_WORDS) if defined?(Ractor)
|
67
|
+
|
65
68
|
def initialize(exception)
|
66
69
|
@name = exception.name.to_s.tr("@", "")
|
67
70
|
@lvar_names = exception.respond_to?(:local_variables) ? exception.local_variables : []
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative "../spell_checker"
|
2
|
+
|
3
|
+
module DidYouMean
|
4
|
+
class PatternKeyNameChecker
|
5
|
+
def initialize(no_matching_pattern_key_error)
|
6
|
+
@key = no_matching_pattern_key_error.key
|
7
|
+
@keys = no_matching_pattern_key_error.matchee.keys
|
8
|
+
end
|
9
|
+
|
10
|
+
def corrections
|
11
|
+
@corrections ||= exact_matches.empty? ? SpellChecker.new(dictionary: @keys).correct(@key).map(&:inspect) : exact_matches
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def exact_matches
|
17
|
+
@exact_matches ||= @keys.select { |word| @key == word.to_s }.map(&:inspect)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -2,13 +2,17 @@
|
|
2
2
|
|
3
3
|
require_relative "../spell_checker"
|
4
4
|
require_relative "../tree_spell_checker"
|
5
|
+
require "rbconfig"
|
5
6
|
|
6
7
|
module DidYouMean
|
7
8
|
class RequirePathChecker
|
8
9
|
attr_reader :path
|
9
10
|
|
10
11
|
INITIAL_LOAD_PATH = $LOAD_PATH.dup.freeze
|
11
|
-
|
12
|
+
Ractor.make_shareable(INITIAL_LOAD_PATH) if defined?(Ractor)
|
13
|
+
|
14
|
+
ENV_SPECIFIC_EXT = ".#{RbConfig::CONFIG["DLEXT"]}"
|
15
|
+
Ractor.make_shareable(ENV_SPECIFIC_EXT) if defined?(Ractor)
|
12
16
|
|
13
17
|
private_constant :INITIAL_LOAD_PATH, :ENV_SPECIFIC_EXT
|
14
18
|
|
data/lib/did_you_mean/verbose.rb
CHANGED
@@ -1,4 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
DidYouMean.formatter = DidYouMean::VerboseFormatter.new
|
1
|
+
warn "The verbose formatter has been removed and now `require 'did_you_mean/verbose'` has no effect. Please " \
|
2
|
+
"remove this call."
|
data/lib/did_you_mean/version.rb
CHANGED
data/lib/did_you_mean.rb
CHANGED
@@ -7,7 +7,8 @@ require_relative 'did_you_mean/spell_checkers/method_name_checker'
|
|
7
7
|
require_relative 'did_you_mean/spell_checkers/key_error_checker'
|
8
8
|
require_relative 'did_you_mean/spell_checkers/null_checker'
|
9
9
|
require_relative 'did_you_mean/spell_checkers/require_path_checker'
|
10
|
-
require_relative 'did_you_mean/
|
10
|
+
require_relative 'did_you_mean/spell_checkers/pattern_key_name_checker'
|
11
|
+
require_relative 'did_you_mean/formatter'
|
11
12
|
require_relative 'did_you_mean/tree_spell_checker'
|
12
13
|
|
13
14
|
# The +DidYouMean+ gem adds functionality to suggest possible method/class
|
@@ -85,28 +86,70 @@ require_relative 'did_you_mean/tree_spell_checker'
|
|
85
86
|
#
|
86
87
|
module DidYouMean
|
87
88
|
# Map of error types and spell checker objects.
|
88
|
-
|
89
|
+
@spell_checkers = Hash.new(NullChecker)
|
90
|
+
|
91
|
+
# Returns a sharable hash map of error types and spell checker objects.
|
92
|
+
def self.spell_checkers
|
93
|
+
@spell_checkers
|
94
|
+
end
|
89
95
|
|
90
96
|
# Adds +DidYouMean+ functionality to an error using a given spell checker
|
91
97
|
def self.correct_error(error_class, spell_checker)
|
92
|
-
|
93
|
-
|
98
|
+
if defined?(Ractor)
|
99
|
+
new_mapping = { **@spell_checkers, error_class.to_s => spell_checker }
|
100
|
+
new_mapping.default = NullChecker
|
101
|
+
|
102
|
+
@spell_checkers = Ractor.make_shareable(new_mapping)
|
103
|
+
else
|
104
|
+
spell_checkers[error_class.to_s] = spell_checker
|
105
|
+
end
|
106
|
+
|
107
|
+
error_class.prepend(Correctable) if error_class.is_a?(Class) && !(error_class < Correctable)
|
94
108
|
end
|
95
109
|
|
96
110
|
correct_error NameError, NameErrorCheckers
|
97
111
|
correct_error KeyError, KeyErrorChecker
|
98
112
|
correct_error NoMethodError, MethodNameChecker
|
99
113
|
correct_error LoadError, RequirePathChecker if RUBY_VERSION >= '2.8.0'
|
114
|
+
correct_error NoMatchingPatternKeyError, PatternKeyNameChecker if defined?(::NoMatchingPatternKeyError)
|
115
|
+
|
116
|
+
# TODO: Remove on 3.3:
|
117
|
+
class DeprecatedMapping # :nodoc:
|
118
|
+
def []=(key, value)
|
119
|
+
warn "Calling `DidYouMean::SPELL_CHECKERS[#{key.to_s}] = #{value.to_s}' has been deprecated. " \
|
120
|
+
"Please call `DidYouMean.correct_error(#{key.to_s}, #{value.to_s})' instead."
|
121
|
+
|
122
|
+
DidYouMean.correct_error(key, value)
|
123
|
+
end
|
124
|
+
|
125
|
+
def merge!(hash)
|
126
|
+
warn "Calling `DidYouMean::SPELL_CHECKERS.merge!(error_name => spell_checker)' has been deprecated. " \
|
127
|
+
"Please call `DidYouMean.correct_error(error_name, spell_checker)' instead."
|
128
|
+
|
129
|
+
hash.each do |error_class, spell_checker|
|
130
|
+
DidYouMean.correct_error(error_class, spell_checker)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# TODO: Remove on 3.3:
|
136
|
+
SPELL_CHECKERS = DeprecatedMapping.new
|
137
|
+
deprecate_constant :SPELL_CHECKERS
|
138
|
+
private_constant :DeprecatedMapping
|
100
139
|
|
101
140
|
# Returns the currently set formatter. By default, it is set to +DidYouMean::Formatter+.
|
102
141
|
def self.formatter
|
103
|
-
|
142
|
+
if defined?(Ractor)
|
143
|
+
Ractor.current[:__did_you_mean_formatter__] || Formatter
|
144
|
+
else
|
145
|
+
Formatter
|
146
|
+
end
|
104
147
|
end
|
105
148
|
|
106
149
|
# Updates the primary formatter used to format the suggestions.
|
107
150
|
def self.formatter=(formatter)
|
108
|
-
|
151
|
+
if defined?(Ractor)
|
152
|
+
Ractor.current[:__did_you_mean_formatter__] = formatter
|
153
|
+
end
|
109
154
|
end
|
110
|
-
|
111
|
-
self.formatter = PlainFormatter.new
|
112
155
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require_relative '../helper'
|
2
2
|
|
3
3
|
class NameErrorExtensionTest < Test::Unit::TestCase
|
4
|
-
SPELL_CHECKERS = DidYouMean
|
4
|
+
SPELL_CHECKERS = DidYouMean.spell_checkers
|
5
5
|
|
6
6
|
class TestSpellChecker
|
7
7
|
def initialize(*); end
|
@@ -9,13 +9,14 @@ class NameErrorExtensionTest < Test::Unit::TestCase
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def setup
|
12
|
-
@
|
12
|
+
@original_spell_checker = DidYouMean.spell_checkers['NameError']
|
13
|
+
DidYouMean.correct_error(NameError, TestSpellChecker)
|
13
14
|
|
14
15
|
@error = assert_raise(NameError){ doesnt_exist }
|
15
16
|
end
|
16
17
|
|
17
18
|
def teardown
|
18
|
-
|
19
|
+
DidYouMean.correct_error(NameError, @original_spell_checker)
|
19
20
|
end
|
20
21
|
|
21
22
|
def test_message
|
data/test/helper.rb
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative '../helper'
|
2
|
+
|
3
|
+
return if !defined?(::NoMatchingPatternKeyError)
|
4
|
+
|
5
|
+
class PatternKeyNameCheckTest < Test::Unit::TestCase
|
6
|
+
include DidYouMean::TestHelper
|
7
|
+
|
8
|
+
def test_corrects_hash_key_name_with_single_pattern_match
|
9
|
+
error = assert_raise(NoMatchingPatternKeyError) do
|
10
|
+
eval(<<~RUBY, binding, __FILE__, __LINE__)
|
11
|
+
hash = {foo: 1, bar: 2, baz: 3}
|
12
|
+
hash => {fooo:}
|
13
|
+
fooo = 1 # suppress "unused variable: fooo" warning
|
14
|
+
RUBY
|
15
|
+
end
|
16
|
+
|
17
|
+
assert_correction ":foo", error.corrections
|
18
|
+
assert_match "Did you mean? :foo", error.to_s
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require_relative './helper'
|
2
|
+
|
3
|
+
return if not DidYouMean::TestHelper.ractor_compatible?
|
4
|
+
|
5
|
+
class RactorCompatibilityTest < Test::Unit::TestCase
|
6
|
+
include DidYouMean::TestHelper
|
7
|
+
|
8
|
+
class ::Book; end
|
9
|
+
class FirstNameError < NameError; end
|
10
|
+
|
11
|
+
def test_class_name_suggestion_works_in_ractor
|
12
|
+
error = Ractor.new {
|
13
|
+
begin
|
14
|
+
Boook
|
15
|
+
rescue NameError => e
|
16
|
+
e.corrections # It is important to call the #corrections method within Ractor.
|
17
|
+
e
|
18
|
+
end
|
19
|
+
}.take
|
20
|
+
|
21
|
+
assert_correction "Book", error.corrections
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_key_name_suggestion_works_in_ractor
|
25
|
+
error = Ractor.new {
|
26
|
+
begin
|
27
|
+
hash = { "foo" => 1, bar: 2 }
|
28
|
+
|
29
|
+
hash.fetch(:bax)
|
30
|
+
rescue KeyError => e
|
31
|
+
e.corrections # It is important to call the #corrections method within Ractor.
|
32
|
+
e
|
33
|
+
end
|
34
|
+
}.take
|
35
|
+
|
36
|
+
assert_correction ":bar", error.corrections
|
37
|
+
assert_match "Did you mean? :bar", error.to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_method_name_suggestion_works_in_ractor
|
41
|
+
error = Ractor.new {
|
42
|
+
begin
|
43
|
+
self.to__s
|
44
|
+
rescue NoMethodError => e
|
45
|
+
e.corrections # It is important to call the #corrections method within Ractor.
|
46
|
+
e
|
47
|
+
end
|
48
|
+
}.take
|
49
|
+
|
50
|
+
assert_correction :to_s, error.corrections
|
51
|
+
assert_match "Did you mean? to_s", error.to_s
|
52
|
+
end
|
53
|
+
|
54
|
+
if defined?(::NoMatchingPatternKeyError)
|
55
|
+
def test_pattern_key_name_suggestion_works_in_ractor
|
56
|
+
error = Ractor.new {
|
57
|
+
begin
|
58
|
+
eval(<<~RUBY, binding, __FILE__, __LINE__)
|
59
|
+
hash = {foo: 1, bar: 2, baz: 3}
|
60
|
+
hash => {fooo:}
|
61
|
+
fooo = 1 # suppress "unused variable: fooo" warning
|
62
|
+
RUBY
|
63
|
+
rescue NoMatchingPatternKeyError => e
|
64
|
+
e.corrections # It is important to call the #corrections method within Ractor.
|
65
|
+
e
|
66
|
+
end
|
67
|
+
}.take
|
68
|
+
|
69
|
+
assert_correction ":foo", error.corrections
|
70
|
+
assert_match "Did you mean? :foo", error.to_s
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_can_raise_other_name_error_in_ractor
|
75
|
+
error = Ractor.new {
|
76
|
+
begin
|
77
|
+
raise FirstNameError, "Other name error"
|
78
|
+
rescue FirstNameError => e
|
79
|
+
e.corrections # It is important to call the #corrections method within Ractor.
|
80
|
+
e
|
81
|
+
end
|
82
|
+
}.take
|
83
|
+
|
84
|
+
assert_not_match(/Did you mean\?/, error.message)
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_variable_name_suggestion_works_in_ractor
|
88
|
+
error = Ractor.new {
|
89
|
+
in_ractor = in_ractor = 1
|
90
|
+
|
91
|
+
begin
|
92
|
+
in_reactor
|
93
|
+
rescue NameError => e
|
94
|
+
e.corrections # It is important to call the #corrections method within Ractor.
|
95
|
+
e
|
96
|
+
end
|
97
|
+
}.take
|
98
|
+
|
99
|
+
assert_correction :in_ractor, error.corrections
|
100
|
+
assert_match "Did you mean? in_ractor", error.to_s
|
101
|
+
end
|
102
|
+
end
|
data/test/test_spell_checker.rb
CHANGED
@@ -10,6 +10,7 @@ class SpellCheckerTest < Test::Unit::TestCase
|
|
10
10
|
assert_spell 'eval', input: 'veal', dictionary: ['email', 'fail', 'eval']
|
11
11
|
assert_spell 'sub!', input: 'suv!', dictionary: ['sub', 'gsub', 'sub!']
|
12
12
|
assert_spell 'sub', input: 'suv', dictionary: ['sub', 'gsub', 'sub!']
|
13
|
+
assert_spell 'Foo', input: 'FOo', dictionary: ['Foo', 'FOo']
|
13
14
|
|
14
15
|
assert_spell %w(gsub! gsub), input: 'gsuv!', dictionary: %w(sub gsub gsub!)
|
15
16
|
assert_spell %w(sub! sub gsub!), input: 'ssub!', dictionary: %w(sub sub! gsub gsub!)
|
@@ -8,7 +8,7 @@ class ChangeWordTest < Test::Unit::TestCase
|
|
8
8
|
@len = @input.length
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
11
|
+
def test_deletion
|
12
12
|
assert_match @cw.deletion(5), 'spec/ervices/anything_spec'
|
13
13
|
assert_match @cw.deletion(@len - 1), 'spec/services/anything_spe'
|
14
14
|
assert_match @cw.deletion(0), 'pec/services/anything_spec'
|
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.
|
4
|
+
version: 1.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yuki Nishijima
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-12-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -55,6 +55,7 @@ files:
|
|
55
55
|
- lib/did_you_mean.rb
|
56
56
|
- lib/did_you_mean/core_ext/name_error.rb
|
57
57
|
- lib/did_you_mean/experimental.rb
|
58
|
+
- lib/did_you_mean/formatter.rb
|
58
59
|
- lib/did_you_mean/formatters/plain_formatter.rb
|
59
60
|
- lib/did_you_mean/formatters/verbose_formatter.rb
|
60
61
|
- lib/did_you_mean/jaro_winkler.rb
|
@@ -66,6 +67,7 @@ files:
|
|
66
67
|
- lib/did_you_mean/spell_checkers/name_error_checkers/class_name_checker.rb
|
67
68
|
- lib/did_you_mean/spell_checkers/name_error_checkers/variable_name_checker.rb
|
68
69
|
- lib/did_you_mean/spell_checkers/null_checker.rb
|
70
|
+
- lib/did_you_mean/spell_checkers/pattern_key_name_checker.rb
|
69
71
|
- lib/did_you_mean/spell_checkers/require_path_checker.rb
|
70
72
|
- lib/did_you_mean/tree_spell_checker.rb
|
71
73
|
- lib/did_you_mean/verbose.rb
|
@@ -79,12 +81,13 @@ files:
|
|
79
81
|
- test/spell_checking/test_class_name_check.rb
|
80
82
|
- test/spell_checking/test_key_name_check.rb
|
81
83
|
- test/spell_checking/test_method_name_check.rb
|
84
|
+
- test/spell_checking/test_pattern_key_name_check.rb
|
82
85
|
- test/spell_checking/test_require_path_check.rb
|
83
86
|
- test/spell_checking/test_uncorrectable_name_check.rb
|
84
87
|
- test/spell_checking/test_variable_name_check.rb
|
88
|
+
- test/test_ractor_compatibility.rb
|
85
89
|
- test/test_spell_checker.rb
|
86
90
|
- test/test_tree_spell_checker.rb
|
87
|
-
- test/test_verbose_formatter.rb
|
88
91
|
- test/tree_spell/change_word.rb
|
89
92
|
- test/tree_spell/human_typo.rb
|
90
93
|
- test/tree_spell/test_change_word.rb
|
@@ -94,7 +97,7 @@ homepage: https://github.com/ruby/did_you_mean
|
|
94
97
|
licenses:
|
95
98
|
- MIT
|
96
99
|
metadata: {}
|
97
|
-
post_install_message:
|
100
|
+
post_install_message:
|
98
101
|
rdoc_options: []
|
99
102
|
require_paths:
|
100
103
|
- lib
|
@@ -109,8 +112,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
112
|
- !ruby/object:Gem::Version
|
110
113
|
version: '0'
|
111
114
|
requirements: []
|
112
|
-
rubygems_version: 3.
|
113
|
-
signing_key:
|
115
|
+
rubygems_version: 3.3.0.dev
|
116
|
+
signing_key:
|
114
117
|
specification_version: 4
|
115
118
|
summary: '"Did you mean?" experience in Ruby'
|
116
119
|
test_files:
|
@@ -123,12 +126,13 @@ test_files:
|
|
123
126
|
- test/spell_checking/test_class_name_check.rb
|
124
127
|
- test/spell_checking/test_key_name_check.rb
|
125
128
|
- test/spell_checking/test_method_name_check.rb
|
129
|
+
- test/spell_checking/test_pattern_key_name_check.rb
|
126
130
|
- test/spell_checking/test_require_path_check.rb
|
127
131
|
- test/spell_checking/test_uncorrectable_name_check.rb
|
128
132
|
- test/spell_checking/test_variable_name_check.rb
|
133
|
+
- test/test_ractor_compatibility.rb
|
129
134
|
- test/test_spell_checker.rb
|
130
135
|
- test/test_tree_spell_checker.rb
|
131
|
-
- test/test_verbose_formatter.rb
|
132
136
|
- test/tree_spell/change_word.rb
|
133
137
|
- test/tree_spell/human_typo.rb
|
134
138
|
- test/tree_spell/test_change_word.rb
|
@@ -1,23 +0,0 @@
|
|
1
|
-
require_relative './helper'
|
2
|
-
|
3
|
-
class VerboseFormatterTest < Test::Unit::TestCase
|
4
|
-
def setup
|
5
|
-
require_relative File.join(DidYouMean::TestHelper.root, 'verbose')
|
6
|
-
|
7
|
-
DidYouMean.formatter = DidYouMean::VerboseFormatter.new
|
8
|
-
end
|
9
|
-
|
10
|
-
def teardown
|
11
|
-
DidYouMean.formatter = DidYouMean::PlainFormatter.new
|
12
|
-
end
|
13
|
-
|
14
|
-
def test_message
|
15
|
-
@error = assert_raise(NoMethodError){ 1.zeor? }
|
16
|
-
|
17
|
-
assert_match <<~MESSAGE.strip, @error.message
|
18
|
-
undefined method `zeor?' for 1:Integer
|
19
|
-
|
20
|
-
Did you mean? zero?
|
21
|
-
MESSAGE
|
22
|
-
end
|
23
|
-
end
|