Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Added NameError#receiver
MRI seems to handle this within C and doesn't define any way of setting
the receiver from Ruby. As a result of this we'll just use a keyword
argument.

Fixes #3607
  • Loading branch information
Yorick Peterse committed Feb 12, 2016
1 parent c700fb3 commit b372185
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 6 deletions.
16 changes: 13 additions & 3 deletions core/exception.rb
Expand Up @@ -237,18 +237,28 @@ class LocalJumpError < StandardError
class NameError < StandardError
attr_reader :name

def initialize(*args)
def initialize(*args, receiver: nil)
super(args.shift)

@name = args.shift
@receiver = receiver
end

def receiver
if @receiver
@receiver
else
raise ArgumentError, 'no receiver is available'
end
end
end

class NoMethodError < NameError
attr_reader :name
attr_reader :args

def initialize(*arguments)
super(arguments.shift)
def initialize(*arguments, **options)
super(arguments.shift, **options)
@name = arguments.shift
@args = arguments.shift
end
Expand Down
2 changes: 1 addition & 1 deletion core/zed.rb
Expand Up @@ -1367,7 +1367,7 @@ def method_missing(meth, *args)
msg << " on an instance of #{object_class}."
end

Kernel.raise cls.new(msg, meth, args)
Kernel.raise(cls.new(msg, meth, args, receiver: self))
end

private :method_missing
Expand Down
18 changes: 18 additions & 0 deletions spec/ruby/core/exception/name_error_spec.rb
Expand Up @@ -11,3 +11,21 @@
NameError.new("msg","name").name.should == "name"
end
end

describe 'NameError#receiver' do
it 'returns the receiver if available' do
x = 'foo'

begin
x.foo
rescue NameError => error
error.receiver.should == x
end
end

it 'raises ArgumentError when no receiver is available' do
error = NameError.new('msg', 'name')

proc { error.receiver }.should raise_error(ArgumentError)
end
end
12 changes: 10 additions & 2 deletions spec/ruby/language/send_spec.rb
Expand Up @@ -193,11 +193,19 @@ def foobar; 200; end
o.message.should == :not_there
o.args.should == [1,2]
end

it "raises NameError if invoked as a vcall" do
lambda { no_such_method }.should raise_error NameError
end


it 'adds the receiver to the raised exception' do
begin
no_such_method
rescue NameError => error
error.receiver.should == self
end
end

it "raises NoMethodError if invoked as an unambiguous method call" do
lambda { no_such_method() }.should raise_error NoMethodError
lambda { no_such_method(1,2,3) }.should raise_error NoMethodError
Expand Down
10 changes: 10 additions & 0 deletions spec/ruby/shared/kernel/method_missing.rb
Expand Up @@ -110,5 +110,15 @@
it "raises a NoMethodError when a private method is called" do
lambda { @object.new.method_private }.should raise_error(NoMethodError)
end

it 'sets the receiver of the raised NoMethodError' do
obj = @object.new

begin
obj.method_private
rescue NoMethodError => error
error.receiver.should == obj
end
end
end
end

0 comments on commit b372185

Please sign in to comment.