я создал проект, в котором у меня есть много классов, и каждый класс имеет похожую структуру:Руби - метапрограммирование, 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
только различие между классами являются его именем и имена elements1
и elements2
массивы. Мой наставник дал мне код DRY мой проект:
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
. Я должен как-то передать атрибуты - elements1
и elements2
. Я экспериментировал с
class ExampleClass < Node
cattr_accessor :element_names
self.element_names = [:elements1, elements2]
end
в моем ExampleClass
передать имена массивов.
Я также пробовал с initialize
, но я не могу заставить его работать. Буду благодарен за любую помощь.