Включить модуль для определения метода динамического класса - PullRequest
3 голосов
/ 18 июня 2009

Я играю с Ruby и написал следующий код:

module IdAndNameRedefine
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def use_id_and_name_from_module(use_attribute)
      class_eval <<CODE
        def id_and_name
          "\#{id}-\#{#{use_attribute}.downcase}"
        end
CODE
    end
  end
end


class Model
  include IdAndNameRedefine

  attr_reader :id, :name1, :name2

  def initialize(id, name1, name2)
    @id = id
    @name1 = name1
    @name2 = name2
  end

  def id_and_name
    "#{id}-#{name1}"
  end

  use_id_and_name_from_module :name2
end

model = Model.new(1, "TesT", "Test number TWO")
puts model.id_and_name

Когда я пытаюсь сделать это здесь, это переопределить метод класса id_and_name в классе Model с помощью метода, динамически вставляемого IdAndNameRedefine -модулем. Когда этот модуль включен, он создает «статический» метод (на самом деле, метод класса Model.class, насколько я понимаю), и когда вызывается use_id_and_name_from_module, он создает метод класса в Model, который переопределяет id_and_name использовать любой атрибут запрашиваемой модели.

У меня вопрос .. Есть ли лучший способ сделать это, или это «правильный» способ сделать это? Я не совсем уверен, что мне нравится, когда class_eval с принимает строку, где мне нужно экранировать значения и т. Д., Чтобы эта работа работала.

1 Ответ

5 голосов
/ 18 июня 2009

Вам не нужно передавать строку в class_eval. Это может занять блок вместо. На самом деле, я не могу вспомнить ни одного случая, когда мне приходилось передавать строку в class_eval. Таким образом, мы можем переписать модуль ClassMethods следующим образом:

module ClassMethods
  def use_id_and_name_from_module(use_attribute)
    class_eval do 
      define_method(:id_and_name) {"#{id}-#{send(use_attribute).downcase}"}
    end
  end
end

Но в данном конкретном случае мы просто сообщаем self class_eval, что означает, что мы уже в контексте этого класса. Таким образом, оно может быть сокращено до:

module ClassMethods
  def use_id_and_name_from_module(use_attribute)
    define_method(:id_and_name) {"#{id}-#{send(use_attribute).downcase}"}
  end
end

(Я просто хотел показать, как на самом деле работает * 1011, поскольку вы, похоже, больше всего интересовались этой частью.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...