2016-10-12 2 views
1

Я помню, как просматривал рубиновый скринкаст от Дейва Томаса об использовании метапрограммирования для создания имен методов, которым не нужно придерживаться требований синтаксиса идентификатора. Как правило, идентификатор не должен содержать пробелов. И он показал, как создавать методы с пробелами. Но я не помню, как это делается.Ruby: Обращайтесь с произвольными именами методов

У меня есть произвольные имена полей для класса, которые include s Mongoid :: Document. Это отлично работает, где _field может быть строкой типа «Hello World»:

MyClass.class_eval <<-EOS 
    field :'#{ _field }', type: #{_type} 
EOS 

Я хочу переопределить сеттер. Так что я попытался это:

MyClass.class_eval <<-EOS 
    field :'#{ _field }', type: #{_type} 
    def #{ _field }=(val) 
    self['#{ _field }'] = [self.send('#{ _field }')[0], val] 
    end 
EOS 

К сожалению, если _field это строка, как «Hello World», я получаю сообщение об ошибке:

SyntaxError: (eval):2: formal argument cannot be a constant 
      def Hello World=(val) 

Как я могу обойти это?

+0

Просто потому, что свойство называется «Hello World» внутри MongoDB, это не значит, что вы должны (или даже должны) использовать это имя в Ruby. Часть работы ORM/ODM заключается в том, чтобы справиться с несоответствием импеданса между базой данных и кодом, использующим O [RD] M, переименование свойств/полей базы данных в соответствии с соглашениями атрибутов Ruby, несомненно, будет частью этого. –

+0

Вы знаете, что Mongoid поддерживает [динамические поля] (https://docs.mongodb.com/ruby-driver/master/tutorials/6.0.0/mongoid-documents/#dynamic-fields) из коробки, aren Не так ли? – Stefan

+1

@muistooshort вы правы. Мое решение состояло в том, чтобы использовать: как вариант Mongoid обеспечивает: field: «Hello World», введите: Array, as:: hello_world – Donato

ответ

4

define_method позволяет сделать это:

define_method(:"hello world") { puts 'hello world' } 
send :"hello world" 

Но вы должны назвать его send, так как имя метода в обычном синтаксисе вызова не допускается либо.


Вы можете сделать это и из определения класса.

class MyClass 
    def name 
    @name 
    end 

    define_method :"set name" do |new_name| 
    @name = new_name 
    end 
end 

instance = MyClass.new 
instance.send :"set name", 'Bob' 
instance.name #=> Bob 

Наконец, я чувствую себя обязанным сказать, что это, вероятно, ужасная идея. Я не уверен точно, что вы здесь, но, вероятно, лучший способ. :can != :should.

+0

Я работаю с Rails и Mongoid, я не думаю, что Rails когда-либо явно вызовет его, не используя send. – Donato

+1

Имя метода с пробелами в нем довольно ореховое, но это также возможно, как вы здесь демонстрируете. – tadman

+0

@Donato, потому что вы обычно используете синтаксически допустимые имена методов, поскольку имена методов - это то, что вы вводите в свой код, чтобы делать что-то. Если вы генерируете подобные методы, вам, вероятно, нужен метод, который принимает ключи в качестве аргумента. Бьюсь об заклад, у Монгоида есть интерфейс под капотом, который выглядит как 'instance.set ('hello world', 'new value')' (или что-то). И это, вероятно, то, что вы хотите переопределить. –

Смежные вопросы