Книга: Программирование на языке Ruby

11.2.6. Хранение кода в виде объекта

11.2.6. Хранение кода в виде объекта

Неудивительно, что Ruby предлагает несколько вариантов хранения фрагмента кода в виде объекта. В этом разделе мы рассмотрим объекты Proc, Method и UnboundMethod.

Встроенный класс Proc позволяет обернуть блок в объект. Объекты Proc, как и блоки, являются замыканиями, то есть запоминают контекст, в котором были определены.

myproc = Proc.new { |a| puts "Параметр равен #{а}" }
myproc.call(99) # Параметр равен 99

Кроме того, Ruby автоматически создает объект Proc, когда метод, последний параметр которого помечен амперсандом, вызывается с блоком в качестве параметра:

def take_block(x, &block)
 puts block.class
 x.times {|i| block[i, i*i] }
end
take_block(3) { |n,s| puts "#{n} в квадрате равно #{s}" }

В этом примере демонстрируется также применение квадратных скобок как синонима метода call. Вот что выводится в результате исполнения:

Proc
0 в квадрате 0
1 в квадрате 1
2 в квадрате 4

Объект Proc можно передавать методу, который ожидает блок, предварив имя знаком &:

myproc = proc { |n| print n, "... " }
(1..3).each(&myproc) # 1... 2... 3...

Ruby позволяет также превратить метод в объект. Исторически для этого применяется метод Object#method, который создает объект класса Method как замыкание в конкретном объекте.

str = "cat"
meth = str.method(:length)
a = meth.call # 3 (длина "cat")
str << "erpillar"
b = meth.call # 11 (длина "caterpillar")
str = "dog"
# Обратите внимание на следующий вызов! Переменная str теперь ссылается
# на новый объект ("dog"), но meth по-прежнему связан со старым объектом.
с = meth.call # 11 (длина "caterpillar")

Начиная с версии Ruby 1.6.2, можно также применять метод Module#instance_method для создания объектов UnboundMethod. С их помощью представляется метод, ассоциированный с классом, а не с конкретным объектом. Прежде чем вызывать объект UnboundMethod, нужно связать его с каким-то объектом. Результатом операции связывания является объект Method, который можно вызывать как обычно:

umeth = String.instance_method(:length)
m1 = umeth.bind("cat")
m1.call # 3
m2 = umeth.bind("caterpillar")
m2.call # 11

Явное связывание делает объект UnboundMethod интуитивно более понятным, чем Method.

Оглавление книги


Генерация: 1.030. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз