2016-11-08 5 views
-1

は私が多くのクラスを持っているプロジェクトを作成し、すべてのクラスが似た構造を持っている:クラス間のルビー - メタプログラミング、define_method、乾燥コード

module Project 
    class ExampleClass 
    attr_accessor :title, :body, :elements_1, :elements_2 

    def initialize(attributes = {}) 
     self.title = attributes[:title] 
     self.body = attributes[:body] 
     self.elements1 = attributes[:elements1] || [] 
     self.elements2 = attributes[:elements2] || [] 
    end 

    def ==(other) 
     title == other.title && body == other.body && elements1 == other.elements1 && elements2 == other.elements2 
    end 
    end 
end 

だけの違いは、その名前とelements1elements2の名前ですアレイ。私のメンターは、私に私のプロジェクトを乾燥させるためのコードを与えた :

module Project 
    class Node 
    extend ActiveModel::Naming 
    include ActiveModel::Model 

    attr_accessor :body, :title 
    cattr_accessor :element_names 
    self.element_names = [] 

    def element 
     element_names.reduce([]) do |name, memo| 
     memo + send(name) 
     end 
    end 

    def ==(other) 
     body == other.body && title == other.title && element_names.all? { |name| element_by_name(name) == other.element_by_name(name) } 
    end 

    def element_by_name(name) 
     instance_variable_get("@#{name}") || instance_variable_set("@#{name}", []) 
    end 

    module ClassMethods 
     def element(name) 
     elements_names << name 

     attr_writer name 
     define_method(name) do 
      element_by_name(name) 
     end 
     end 
    end 
    extend ClassMethods 
    end 
end 

それはかなり私のレベルより上だ、私はそれを動作させるためにしようとしている - すべてのクラスはNode後に継承する必要があります。私はどうにかして属性 - elements1elements2を渡す必要があります。私は実験していた

class ExampleClass < Node  
    cattr_accessor :element_names 
    self.element_names = [:elements1, elements2] 
end 

私のExampleClassの配列の名前を渡す。

私もinitializeで試しましたが、動作させることはできません。私はどんな助けにも感謝します。

答えて

1

elementクラスメソッドは、新しい要素を定義するために使用されます。

あなたが欲しいあなたのメンターはあなたを与えたコードに深刻な問題があるものの

class ExampleClass < Node 
    element :elements1 
    element :elements2 
end 

のようなもの:要素名がクラス変数に格納されている、彼らはNodeのすべてのサブクラス間で共有されることを意味します。あなたが望むのはクラスインスタンスの変数です。

各サブクラスは、要素名の独自の配列を格納していない(そしてボーナスとして、あなたは、もはやそのActiveModel嫌なもののいずれかを必要とする)そのように、この

def self.element_names 
    @element_names ||= [] 
end 

この

cattr_accessor :element_names 
self.element_names = [] 

を交換してください。

関連する問題