#ruby #metaprogramming #eventmachine
#ruby #метапрограммирование #eventmachine
Вопрос:
Это немного сложно объяснить, но, похоже, мне иногда не удается переопределить метод ‘send’ в моем приложении. Я создаю довольно большое приложение на основе EventMachine и иногда, глубоко в недрах моего кода, я решаю определить метод ‘send’ в одном из моих классов. Когда я позже пытаюсь использовать этот метод, я обычно получаю исключение, которое выглядит примерно так TypeError: <parameter> is not a symbol
, например, следующее (случается, что оно вызвано требуемым AMQP gem (не моим), но этот вопрос более общий):
Exception caught: TypeError - #<AMQ::Protocol::MethodFrame:0x000001008434f0 @payload="x002x00x14x00x00x01atamq.topicx00x01x00x00x00x00", @channel=1> is not a symbol
/Users/mlartz/.rvm/gems/ruby-1.9.2-p180@rflow-component-devel/gems/amq-client-0.7.0.alpha27/lib/amq/client/queue.rb:137:in `bind'
/Users/mlartz/.rvm/gems/ruby-1.9.2-p180@rflow-component-devel/gems/amqp-0.8.0.rc12/lib/amqp/queue.rb:282:in `block in bind'
/Users/mlartz/.rvm/gems/ruby-1.9.2-p180@rflow-component-devel/gems/eventmachine-1.0.0.beta.3/lib/em/deferrable.rb:47:in `call'
/Users/mlartz/.rvm/gems/ruby-1.9.2-p180@rflow-component-devel/gems/eventmachine-1.0.0.beta.3/lib/em/deferrable.rb:47:in `callback'
Это некорректная строка:
@connection.send(Protocol::Queue::Bind.encode(@channel.id, @name, exchange_name, routing_key, nowait, arguments))
В этом конкретном случае класс @connection
объекта определил send
метод, который принимает AMQ::Protocol::MethodFrame
. Однако, похоже, что каким-то образом вызывается метод по умолчанию Object#send
(который ожидает символ, отсюда и исключение).
Ранее в процессе разработки у меня была такая же проблема с одним из моих пользовательских классов, которая была решена путем изменения имени моего метода ‘send’ на ‘send_message’.
Итак, поскольку это немного общий вопрос, вопрос в том, какие вещи могут помешать моей способности вызывать пользовательский send
метод для объекта, который его определил?
К вашему сведению: я использую Ruby 1.9.2p180 в OSX.
Комментарии:
1. Это происходит только в процессе разработки? Возможно ли, что проблема в перезагрузке класса, поскольку классы не кэшируются при разработке, если вы добавляете методы во время выполнения, класс может быть перезагружен без ваших вновь определенных методов?
2. Я не говорю, что рекомендую это, но вы могли бы
Object.class_eval { undef :send }
отменить определениеObject#send
. В тех случаях, когда он вам все еще нужен, он доступен какObject#__send__
.3. Стив, на данный момент у меня только разработка. Есть ли что-то, чего я не понимаю в Ruby, rvm, bundler, что выполняло бы перезагрузку класса без моего ведома, или я должен был бы четко указать на это?
4. И на самом деле, при воспроизведении кажется, что это может быть
nil
проблема с объектом, т. Е. если объект-получатель есть,nil
тогда он попытается выполнитьObject#send
. Так что, возможно, это было просто мое замешательство.5. @Майкл Л. Артс. В среде разработки классы не кэшируются и перезагружаются для каждого запроса. В производственных средах классы кэшируются, поэтому у вас нет накладных расходов на загрузку всех классов для каждого запроса. Это контролируется в файлах конфигурации среды путем изменения значения config.cache_classes
Ответ №1:
Не рекомендуется использовать или переопределять send
метод. Object.send — это очень простой метод в модуле ядра Ruby. Однажды у меня возникла серьезная проблема, когда я определял Message.send
класс, и в итоге я использовал другое имя, например Message.transmit
. В Ruby on Rails это зарезервированное слово.
Комментарии:
1. Примерно так я и думал. Я предполагаю, что симптомом этой проблемы является сбивающее с толку
TypeError
исключение, когда фактически существуетnil
объект receiver (nil
получаетsend
).