Created
February 1, 2022 18:58
-
-
Save mame/2c34230f11237dc4af64510cb98acdd8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/lib/did_you_mean/core_ext/name_error.rb b/lib/did_you_mean/core_ext/name_error.rb | |
index eb3ef117a0..8c170c4b90 100644 | |
--- a/lib/did_you_mean/core_ext/name_error.rb | |
+++ b/lib/did_you_mean/core_ext/name_error.rb | |
@@ -1,24 +1,49 @@ | |
module DidYouMean | |
module Correctable | |
- SKIP_TO_S_FOR_SUPER_LOOKUP = true | |
- private_constant :SKIP_TO_S_FOR_SUPER_LOOKUP | |
+ if Exception.method_defined?(:detailed_message) | |
+ # just for compatibility | |
+ def original_message | |
+ # we cannot use alias here because | |
+ to_s | |
+ end | |
+ | |
+ def detailed_message(highlight: true, did_you_mean: true, **) | |
+ msg = super.dup | |
+ | |
+ return msg unless did_you_mean | |
+ | |
+ suggestion = DidYouMean.formatter.message_for(corrections) | |
+ | |
+ if highlight | |
+ suggestion = suggestion.gsub(/.+/) { "\e[1m" + $& + "\e[m" } | |
+ end | |
- def original_message | |
- meth = method(:to_s) | |
- while meth.owner.const_defined?(:SKIP_TO_S_FOR_SUPER_LOOKUP) | |
- meth = meth.super_method | |
+ msg << suggestion | |
+ msg | |
+ rescue | |
+ super | |
+ end | |
+ else | |
+ SKIP_TO_S_FOR_SUPER_LOOKUP = true | |
+ private_constant :SKIP_TO_S_FOR_SUPER_LOOKUP | |
+ | |
+ def original_message | |
+ meth = method(:to_s) | |
+ while meth.owner.const_defined?(:SKIP_TO_S_FOR_SUPER_LOOKUP) | |
+ meth = meth.super_method | |
+ end | |
+ meth.call | |
end | |
- meth.call | |
- end | |
- def to_s | |
- msg = super.dup | |
- suggestion = DidYouMean.formatter.message_for(corrections) | |
+ def to_s | |
+ msg = super.dup | |
+ suggestion = DidYouMean.formatter.message_for(corrections) | |
- msg << suggestion if !msg.include?(suggestion) | |
- msg | |
- rescue | |
- super | |
+ msg << suggestion if !msg.include?(suggestion) | |
+ msg | |
+ rescue | |
+ super | |
+ end | |
end | |
def corrections | |
diff --git a/lib/error_highlight/core_ext.rb b/lib/error_highlight/core_ext.rb | |
index 78cda8ace2..166e9617d8 100644 | |
--- a/lib/error_highlight/core_ext.rb | |
+++ b/lib/error_highlight/core_ext.rb | |
@@ -8,14 +8,13 @@ module CoreExt | |
SKIP_TO_S_FOR_SUPER_LOOKUP = true | |
private_constant :SKIP_TO_S_FOR_SUPER_LOOKUP | |
- def to_s | |
- msg = super.dup | |
- | |
+ private def generate_snippet | |
locs = backtrace_locations | |
- return msg unless locs | |
+ return "" unless locs | |
loc = locs.first | |
- return msg unless loc | |
+ return "" unless loc | |
+ | |
begin | |
node = RubyVM::AbstractSyntaxTree.of(loc, keep_script_lines: true) | |
opts = {} | |
@@ -36,11 +35,31 @@ def to_s | |
end | |
if spot | |
- points = ErrorHighlight.formatter.message_for(spot) | |
- msg << points if !msg.include?(points) | |
+ return ErrorHighlight.formatter.message_for(spot) | |
end | |
- msg | |
+ "" | |
+ end | |
+ | |
+ if Exception.method_defined?(:detailed_message) | |
+ def detailed_message(highlight: false, error_highlight: true, **) | |
+ return super unless error_highlight | |
+ snippet = generate_snippet | |
+ if highlight | |
+ snippet = snippet.gsub(/.+/) { "\e[1m" + $& + "\e[m" } | |
+ end | |
+ super + snippet | |
+ end | |
+ else | |
+ def to_s | |
+ msg = super | |
+ snippet = generate_snippet | |
+ if snippet != "" && !msg.include?(snippet) | |
+ msg + snippet | |
+ else | |
+ msg | |
+ end | |
+ end | |
end | |
end | |
diff --git a/test/did_you_mean/core_ext/test_name_error_extension.rb b/test/did_you_mean/core_ext/test_name_error_extension.rb | |
index 91871cda9a..1fdbd4510f 100644 | |
--- a/test/did_you_mean/core_ext/test_name_error_extension.rb | |
+++ b/test/did_you_mean/core_ext/test_name_error_extension.rb | |
@@ -1,6 +1,8 @@ | |
require_relative '../helper' | |
class NameErrorExtensionTest < Test::Unit::TestCase | |
+ include DidYouMean::TestHelper | |
+ | |
SPELL_CHECKERS = DidYouMean.spell_checkers | |
class TestSpellChecker | |
@@ -20,8 +22,12 @@ def teardown | |
end | |
def test_message | |
- assert_match(/Did you mean\? does_exist/, @error.to_s) | |
- assert_match(/Did you mean\? does_exist/, @error.message) | |
+ if Exception.method_defined?(:detailed_message) | |
+ assert_match(/Did you mean\? does_exist/, @error.detailed_message) | |
+ else | |
+ assert_match(/Did you mean\? does_exist/, @error.to_s) | |
+ assert_match(/Did you mean\? does_exist/, @error.message) | |
+ end | |
end | |
def test_to_s_does_not_make_disruptive_changes_to_error_message | |
@@ -29,8 +35,8 @@ def test_to_s_does_not_make_disruptive_changes_to_error_message | |
raise NameError, "uninitialized constant Object" | |
end | |
- error.to_s | |
- assert_equal 1, error.to_s.scan("Did you mean?").count | |
+ get_message(error) | |
+ assert_equal 1, get_message(error).scan("Did you mean?").count | |
end | |
def test_correctable_error_objects_are_dumpable | |
@@ -41,7 +47,7 @@ def test_correctable_error_objects_are_dumpable | |
e | |
end | |
- error.to_s | |
+ get_message(error) | |
assert_equal "undefined method `sizee' for #<File:test_name_error_extension.rb (closed)>", | |
Marshal.load(Marshal.dump(error)).original_message | |
diff --git a/test/did_you_mean/helper.rb b/test/did_you_mean/helper.rb | |
index 7cb7b10282..d40d58d95d 100644 | |
--- a/test/did_you_mean/helper.rb | |
+++ b/test/did_you_mean/helper.rb | |
@@ -29,5 +29,15 @@ def ractor_compatible? | |
def assert_correction(expected, array) | |
assert_equal Array(expected), array, "Expected #{array.inspect} to only include #{expected.inspect}" | |
end | |
+ | |
+ def get_message(err) | |
+ if err.respond_to?(:detailed_message) | |
+ err.detailed_message(highlight: false) | |
+ else | |
+ err.to_s | |
+ end | |
+ end | |
+ | |
+ module_function :get_message | |
end | |
end | |
diff --git a/test/did_you_mean/spell_checking/test_key_name_check.rb b/test/did_you_mean/spell_checking/test_key_name_check.rb | |
index ea05ff69e4..2f246f04d7 100644 | |
--- a/test/did_you_mean/spell_checking/test_key_name_check.rb | |
+++ b/test/did_you_mean/spell_checking/test_key_name_check.rb | |
@@ -8,11 +8,11 @@ def test_corrects_hash_key_name_with_fetch | |
error = assert_raise(KeyError) { hash.fetch(:bax) } | |
assert_correction ":bar", error.corrections | |
- assert_match "Did you mean? :bar", error.to_s | |
+ assert_match "Did you mean? :bar", get_message(error) | |
error = assert_raise(KeyError) { hash.fetch("fooo") } | |
assert_correction %("foo"), error.corrections | |
- assert_match %(Did you mean? "foo"), error.to_s | |
+ assert_match %(Did you mean? "foo"), get_message(error) | |
end | |
def test_corrects_hash_key_name_with_fetch_values | |
@@ -20,11 +20,11 @@ def test_corrects_hash_key_name_with_fetch_values | |
error = assert_raise(KeyError) { hash.fetch_values("foo", :bar, :bax) } | |
assert_correction ":bar", error.corrections | |
- assert_match "Did you mean? :bar", error.to_s | |
+ assert_match "Did you mean? :bar", get_message(error) | |
error = assert_raise(KeyError) { hash.fetch_values("foo", :bar, "fooo") } | |
assert_correction %("foo"), error.corrections | |
- assert_match %(Did you mean? "foo"), error.to_s | |
+ assert_match %(Did you mean? "foo"), get_message(error) | |
end | |
def test_correct_symbolized_hash_keys_with_string_value | |
@@ -32,13 +32,13 @@ def test_correct_symbolized_hash_keys_with_string_value | |
error = assert_raise(KeyError) { hash.fetch('foo_1') } | |
assert_correction %(:foo_1), error.corrections | |
- assert_match %(Did you mean? :foo_1), error.to_s | |
+ assert_match %(Did you mean? :foo_1), get_message(error) | |
end | |
def test_corrects_sprintf_key_name | |
error = assert_raise(KeyError) { sprintf("%<foo>d", {fooo: 1}) } | |
assert_correction ":fooo", error.corrections | |
- assert_match "Did you mean? :fooo", error.to_s | |
+ assert_match "Did you mean? :fooo", get_message(error) | |
end | |
def test_corrects_env_key_name | |
@@ -46,7 +46,7 @@ def test_corrects_env_key_name | |
ENV["BAR"] = "2" | |
error = assert_raise(KeyError) { ENV.fetch("BAX") } | |
assert_correction %("BAR"), error.corrections | |
- assert_match %(Did you mean? "BAR"), error.to_s | |
+ assert_match %(Did you mean? "BAR"), get_message(error) | |
ensure | |
ENV.delete("FOO") | |
ENV.delete("BAR") | |
diff --git a/test/did_you_mean/spell_checking/test_method_name_check.rb b/test/did_you_mean/spell_checking/test_method_name_check.rb | |
index 6e14e6acc4..d2e46d58f3 100644 | |
--- a/test/did_you_mean/spell_checking/test_method_name_check.rb | |
+++ b/test/did_you_mean/spell_checking/test_method_name_check.rb | |
@@ -41,28 +41,28 @@ def test_corrections_include_instance_method | |
error = assert_raise(NoMethodError){ @user.flrst_name } | |
assert_correction :first_name, error.corrections | |
- assert_match "Did you mean? first_name", error.to_s | |
+ assert_match "Did you mean? first_name", get_message(error) | |
end | |
def test_corrections_include_private_method | |
error = assert_raise(NoMethodError){ @user.friend } | |
assert_correction :friends, error.corrections | |
- assert_match "Did you mean? friends", error.to_s | |
+ assert_match "Did you mean? friends", get_message(error) | |
end | |
def test_corrections_include_method_from_module | |
error = assert_raise(NoMethodError){ @user.fr0m_module } | |
assert_correction :from_module, error.corrections | |
- assert_match "Did you mean? from_module", error.to_s | |
+ assert_match "Did you mean? from_module", get_message(error) | |
end | |
def test_corrections_include_class_method | |
error = assert_raise(NoMethodError){ User.l0ad } | |
assert_correction :load, error.corrections | |
- assert_match "Did you mean? load", error.to_s | |
+ assert_match "Did you mean? load", get_message(error) | |
end | |
def test_private_methods_should_not_be_suggested | |
@@ -77,7 +77,7 @@ def test_corrections_when_private_method_is_called_with_args | |
error = assert_raise(NoMethodError){ @user.call_incorrect_private_method } | |
assert_correction :raise, error.corrections | |
- assert_match "Did you mean? raise", error.to_s | |
+ assert_match "Did you mean? raise", get_message(error) | |
end | |
def test_exclude_methods_on_nil | |
@@ -104,7 +104,7 @@ def test_does_not_append_suggestions_twice | |
end | |
end | |
- assert_equal 1, error.to_s.scan(/Did you mean/).count | |
+ assert_equal 1, get_message(error).scan(/Did you mean/).count | |
end | |
def test_does_not_append_suggestions_three_times | |
@@ -116,7 +116,7 @@ def test_does_not_append_suggestions_three_times | |
end | |
end | |
- assert_equal 1, error.to_s.scan(/Did you mean/).count | |
+ assert_equal 1, get_message(error).scan(/Did you mean/).count | |
end | |
def test_suggests_corrections_on_nested_error | |
@@ -128,20 +128,20 @@ def test_suggests_corrections_on_nested_error | |
end | |
end | |
- assert_equal 1, error.to_s.scan(/Did you mean/).count | |
+ assert_equal 1, get_message(error).scan(/Did you mean/).count | |
end | |
def test_suggests_yield | |
error = assert_raise(NoMethodError) { yeild(1) } | |
assert_correction :yield, error.corrections | |
- assert_match "Did you mean? yield", error.to_s | |
+ assert_match "Did you mean? yield", get_message(error) | |
end | |
def test_does_not_suggest_yield | |
error = assert_raise(NoMethodError) { 1.yeild } | |
assert_correction [], error.corrections | |
- assert_not_match(/Did you mean\? +yield/, error.to_s) | |
+ assert_not_match(/Did you mean\? +yield/, get_message(error)) | |
end if RUBY_ENGINE != "jruby" | |
end | |
diff --git a/test/did_you_mean/spell_checking/test_pattern_key_name_check.rb b/test/did_you_mean/spell_checking/test_pattern_key_name_check.rb | |
index 2b0752a56a..10f973802b 100644 | |
--- a/test/did_you_mean/spell_checking/test_pattern_key_name_check.rb | |
+++ b/test/did_you_mean/spell_checking/test_pattern_key_name_check.rb | |
@@ -15,6 +15,6 @@ def test_corrects_hash_key_name_with_single_pattern_match | |
end | |
assert_correction ":foo", error.corrections | |
- assert_match "Did you mean? :foo", error.to_s | |
+ assert_match "Did you mean? :foo", get_message(error) | |
end | |
end | |
diff --git a/test/did_you_mean/spell_checking/test_require_path_check.rb b/test/did_you_mean/spell_checking/test_require_path_check.rb | |
index f67fab0568..d6c06e9999 100644 | |
--- a/test/did_you_mean/spell_checking/test_require_path_check.rb | |
+++ b/test/did_you_mean/spell_checking/test_require_path_check.rb | |
@@ -11,7 +11,7 @@ def test_load_error_from_require_has_suggestions | |
end | |
assert_correction 'ostruct', error.corrections | |
- assert_match "Did you mean? ostruct", error.to_s | |
+ assert_match "Did you mean? ostruct", get_message(error) | |
end | |
def test_load_error_from_require_for_nested_files_has_suggestions | |
@@ -20,13 +20,13 @@ def test_load_error_from_require_for_nested_files_has_suggestions | |
end | |
assert_correction 'net/http', error.corrections | |
- assert_match "Did you mean? net/http", error.to_s | |
+ assert_match "Did you mean? net/http", get_message(error) | |
error = assert_raise LoadError do | |
require 'net-http' | |
end | |
assert_correction ['net/http', 'net/https'], error.corrections | |
- assert_match "Did you mean? net/http", error.to_s | |
+ assert_match "Did you mean? net/http", get_message(error) | |
end | |
end | |
diff --git a/test/did_you_mean/spell_checking/test_variable_name_check.rb b/test/did_you_mean/spell_checking/test_variable_name_check.rb | |
index 193e2b7520..9d8b86eb5b 100644 | |
--- a/test/did_you_mean/spell_checking/test_variable_name_check.rb | |
+++ b/test/did_you_mean/spell_checking/test_variable_name_check.rb | |
@@ -39,7 +39,7 @@ def test_corrections_include_instance_method | |
end | |
assert_correction :first_name, error.corrections | |
- assert_match "Did you mean? first_name", error.to_s | |
+ assert_match "Did you mean? first_name", get_message(error) | |
end | |
def test_corrections_include_method_from_module | |
@@ -48,7 +48,7 @@ def test_corrections_include_method_from_module | |
end | |
assert_correction :from_module, error.corrections | |
- assert_match "Did you mean? from_module", error.to_s | |
+ assert_match "Did you mean? from_module", get_message(error) | |
end | |
def test_corrections_include_local_variable_name | |
@@ -57,7 +57,7 @@ def test_corrections_include_local_variable_name | |
error = (eprson rescue $!) # Do not use @assert_raise here as it changes a scope. | |
assert_correction :person, error.corrections | |
- assert_match "Did you mean? person", error.to_s | |
+ assert_match "Did you mean? person", get_message(error) | |
end | |
end | |
@@ -81,30 +81,30 @@ def test_corrections_include_ruby_predefined_objects | |
end | |
assert_correction :false, false_error.corrections | |
- assert_match "Did you mean? false", false_error.to_s | |
+ assert_match "Did you mean? false", get_message(false_error) | |
assert_correction :true, true_error.corrections | |
- assert_match "Did you mean? true", true_error.to_s | |
+ assert_match "Did you mean? true", get_message(true_error) | |
assert_correction :nil, nil_error.corrections | |
- assert_match "Did you mean? nil", nil_error.to_s | |
+ assert_match "Did you mean? nil", get_message(nil_error) | |
assert_correction :__FILE__, file_error.corrections | |
- assert_match "Did you mean? __FILE__", file_error.to_s | |
+ assert_match "Did you mean? __FILE__", get_message(file_error) | |
end | |
def test_suggests_yield | |
error = assert_raise(NameError) { yeild } | |
assert_correction :yield, error.corrections | |
- assert_match "Did you mean? yield", error.to_s | |
+ assert_match "Did you mean? yield", get_message(error) | |
end | |
def test_corrections_include_instance_variable_name | |
error = assert_raise(NameError){ @user.to_s } | |
assert_correction :@email_address, error.corrections | |
- assert_match "Did you mean? @email_address", error.to_s | |
+ assert_match "Did you mean? @email_address", get_message(error) | |
end | |
def test_corrections_include_private_method | |
@@ -113,7 +113,7 @@ def test_corrections_include_private_method | |
end | |
assert_correction :cia_codename, error.corrections | |
- assert_match "Did you mean? cia_codename", error.to_s | |
+ assert_match "Did you mean? cia_codename", get_message(error) | |
end | |
@@does_exist = true | |
@@ -122,7 +122,7 @@ def test_corrections_include_class_variable_name | |
error = assert_raise(NameError){ @@doesnt_exist } | |
assert_correction :@@does_exist, error.corrections | |
- assert_match "Did you mean? @@does_exist", error.to_s | |
+ assert_match "Did you mean? @@does_exist", get_message(error) | |
end | |
def test_struct_name_error | |
@@ -130,7 +130,7 @@ def test_struct_name_error | |
error = assert_raise(NameError){ value[:doesnt_exist] } | |
assert_correction [:does_exist, :does_exist=], error.corrections | |
- assert_match "Did you mean? does_exist", error.to_s | |
+ assert_match "Did you mean? does_exist", get_message(error) | |
end | |
def test_exclude_typical_incorrect_suggestions | |
diff --git a/test/error_highlight/test_error_highlight.rb b/test/error_highlight/test_error_highlight.rb | |
index a3cc7aa149..5b7c05e5f4 100644 | |
--- a/test/error_highlight/test_error_highlight.rb | |
+++ b/test/error_highlight/test_error_highlight.rb | |
@@ -23,9 +23,16 @@ def teardown | |
end | |
end | |
- def assert_error_message(klass, expected_msg, &blk) | |
- err = assert_raise(klass, &blk) | |
- assert_equal(expected_msg.chomp, err.message) | |
+ if Exception.method_defined?(:detailed_message) | |
+ def assert_error_message(klass, expected_msg, &blk) | |
+ err = assert_raise(klass, &blk) | |
+ assert_equal(expected_msg.chomp, err.detailed_message(highlight: false).sub(/ \((?:NoMethod|Name)Error\)/, "")) | |
+ end | |
+ else | |
+ def assert_error_message(klass, expected_msg, &blk) | |
+ err = assert_raise(klass, &blk) | |
+ assert_equal(expected_msg.chomp, err.message) | |
+ end | |
end | |
def test_CALL_noarg_1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment