NoMethodError: неопределенный метод `RuntimeError ' - PullRequest
3 голосов
/ 22 апреля 2011

Я написал некоторый код в библиотеке Ruby (случайно используемый в Rails), который вызвал RuntimeError, как показано ниже:

class MyClass
  def initialize(opts = {})
     # do stuff
     thing = opts[:thing]
     raise RuntimeError "must have a thing!" unless thing.present? && thing.is_a?(Thing)
     # more stuff
  end
end

и когда я запустил над ним мою новую новую спецификацию rspec, которая выглядит примерно так:

it "should raise an error if we don't pass a thing" do
  lambda {
    my_class = MyClass.new(:thing => nil)
  }.should raise_exception(RuntimeError)
end

Я продолжал получать что-то странное:

expected RuntimeError, got 
#<NoMethodError: undefined method `RuntimeError' for #<MyClass:0xb5acbf9c>>

Ответы [ 3 ]

11 голосов
/ 22 апреля 2011

Вы, возможно, уже заметили проблему ... ах, односимвольные ошибки, донча любит их?

Вот оно.* RIGHT:

 raise RuntimeError, "must have a thing!" unless thing.present? && thing.is_a?(Thing)

конечно, вы также можете просто пойти дальше и полностью исключить RuntimeError:

 raise "must have a thing!" unless thing.present? && thing.is_a?(Thing)

, потому что это по умолчанию в любом случае ...

5 голосов
/ 22 апреля 2011

Вам не хватает запятой:

raise RuntimeError, "must have a thing!" unless thing.present? && thing.is_a?(Thing)
                  ^
1 голос
/ 22 апреля 2011

Просто добавим немного более подробного объяснения: в Ruby существует неоднозначность между ссылками на переменные и отправкой сообщений.

foo
Foo

Может или означать «разыменовать переменную с именем foo (или Fooили », отправив сообщение :foo (или :Foo) с пустым список аргументов для получателя по умолчанию ".

Эта неопределенность разрешается следующим образом:

  1. Если foo начинается со строчной буквы, предполагается, что это отправка сообщения, если только синтаксический анализатор не видел присвоение foo ранее, и в этом случае он обрабатывается как переменная разыменования. (Обратите внимание, что задание должно только проанализировано , не выполнено; if false then foo = nil end совершенно нормально.)
  2. Если Foo начинается с заглавной буквы, она обрабатывается как переменная (или скорее постоянная) разыменование, если только вы не передаете список аргументов (даже пустой), в этом случае он обрабатывается как отправка сообщения.

В этом случае RuntimeError обрабатывается как отправка сообщения, поскольку у него есть список аргументов: "must have a thing!". Это, конечно, из-за другой особенности Ruby, а именно, что она позволяет вам оставлять скобки вокруг списка аргументов, пока он однозначен.

IOW: все это интерпретируется примерно как

self.RuntimeError("must have a thing!")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...