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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3befc8f677ec57e2975d04b2095fcecf7314ff207150aa994b197894dba883af
4
- data.tar.gz: dc5a44ad2f6058ef68913f4080a23141f39b23f3b30129fe753d5d88cca85cc0
3
+ metadata.gz: 5179422bf1ff107c7189cb5e75e44f1cd8d44c2e305cbd46f1c262011fe46add
4
+ data.tar.gz: ea8103ee404f2bed7e002efb615b9a1c26b8080284fac57929276b72fa5cb0c5
5
5
  SHA512:
6
- metadata.gz: 4d60d78614d4a6650b2be87599d3c3d867ab74f4cdf7f6083594229e3c51588af57a5c9574ca35ced229558f4280cd3677cbd7944cc5cef55e34a4f7ff7addf3
7
- data.tar.gz: df5f07a5893afee4e03af416230ee828c7c2c2dfb8e5e35b5c525bebdff03710645b4af192563dc546abd4c210f8f2e8ce15e90124503488b74db19bd700f71c
6
+ metadata.gz: 45ee6a7e79a463743a5529f38b503c78266458b07fe2e8a85d8f4e0ece2c65dbc40baf0aaa96c4c6592bca868c4a99f9d6001f4b5b9c033bf504aedb34ba5340
7
+ data.tar.gz: f259d9fef544f4071733007277c672c16f95bbe0e7d303bc6bf52fa0d7fa7108dcf615d6502e7950d2b48e4ce720034cc2d23096d52bee6f03e7206eab02569b
@@ -13,7 +13,7 @@ jobs:
13
13
  runs-on: ubuntu-latest
14
14
  strategy:
15
15
  matrix:
16
- ruby: [ '2.5.8', '2.6.6', '2.7.1', 'ruby-head', 'jruby-9.2.11.1', 'jruby-head' ]
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.5.0
1
+ ## v1.6.1
2
2
 
3
- - Suggest require paths on LoadError ([#143](https://github.com/ruby/did_you_mean/pull/143))
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 [![Gem Version](https://badge.fury.io/rb/did_you_mean.svg)](https://rubygems.org/gems/did_you_mean) [![Build Status](https://travis-ci.org/ruby/did_you_mean.svg?branch=master)](https://travis-ci.org/ruby/did_you_mean)
1
+ # did_you_mean [![Gem Version](https://badge.fury.io/rb/did_you_mean.svg)](https://rubygems.org/gems/did_you_mean) [![Build status](https://github.com/ruby/did_you_mean/actions/workflows/ruby.yml/badge.svg)](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
- ## Verbose Formatter
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
- OBject
78
- # => NameError: uninitialized constant OBject
79
- # Did you mean? Object
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 applyoptions using the
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 charactor. Cannot be cannot be alphabetical, '@' or '.'.
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).super_method.call
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.end_with?(suggestion)
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
- SPELL_CHECKERS[self.class.to_s].new(self)
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
- # frozen-string-literal: true
1
+ require_relative '../formatter'
2
2
 
3
- module DidYouMean
4
- # The +DidYouMean::PlainFormatter+ 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 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
- # frozen-string-literal: true
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
- # Returns a human readable string that contains +corrections+. This
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
- output = "\n\n Did you mean? ".dup
45
- output << corrections.join("\n ")
46
- output << "\n "
47
- end
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
- input = normalize(input)
14
- threshold = input.length > 3 ? 0.834 : 0.77
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), input) >= threshold }
17
- words.reject! { |word| input == word.to_s }
18
- words.sort_by! { |word| JaroWinkler.distance(word.to_s, input) }
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 = (input.length * 0.25).ceil
23
- corrections = words.select { |c| Levenshtein.distance(normalize(c), input) <= threshold }
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 = input.length < word.length ? input.length : word.length
29
+ length = normalized_input.length < word.length ? normalized_input.length : word.length
30
30
 
31
- Levenshtein.distance(word, input) < length
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
- ENV_SPECIFIC_EXT = ".#{RbConfig::CONFIG["DLEXT"]}"
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
 
@@ -1,4 +1,2 @@
1
- require_relative '../did_you_mean'
2
- require_relative 'formatters/verbose_formatter'
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."
@@ -1,3 +1,3 @@
1
1
  module DidYouMean
2
- VERSION = "1.5.0"
2
+ VERSION = "1.6.1".freeze
3
3
  end
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/formatters/plain_formatter'
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
- SPELL_CHECKERS = Hash.new(NullChecker)
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
- SPELL_CHECKERS[error_class.name] = spell_checker
93
- error_class.prepend(Correctable) unless error_class < Correctable
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
- @@formatter
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
- @@formatter = formatter
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::SPELL_CHECKERS
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
- @org, SPELL_CHECKERS['NameError'] = SPELL_CHECKERS['NameError'], TestSpellChecker
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
- SPELL_CHECKERS['NameError'] = @org
19
+ DidYouMean.correct_error(NameError, @original_spell_checker)
19
20
  end
20
21
 
21
22
  def test_message
data/test/helper.rb CHANGED
@@ -4,6 +4,10 @@ module DidYouMean
4
4
  module TestHelper
5
5
  class << self
6
6
  attr_reader :root
7
+
8
+ def ractor_compatible?
9
+ defined?(Ractor) && RUBY_VERSION >= "3.1.0"
10
+ end
7
11
  end
8
12
 
9
13
  if File.file?(File.expand_path('../lib/did_you_mean.rb', __dir__))
@@ -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
@@ -10,6 +10,6 @@ class UncorrectableNameCheckTest < Test::Unit::TestCase
10
10
  end
11
11
 
12
12
  def test_message
13
- assert_equal "Other name error", @error.message
13
+ assert_not_match(/Did you mean\?/, @error.message)
14
14
  end
15
15
  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
@@ -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 test_deleletion
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.5.0
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: 2020-12-22 00:00:00.000000000 Z
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.1.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