Сожалеем, но текст оригинала доступен только зарегистрированным пользователям. |
(Упражнениие 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
|
|