2009-06-18 2 views
3

Я играл с 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 в классе Модель со способом, динамически вставленным модулем IdAndNameRedefine. Когда этот модуль включен, он создает «статический» метод (действительно, метод класса Model.class, как я его понимаю), и когда вызывается use_id_and_name_from_module, он создает метод класса в модели, который переопределяет id_and_name для использования любого атрибута Модель спросила.

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

ответ

5

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

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 

(я просто хотел показать, как class_eval действительно работает, так как вы, казалось, больше всего интересует в этой части.)

+0

Спасибо! Я думал, что это выглядит глупо, но я не мог понять, как это сделать. Я действительно верю, что я тоже пробовал define_method, но в этом вопросе я использовал 'use_id_and_name_from_module'-вызов в верхней части определения класса, поэтому он не работал (перезаписывается декларацией позже в классе, я думаю). Просто из любопытства; Есть ли способ разместить 'use_id_and_name_from_module' в верхней части класса и убедиться, что он не может быть переопределен в последующих объявлениях? –

+0

Вы можете переопределить метод_added и повторно добавить свою версию всякий раз, когда кто-то пытается ее заменить. Кажется немного запутанным. Лучше просто не переопределять метод в первую очередь. – Chuck

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