Методы и атрибуты

Как мы уже видели, методы обычно используются в сочетании с простыми экземплярами
классов и переменными, причем вызывающий объект отделяется от имени
метода точкой (receiver .method). Если имя метода является знаком препинания,
то точка опускается. У методов могут быть аргументы:
Time.mktime(2000, "Aug", 24, 16, 0)
Поскольку каждое выражение возвращает значение, то вызовы методов могут
сцепляться:
3.succ.to_s
/(x.z).*?(x.z).*?/.match("xlz_la3_x2z_lb3_").to_a[l..3]
3+2.succ
Отметим, что могут возникать проблемы, если выражение, являющееся результатом
сцепления, имеет тип, который не поддерживает конкретный метод.
Точнее, при определенных условиях некоторые методы возвращают nil, а вызов
любого метода с1т имени такого объекта приведет к ошибке. (Конечно, nil -
полноценный объект, но он не обладает теми же методами, что и, например, массив.)
Некоторым методам можно передавать блоки. Это верно для всех итераторов
- как встроенных, так и определенных пользователем. Блок обычно заключается
в операторные скобки do-end или в фигурные скобки. Но он не рассматривается
так же, как предшествующие ему параметры, если таковые существуют. Вот
пример вызова метода File.open:
my_array.each do IxI
some_action
end
File.open(filename) { If I some_action }
Именованные параметры будут поддерживаться в последующих версиях Ruby,
но на момент работы над этой книгой еще не поддерживались. В языке Python они
называются ключевыми аргументами, сама идея восходит еще к языку Ada.
Методы могут принимать переменное число аргументов:
receiver.method(argl, *more_args)
В данном случае вызванный метод трактует more_args как массив и обращается
с ним, как с любым другим массивом. На самом деле звездочка в списке формальных
параметров (перед последним или единственным параметром) может
«свернуть» последовательность фактических параметров в массив:
def mymethod(a, b, *с)
print a, b
с.each do |x| print x end
end
mymethod(l,2,3,4,5,6,7)
# a=l, b=2, c=[3,4,5,6,7]
В Ruby есть возможность определять методы на уровне объекта (а не класса).
Такие методы называются синглетными; они принадлежат одному-единствен-
ному объекту и не оказывают влияния ни на класс, ни на его суперклассы. Такая
возможность может быть полезна, например, при разработке графических интерфейсов
пользователя: чтобы определить действие кнопки, вы задаете синглетный
метод для данной и только данной кнопки.
Вот пример определения синглетного метода для строкового объекта:
str = "Hello, world!"
stг2 = "Goodbye!"
def str.spell
self.split(/./).join("-")
end
str.spell # "H-e-l-l-o-,- -w-o-r-l-d-!"
str2.spell # Ошибка!
Имейте в виду, что метод определяется для объекта, а не для переменной.
Теоретически с помощью синглетных методов можно было бы создать систему
объектов на базе прототипов. Это менее распространенная форма ООП без классов*.
Основной структурный механизм в ней состоит в конструировании нового
объекта путем использования существующего в качестве образца; новый объект
ведет себя как старый за исключением тех особенностей, которые были переопределены.
Тем самым можно строить системы на основе прототипов, а не наследования.
Хотя у нас нет опыта в этой области, мы полагаем, что создание такой системы
позволило бы полнее раскрыть возможности Ruby.