mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* gems/default_gems: Sync did_you_mean
This commit is contained in:
parent
fdf3996349
commit
ac4e0978ee
10 changed files with 171 additions and 14 deletions
|
@ -86,12 +86,25 @@ require_relative 'did_you_mean/tree_spell_checker'
|
||||||
#
|
#
|
||||||
module DidYouMean
|
module DidYouMean
|
||||||
# Map of error types and spell checker objects.
|
# Map of error types and spell checker objects.
|
||||||
SPELL_CHECKERS = Hash.new(NullChecker)
|
@spell_checkers = Hash.new(NullChecker)
|
||||||
|
|
||||||
|
# Returns a sharable hash map of error types and spell checker objects.
|
||||||
|
def self.spell_checkers
|
||||||
|
@spell_checkers
|
||||||
|
end
|
||||||
|
|
||||||
# Adds +DidYouMean+ functionality to an error using a given spell checker
|
# Adds +DidYouMean+ functionality to an error using a given spell checker
|
||||||
def self.correct_error(error_class, spell_checker)
|
def self.correct_error(error_class, spell_checker)
|
||||||
SPELL_CHECKERS[error_class.name] = spell_checker
|
if defined?(Ractor)
|
||||||
error_class.prepend(Correctable) unless error_class < Correctable
|
new_mapping = { **@spell_checkers, error_class.to_s => spell_checker }
|
||||||
|
new_mapping.default = NullChecker
|
||||||
|
|
||||||
|
@spell_checkers = Ractor.make_shareable(new_mapping)
|
||||||
|
else
|
||||||
|
spell_checkers[error_class.to_s] = spell_checker
|
||||||
|
end
|
||||||
|
|
||||||
|
error_class.prepend(Correctable) if error_class.is_a?(Class) && !(error_class < Correctable)
|
||||||
end
|
end
|
||||||
|
|
||||||
correct_error NameError, NameErrorCheckers
|
correct_error NameError, NameErrorCheckers
|
||||||
|
@ -100,15 +113,43 @@ module DidYouMean
|
||||||
correct_error LoadError, RequirePathChecker if RUBY_VERSION >= '2.8.0'
|
correct_error LoadError, RequirePathChecker if RUBY_VERSION >= '2.8.0'
|
||||||
correct_error NoMatchingPatternKeyError, PatternKeyNameChecker if defined?(::NoMatchingPatternKeyError)
|
correct_error NoMatchingPatternKeyError, PatternKeyNameChecker if defined?(::NoMatchingPatternKeyError)
|
||||||
|
|
||||||
|
# TODO: Remove on 3.3:
|
||||||
|
class DeprecatedMapping # :nodoc:
|
||||||
|
def []=(key, value)
|
||||||
|
warn "Calling `DidYouMean::SPELL_CHECKERS[#{key.to_s}] = #{value.to_s}' has been deprecated. " \
|
||||||
|
"Please call `DidYouMean.correct_error(#{key.to_s}, #{value.to_s})' instead."
|
||||||
|
|
||||||
|
DidYouMean.correct_error(key, value)
|
||||||
|
end
|
||||||
|
|
||||||
|
def merge!(hash)
|
||||||
|
warn "Calling `DidYouMean::SPELL_CHECKERS.merge!(error_name => spell_checker)' has been deprecated. " \
|
||||||
|
"Please call `DidYouMean.correct_error(error_name, spell_checker)' instead."
|
||||||
|
|
||||||
|
hash.each do |error_class, spell_checker|
|
||||||
|
DidYouMean.correct_error(error_class, spell_checker)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# TODO: Remove on 3.3:
|
||||||
|
SPELL_CHECKERS = DeprecatedMapping.new
|
||||||
|
deprecate_constant :SPELL_CHECKERS
|
||||||
|
private_constant :DeprecatedMapping
|
||||||
|
|
||||||
# Returns the currently set formatter. By default, it is set to +DidYouMean::Formatter+.
|
# Returns the currently set formatter. By default, it is set to +DidYouMean::Formatter+.
|
||||||
def self.formatter
|
def self.formatter
|
||||||
@formatter
|
if defined?(Reactor)
|
||||||
|
Ractor.current[:__did_you_mean_formatter__] || Formatter
|
||||||
|
else
|
||||||
|
Formatter
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Updates the primary formatter used to format the suggestions.
|
# Updates the primary formatter used to format the suggestions.
|
||||||
def self.formatter=(formatter)
|
def self.formatter=(formatter)
|
||||||
@formatter = formatter
|
if defined?(Reactor)
|
||||||
|
Ractor.current[:__did_you_mean_formatter__] = formatter
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@formatter = Formatter.new
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -26,7 +26,7 @@ module DidYouMean
|
||||||
end
|
end
|
||||||
|
|
||||||
def spell_checker
|
def spell_checker
|
||||||
SPELL_CHECKERS[self.class.to_s].new(self)
|
DidYouMean.spell_checkers[self.class.to_s].new(self)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -26,7 +26,7 @@ module DidYouMean
|
||||||
#
|
#
|
||||||
# # => nil
|
# # => nil
|
||||||
#
|
#
|
||||||
def message_for(corrections)
|
def self.message_for(corrections)
|
||||||
corrections.empty? ? "" : "\nDid you mean? #{corrections.join("\n ")}"
|
corrections.empty? ? "" : "\nDid you mean? #{corrections.join("\n ")}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,6 +6,7 @@ module DidYouMean
|
||||||
|
|
||||||
NAMES_TO_EXCLUDE = { NilClass => nil.methods }
|
NAMES_TO_EXCLUDE = { NilClass => nil.methods }
|
||||||
NAMES_TO_EXCLUDE.default = []
|
NAMES_TO_EXCLUDE.default = []
|
||||||
|
Ractor.make_shareable(NAMES_TO_EXCLUDE) if defined?(Ractor)
|
||||||
|
|
||||||
# +MethodNameChecker::RB_RESERVED_WORDS+ is the list of reserved words in
|
# +MethodNameChecker::RB_RESERVED_WORDS+ is the list of reserved words in
|
||||||
# Ruby that take an argument. Unlike
|
# Ruby that take an argument. Unlike
|
||||||
|
@ -36,6 +37,8 @@ module DidYouMean
|
||||||
yield
|
yield
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Ractor.make_shareable(RB_RESERVED_WORDS) if defined?(Ractor)
|
||||||
|
|
||||||
def initialize(exception)
|
def initialize(exception)
|
||||||
@method_name = exception.name
|
@method_name = exception.name
|
||||||
@receiver = exception.receiver
|
@receiver = exception.receiver
|
||||||
|
|
|
@ -8,6 +8,7 @@ module DidYouMean
|
||||||
|
|
||||||
NAMES_TO_EXCLUDE = { 'foo' => [:fork, :for] }
|
NAMES_TO_EXCLUDE = { 'foo' => [:fork, :for] }
|
||||||
NAMES_TO_EXCLUDE.default = []
|
NAMES_TO_EXCLUDE.default = []
|
||||||
|
Ractor.make_shareable(NAMES_TO_EXCLUDE) if defined?(Ractor)
|
||||||
|
|
||||||
# +VariableNameChecker::RB_RESERVED_WORDS+ is the list of all reserved
|
# +VariableNameChecker::RB_RESERVED_WORDS+ is the list of all reserved
|
||||||
# words in Ruby. They could be declared like methods are, and a typo would
|
# words in Ruby. They could be declared like methods are, and a typo would
|
||||||
|
@ -62,6 +63,8 @@ module DidYouMean
|
||||||
__ENCODING__
|
__ENCODING__
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Ractor.make_shareable(RB_RESERVED_WORDS) if defined?(Ractor)
|
||||||
|
|
||||||
def initialize(exception)
|
def initialize(exception)
|
||||||
@name = exception.name.to_s.tr("@", "")
|
@name = exception.name.to_s.tr("@", "")
|
||||||
@lvar_names = exception.respond_to?(:local_variables) ? exception.local_variables : []
|
@lvar_names = exception.respond_to?(:local_variables) ? exception.local_variables : []
|
||||||
|
|
|
@ -9,7 +9,10 @@ module DidYouMean
|
||||||
attr_reader :path
|
attr_reader :path
|
||||||
|
|
||||||
INITIAL_LOAD_PATH = $LOAD_PATH.dup.freeze
|
INITIAL_LOAD_PATH = $LOAD_PATH.dup.freeze
|
||||||
|
Ractor.make_shareable(INITIAL_LOAD_PATH) if defined?(Ractor)
|
||||||
|
|
||||||
ENV_SPECIFIC_EXT = ".#{RbConfig::CONFIG["DLEXT"]}"
|
ENV_SPECIFIC_EXT = ".#{RbConfig::CONFIG["DLEXT"]}"
|
||||||
|
Ractor.make_shareable(ENV_SPECIFIC_EXT) if defined?(Ractor)
|
||||||
|
|
||||||
private_constant :INITIAL_LOAD_PATH, :ENV_SPECIFIC_EXT
|
private_constant :INITIAL_LOAD_PATH, :ENV_SPECIFIC_EXT
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
module DidYouMean
|
module DidYouMean
|
||||||
VERSION = "1.6.0-alpha"
|
VERSION = "1.6.1-alpha".freeze
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
require_relative '../helper'
|
require_relative '../helper'
|
||||||
|
|
||||||
class NameErrorExtensionTest < Test::Unit::TestCase
|
class NameErrorExtensionTest < Test::Unit::TestCase
|
||||||
SPELL_CHECKERS = DidYouMean::SPELL_CHECKERS
|
SPELL_CHECKERS = DidYouMean.spell_checkers
|
||||||
|
|
||||||
class TestSpellChecker
|
class TestSpellChecker
|
||||||
def initialize(*); end
|
def initialize(*); end
|
||||||
|
@ -9,13 +9,14 @@ class NameErrorExtensionTest < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def setup
|
def setup
|
||||||
@org, SPELL_CHECKERS['NameError'] = SPELL_CHECKERS['NameError'], TestSpellChecker
|
@original_spell_checker = DidYouMean.spell_checkers['NameError']
|
||||||
|
DidYouMean.correct_error(NameError, TestSpellChecker)
|
||||||
|
|
||||||
@error = assert_raise(NameError){ doesnt_exist }
|
@error = assert_raise(NameError){ doesnt_exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
def teardown
|
def teardown
|
||||||
SPELL_CHECKERS['NameError'] = @org
|
DidYouMean.correct_error(NameError, @original_spell_checker)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_message
|
def test_message
|
||||||
|
|
|
@ -4,6 +4,10 @@ module DidYouMean
|
||||||
module TestHelper
|
module TestHelper
|
||||||
class << self
|
class << self
|
||||||
attr_reader :root
|
attr_reader :root
|
||||||
|
|
||||||
|
def ractor_compatible?
|
||||||
|
defined?(Ractor) && RUBY_VERSION >= "3.1.0"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if File.file?(File.expand_path('../lib/did_you_mean.rb', __dir__))
|
if File.file?(File.expand_path('../lib/did_you_mean.rb', __dir__))
|
||||||
|
|
102
test/did_you_mean/test_ractor_compatibility.rb
Normal file
102
test/did_you_mean/test_ractor_compatibility.rb
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
require_relative './helper'
|
||||||
|
|
||||||
|
return if not DidYouMean::TestHelper.ractor_compatible?
|
||||||
|
|
||||||
|
class RactorCompatibilityTest < Test::Unit::TestCase
|
||||||
|
include DidYouMean::TestHelper
|
||||||
|
|
||||||
|
class ::Book; end
|
||||||
|
class FirstNameError < NameError; end
|
||||||
|
|
||||||
|
def test_class_name_suggestion_works_in_ractor
|
||||||
|
error = Ractor.new {
|
||||||
|
begin
|
||||||
|
Boook
|
||||||
|
rescue NameError => e
|
||||||
|
e.corrections # It is important to call the #corrections method within Ractor.
|
||||||
|
e
|
||||||
|
end
|
||||||
|
}.take
|
||||||
|
|
||||||
|
assert_correction "Book", error.corrections
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_key_name_suggestion_works_in_ractor
|
||||||
|
error = Ractor.new {
|
||||||
|
begin
|
||||||
|
hash = { "foo" => 1, bar: 2 }
|
||||||
|
|
||||||
|
hash.fetch(:bax)
|
||||||
|
rescue KeyError => e
|
||||||
|
e.corrections # It is important to call the #corrections method within Ractor.
|
||||||
|
e
|
||||||
|
end
|
||||||
|
}.take
|
||||||
|
|
||||||
|
assert_correction ":bar", error.corrections
|
||||||
|
assert_match "Did you mean? :bar", error.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_method_name_suggestion_works_in_ractor
|
||||||
|
error = Ractor.new {
|
||||||
|
begin
|
||||||
|
self.to__s
|
||||||
|
rescue NoMethodError => e
|
||||||
|
e.corrections # It is important to call the #corrections method within Ractor.
|
||||||
|
e
|
||||||
|
end
|
||||||
|
}.take
|
||||||
|
|
||||||
|
assert_correction :to_s, error.corrections
|
||||||
|
assert_match "Did you mean? to_s", error.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
if defined?(::NoMatchingPatternKeyError)
|
||||||
|
def test_pattern_key_name_suggestion_works_in_ractor
|
||||||
|
error = Ractor.new {
|
||||||
|
begin
|
||||||
|
eval(<<~RUBY, binding, __FILE__, __LINE__)
|
||||||
|
hash = {foo: 1, bar: 2, baz: 3}
|
||||||
|
hash => {fooo:}
|
||||||
|
fooo = 1 # suppress "unused variable: fooo" warning
|
||||||
|
RUBY
|
||||||
|
rescue NoMatchingPatternKeyError => e
|
||||||
|
e.corrections # It is important to call the #corrections method within Ractor.
|
||||||
|
e
|
||||||
|
end
|
||||||
|
}.take
|
||||||
|
|
||||||
|
assert_correction ":foo", error.corrections
|
||||||
|
assert_match "Did you mean? :foo", error.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_can_raise_other_name_error_in_ractor
|
||||||
|
error = Ractor.new {
|
||||||
|
begin
|
||||||
|
raise FirstNameError, "Other name error"
|
||||||
|
rescue FirstNameError => e
|
||||||
|
e.corrections # It is important to call the #corrections method within Ractor.
|
||||||
|
e
|
||||||
|
end
|
||||||
|
}.take
|
||||||
|
|
||||||
|
assert_not_match(/Did you mean\?/, error.message)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_variable_name_suggestion_works_in_ractor
|
||||||
|
error = Ractor.new {
|
||||||
|
in_ractor = in_ractor = 1
|
||||||
|
|
||||||
|
begin
|
||||||
|
in_reactor
|
||||||
|
rescue NameError => e
|
||||||
|
e.corrections # It is important to call the #corrections method within Ractor.
|
||||||
|
e
|
||||||
|
end
|
||||||
|
}.take
|
||||||
|
|
||||||
|
assert_correction :in_ractor, error.corrections
|
||||||
|
assert_match "Did you mean? in_ractor", error.to_s
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue