Могу ли я предложить решение, которое не использует миксины модуля и тем самым предоставляет вам больше гибкости.Например, используя решение, немного более похожее на традиционный GoF-декоратор, вы можете развернуть свою статью (вы не можете удалить миксин, если он был применен один раз), и это даже позволяет вам заменить обернутую статью на другую во время выполнения.
Вот мой код:
class ArticleDecorator < BasicObject
def self.[](instance_or_array)
if instance_or_array.respond_to?(:to_a)
instance_or_array.map {|instance| new(instance) }
else
new(instance_or_array)
end
end
attr_accessor :wrapped_article
def initialize(wrapped_article)
@wrapped_article = wrapped_article
end
def format_title
@wrapped_article.title.upcase
end
protected
def method_missing(method, *arguments)
@wrapped_article.method(method).call(*arguments)
end
end
Теперь вы можете расширить одну статью, позвонив
extended_article = ArticleDecorator[article]
или несколько статей, позвонив
articles = [article_a, article_b]
extended_articles = ArticleDecorator[articles]
Вы можете восстановить исходную статью, вызвав
extended_article.wrapped_article
Или вы можете обменять обернутую статью внутри следующим образом
extended_article = ArticleDecorator[article_a]
extended_article.format_title
# => "FIRST"
extended_article.wrapped_article = article_b
extended_article.format_title
# => "SECOND"
Поскольку ArticleDecorator расширяет класс BasicObject, который почти не имеетуже определенные методы, даже такие вещи, как #class и #object_id остаются неизменными для обернутого элемента:
article.object_id
# => 123
extended_article = ArticleDecorator[article]
extended_article.object_id
# => 123
Обратите внимание, что BasicObject существует только в Ruby 1.9 и выше.