Ruby - новые грани [Евгений Охотников] (pdf) читать постранично, страница - 19
Книга в формате pdf! Изображения и текст могут не отображаться!
[Настройки текста] [Cбросить фильтры]
51
# метод Object#extend: a.extend(Greeting)
class []
# => "Hi!"
# Теперь модуль Greeting модифицируется.
module Greeting
def hello; ’Hello!’;
def applaud; ’Bravo!’; end
end
a.public_methods.grep(/(hello|applaud)/)
a.hello
a.applaud
# => ["hello", "applaud"]
# => "Hello!"
# => "Bravo!"
Возможность расширения классов и объектов в Ruby вызывает много споров. Кто-то справедливо
считает, что необдуманное ее применение приведет к проблемам, особенно при сопровождении
больших проектов. Тем не менее, эта возможность в Ruby есть. Выделяются, как минимум, две
ситуации, в которых она будет востребована:
смена реализации методов без останова приложения. Это важно для приложений,
работающих в режиме 24x7, поскольку можно исправлять небольшие ошибки без
перезапуска приложений.
Наполнение
специфической прикладной функциональностью
чужих классов
без
модификации их исходных текстов (как делает Ruby-On-Rails со стандартными классами
Integer, Time и String).
Как бы то ни было, динамическое расширение классов, модулей и объектов является одной из
основополагающих возможностей языка. Поэтому при использовании Ruby нужно принимать ее во
внимание, поскольку она действительно предоставляет уникальные возможности.
4.17 Переопределение методов
Как было показано выше, в Ruby можно переопределить метод объекта. Но не всегда требуется
полностью менять реализацию метода, иногда необходимо дополнить уже существующий метод
дополнительными действиями. Например, захватить какой-то ресурс в эксклюзивном режиме,
выполнить действия метода, после чего освободить ресурс. В Ruby это выполняется посредством
назначения псевдонима, осуществляемого с помощью Method#alias_method, с последующим
переопределением метода:
class Demo
def do_something
puts ’doing something’
end
end
d = Demo.new
# Используется оригинальная версия метода do_something.
d.do_something
# Теперь объект d расширяется методами lock_resource, unlock_resource
# и получает новую реализацию метода do_something.
class nil
# => "a"
# => :BlaBlaBla
Показанный выше класс ValueHolder является примитивной демонстрацией принципа работы класса
OpenStruct [37] из стандартной библиотеки Ruby, в основе которого также лежит использование
method_missing.
Но наибольшее значение method_missing имеет для построения DSL – настолько важное, что даже в
документации к Kernel#method_missing приводится пример класса для хранения римских чисел, в
котором method_missing служит для разбора римской нотации:
class Roman
def romanToInt(str)
# ...
end
def method_missing(methId)
str = methId.id2name
romanToInt(str)
end
end
r = Roman.new
r.iv
r.xxiii
r.mm
#=> 4
#=> 23
#=> 2000
Одним из самых ярких и впечатляющих примеров использования method_missing для организации
DSL является библиотека Builder [38], которая позволяет записывать XML/HTML-конструкции в виде
Ruby-кода:
require ’rubygems’
require_gem ’builder’, ’~> 2.0’
builder = Builder::XmlMarkup.new
xml = builder.person { |b|
b.name
"Jim"
b.phone
"555-1234"
b.address { |a|
a.town
"New-York"
a.zip
"655374"
a.street "Broadway"
}
}
xml # => "Jim555-1234
New-York655374
Broadway"
55
4.19 Утиная типизация
Еще одной, очень горячо обсуждаемой особенностью Ruby является т.н. «утиная типизация» (duck
typing). Ее принцип состоит в том, что если некий объект «ходит как утка и крякает как утка»
значит он — утка. Подобие объекта чему-либо проверяется наличием методов с нужными именами и
сигнатурами, то есть наличие у объекта подходящего метода более важно, чем наследование класса
объекта от некоторого базового класса.
Например, пусть требуется создать метод do_something_important, который протоколирует ход
своей работы в журнальный файл. Объект файла-журнала должен передаваться методу в качестве
параметра. Поскольку задача do_something_important заключается в выполнении собственных
действий, то подготовка подходящих для этого условий – не его проблема:
def do_someting_important(log)
log
Последние комментарии
1 день 6 часов назад
1 день 11 часов назад
1 день 18 часов назад
1 день 21 часов назад
1 день 21 часов назад
3 дней 8 часов назад