mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #39140 from Shopify/missing-name-corner-case
Make NameError#missing_name work even for real Ruby NameError
This commit is contained in:
commit
5ffccfad8b
4 changed files with 50 additions and 5 deletions
|
@ -88,7 +88,11 @@ class HelpersTypoControllerTest < ActiveSupport::TestCase
|
|||
def test_helper_typo_error_message
|
||||
e = assert_raise(NameError) { HelpersTypoController.helper "admin/users" }
|
||||
# This message is better if autoloading.
|
||||
assert_equal "uninitialized constant Admin::UsersHelper", e.message
|
||||
if RUBY_VERSION >= "2.6"
|
||||
assert_equal "uninitialized constant Admin::UsersHelper\nDid you mean? Admin::UsersHelpeR", e.message
|
||||
else
|
||||
assert_equal "uninitialized constant Admin::UsersHelper", e.message
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -14,9 +14,22 @@ class NameError
|
|||
# It extends NameError#message with spell corrections which are SLOW.
|
||||
# We should use original_message message instead.
|
||||
message = respond_to?(:original_message) ? original_message : self.message
|
||||
return unless message.start_with?("uninitialized constant ")
|
||||
|
||||
unless /undefined local variable or method/.match?(message)
|
||||
$1 if /((::)?([A-Z]\w*)(::[A-Z]\w*)*)$/ =~ message
|
||||
receiver = begin
|
||||
self.receiver
|
||||
rescue ArgumentError
|
||||
nil
|
||||
end
|
||||
|
||||
if receiver == Object
|
||||
name.to_s
|
||||
elsif receiver
|
||||
"#{real_mod_name(receiver)}::#{self.name}"
|
||||
else
|
||||
if match = message.match(/((::)?([A-Z]\w*)(::[A-Z]\w*)*)$/)
|
||||
match[1]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -35,4 +48,18 @@ class NameError
|
|||
missing_name == name.to_s
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
UNBOUND_METHOD_MODULE_NAME = Module.instance_method(:name)
|
||||
private_constant :UNBOUND_METHOD_MODULE_NAME
|
||||
|
||||
if UnboundMethod.method_defined?(:bind_call)
|
||||
def real_mod_name(mod)
|
||||
UNBOUND_METHOD_MODULE_NAME.bind_call(mod)
|
||||
end
|
||||
else
|
||||
def real_mod_name(mod)
|
||||
UNBOUND_METHOD_MODULE_NAME.bind(mod).call
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -592,8 +592,8 @@ module ActiveSupport #:nodoc:
|
|||
end
|
||||
end
|
||||
|
||||
name_error = NameError.new("uninitialized constant #{qualified_name}", const_name)
|
||||
name_error.set_backtrace(caller.reject { |l| l.start_with?(__FILE__) })
|
||||
name_error = uninitialized_constant(qualified_name, const_name, receiver: from_mod)
|
||||
name_error.set_backtrace(caller.reject { |l| l.start_with? __FILE__ })
|
||||
raise name_error
|
||||
end
|
||||
|
||||
|
@ -801,6 +801,16 @@ module ActiveSupport #:nodoc:
|
|||
end
|
||||
|
||||
private
|
||||
if RUBY_VERSION < "2.6"
|
||||
def uninitialized_constant(qualified_name, const_name, receiver:)
|
||||
NameError.new("uninitialized constant #{qualified_name}", const_name)
|
||||
end
|
||||
else
|
||||
def uninitialized_constant(qualified_name, const_name, receiver:)
|
||||
NameError.new("uninitialized constant #{qualified_name}", const_name, receiver: receiver)
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the original name of a class or module even if `name` has been
|
||||
# overridden.
|
||||
def real_mod_name(mod)
|
||||
|
|
|
@ -11,6 +11,9 @@ class NameErrorTest < ActiveSupport::TestCase
|
|||
assert_equal "NameErrorTest::SomeNameThatNobodyWillUse____Really", exc.missing_name
|
||||
assert exc.missing_name?(:SomeNameThatNobodyWillUse____Really)
|
||||
assert exc.missing_name?("NameErrorTest::SomeNameThatNobodyWillUse____Really")
|
||||
if RUBY_VERSION >= "2.6"
|
||||
assert_equal NameErrorTest, exc.receiver
|
||||
end
|
||||
end
|
||||
|
||||
def test_missing_method_should_ignore_missing_name
|
||||
|
@ -19,5 +22,6 @@ class NameErrorTest < ActiveSupport::TestCase
|
|||
end
|
||||
assert_not exc.missing_name?(:Foo)
|
||||
assert_nil exc.missing_name
|
||||
assert_equal self, exc.receiver
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue