HW 1: Ruby calisthenics / ДЗ1: Ruby тренировка: Part 5: advanced OOP with some metaprogramming

Английский оригинал Перевод на русский

Сожалеем, но текст оригинала доступен только зарегистрированным пользователям.

(Упражнениие 3.4 из ELLS)
В лекции мы видели как attr_accessor использует метапрограммирование для создания геттеров и сеттеров для атрибутов объекта налету.
Определите метод attr_accessor_with_history, который дает те же возможности как аксессор attr, но также отслеживает каждое значение, которое когда-либо было у атрибута:
class Foo
attr_accessor_with_history :bar
end
f = Foo.new # => #
f.bar = 3 # => 3
f.bar = :wowzo # => :wowzo
f.bar = 'boo!' # => 'boo!'
f.bar_history # => [nil, 3, :wowzo, 'boo!']
Мы засадим вас за работу. Первая вещь, которую хочется отменить: если мы определим attr_accessor_with_history в классе Class, мы сможем использовать его, как в коде, приведенном выше. Это потому, что, как отмечает ELLS, в Руби класс -- это просто объект класса Class. (Если это взрывает ваш мозг, просто не думайте сейчас об этом. Это придет.) Вторая вещь заключается в том, что Руби предоставляет метод class_eval, который принимает строку и выполняет её в контексте текущего класса, то есть, класса, из которого вы вызываете attr_accessor_with_history. Эта строка должна содержать определение метода, который реализует сеттер-с-историей для желаемого атрибута attr_name.
• Не забудьте, что в первый раз, когда атрибут получает значение, массив с его историей должен быть проинициализирован.
• Не забудьте, что переменные экземляра доступны через @bar из геттеров и сеттеров, как объясняет ELLS, Раздел 3.4.
• Хотя существующий attr_accessor может обрабатывать несколько агрументов (например, attr_accessor :foo, :bar), ваша версия нуждается в обработке только одного аргумента.
• Ваша реализация должна быть достаточно общей, чтобы работать в контексте любого класса и для атрибутов с любым (допустимым) именем переменной
• История переменных экземляра должна обслуживаться отдельно от каждого экземляра объекта. То есть, если вы сделаете
f = Foo.new
f.bar = 1
f.bar = 2
f = Foo.new
f. bar = 4
f.bar_history
то последняя строка должна вернуть только [nil,4], а не [nil,1,2,4]
Вот каркас, чтобы вы начали:
class Class
def attr_accessor_with_history(attr_name)
attr_name = attr_name.to_s # убеждается, что это строка
attr_reader attr_name # создает геттер атрибута
attr_reader attr_name+"_history" # создает геттер bar_history
class_eval "your code here, use %Q for multiline strings"
end
end
class Foo
attr_accessor_with_history :bar
end
f = Foo.new
f.bar = 1f.bar = 2
f.bar_history # => если ваш код работает, должен быть [nil,1,2]

starius 05.03.12 в 16:50

0
Минутку...