Ruby - новые грани [Евгений Охотников] (pdf) читать постранично, страница - 18
Книга в формате pdf! Изображения и текст могут не отображаться!
[Настройки текста] [Cбросить фильтры]
class ProjectDescription
...
def presentations; ...; end
end
Такое расширение уже существующих классов может оказаться востребованным в различных
ситуациях. Например, когда реализация части методов зависит от платформы, на которой работает
программа:
47
class Application
def run
load_configuration
perform_work
store_results
end
def perform_work; ...; end
def store_results; ...; end
end
# Реализация метода load_configuration зависит от платформы.
if /mswin/ =~ Config::CONFIG[ ’host_os’ ]
require ’app-mswin’
else
require ’app-non-mswin’
end
# Файл app-mswin.rb. Реализация загрузки конфигурации из реестра.
class Application
def load_configuration; ...; end
end
# Файл app-non-mswin.rb. Реализация загрузки конфигурации из файлов.
class Application
def load_configuration; ...; end
end
При расширении класса автоматически расширяются все уже созданные объекты этого класса. То
есть, если в класс были добавлены новые методы, они автоматически появляются в каждом из уже
существующих объектов:
class Demo
def first; end
def second; end
end
a = Demo.new
a.class.instance_methods(false)
# => ["second", "first"]
class Demo
def third; end
end
a.class.instance_methods(false)
# => ["second", "first", "third"]
Если в дополнительном определении класса заново реализуется уже имеющийся в классе метод, то
данный метод получает новую реализацию у всех существующих объектов этого класса:
class Demo
def greeting
’hi’
end
end
a = Demo.new
a.greeting
# => "hi"
class Demo
def greeting
’Hello’
end
end
a.greeting
# => "Hello"
48
Расширять в Ruby можно любые классы, даже стандартные. Например, Ruby-On-Rails расширяет
стандартные классы Integer, String и Time для предоставления удобных вспомогательных
методов [19]:
puts
puts
puts
puts
puts
20.kilobytes
20.hours.from_now
"cat".pluralize
"cats".singularize
Time.now.at_beginning_of_month
#
#
#
#
#
=>
=>
=>
=>
=>
20480
Wed May 11 13:03:43 CDT 2005
cats
cat
Sun May 01 00:00:00 CDT 2005
Все вышесказанное распространяется и на модули. Модули, как и классы, являются открытыми.
Поэтому расширение модуля или смена реализации метода в модуле автоматически
распространяется на объекты всех типов, в которых модуль был использован в качестве примеси:
module Greeting
def hello; ’Hi!’; end
end
class Demo
include Greeting
end
a = Demo.new
a.public_methods.grep(/(hello|applaud)/)
a.hello
# => ["hello"]
# => "Hi!"
# Теперь модуль Greeting модифицируется.
module Greeting
def hello; ’Hello!’; end
def applaud; ’Bravo!’; end
end
a.public_methods.grep(/(hello|applaud)/)
a.hello
a.applaud
# => ["hello", "applaud"]
# => "Hello!"
# => "Bravo!"
(метод public_methods по умолчанию возвращает список всех публичных методов объекта, включая
унаследованные из базовых классов и примесей, но этот список большой, поэтому из него
выделяются только методы с именами hello и applaud).
То, что в Ruby можно снабдить собственными методами любой, даже чужой, класс, открывает перед
разработчиком новые возможности. Например, если при использовании сторонней библиотеки
обнаруживается ошибка в ее реализации, то эта ошибка может быть исправлена без модификации
исходного текста библиотеки — достаточно модифицировать проблемный класс в своем коде. Еще
один пример: при использовании какого-то готового фреймворка может потребоваться
модифицировать какой-либо его класс. Скажем, для того, чтобы снабдить его новой
функциональностью или дополнительными атрибутами. Сделать это при помощи обычного
наследования невозможно, если объекты нужного класса создаются где-то внутри фреймворка. Но
можно расширить класс собственными методами/атрибутами, и тогда фреймворк автоматически
начнет создавать объекты уже обновленного класса. Ruby-On-Rails демонстрирует это на примере
стандартного класса Integer, объекты которого создаются где-то в глубине интерпретатора Ruby.
Открытыми в Ruby являются не только классы, но и объекты. Любой объект может быть расширен
собственными методами, которые будут присутствовать только у него, но не у других объектов того
же класса:
class
def
def
def
end
Demo
f; end
g; end
j; end
49
a, b, c = Demo.new, Demo.new, Demo.new
a.public_methods(false)
# => ["g", "f", "j"]
b.public_methods(false)
# => ["g", "f", "j"]
c.public_methods(false)
# => ["g", "f", "j"]
# Добавление нового метода в объект a.
def a.k
end
# Добавление нового метода в объект b. Используется другой способ записи.
class ["g", "f", "j", "m"]
# => ["g", "f", "j"]
(обращение к методу public_methods с аргументом false приводит к возврату списка только
собственных методов объекта, без унаследованных из базовых классов и примесей).
Можно не только расширять объект новыми методами, но и менять реализацию существующих
методов. Причем делать это не только для собственных объектов, но и для любых объектов, в том
числе и для объектов стандартных типов:
a = [ 1, ’1’, :first ]
b = a.dup
a.to_s
b.to_s
# => "11first"
# => "11first"
class "11first"
Cпособ записи расширения объекта в виде конструкции class 20943200
class []
# Выполняем подмешивание модуля Greeting только к объекту a.
# Как вариант более компактной записи можно было бы
Последние комментарии
7 часов 44 минут назад
21 часов 39 минут назад
23 часов 11 минут назад
1 день 3 часов назад
1 день 3 часов назад
1 день 8 часов назад