Spec-Zone.ru › Ruby 3.4

модуль Forwardable

Модуль Forwardable предоставляет делегирование указанных методов выделенному объекту, используя методы def_delegator и def_delegators.

Например, предположим, у вас есть класс RecordCollection, содержащий массив @records. Вы можете предоставить метод поиска record_number(), который просто вызывает [] на массиве @records, как показано ниже:

require 'forwardable'

class RecordCollection
  attr_accessor :records
  extend Forwardable
  def_delegator :@records, :[], :record_number
end

Мы можем использовать метод поиска следующим образом:

r = RecordCollection.new
r.records = [4,5,6]
r.record_number(0)  # => 4

Далее, если вы хотите предоставить методы size, << и map, все из которых делегируют @records, вот как это можно сделать:

class RecordCollection # re-open RecordCollection class
  def_delegators :@records, :size, :<<, :map
end

r = RecordCollection.new
r.records = [1,2,3]
r.record_number(0)   # => 1
r.size               # => 3
r << 4               # => [1, 2, 3, 4]
r.map { |x| x * 2 }  # => [2, 4, 6, 8]

Вы даже можете расширить обычные объекты с помощью Forwardable.

my_hash = Hash.new
my_hash.extend Forwardable              # prepare object for delegation
my_hash.def_delegator "STDOUT", "puts"  # add delegation for STDOUT.puts()
my_hash.puts "Howdy!"

Другой пример

Вы можете использовать Forwardable в качестве альтернативы наследованию, когда вы не хотите наследовать все методы от суперкласса. Например, вот как вы можете добавить ряд методов экземпляра Array к новому классу Queue:

class Queue
  extend Forwardable

  def initialize
    @q = [ ]    # prepare delegate object
  end

  # setup preferred interface, enq() and deq()...
  def_delegator :@q, :push, :enq
  def_delegator :@q, :shift, :deq

  # support some general Array methods that fit Queues well
  def_delegators :@q, :clear, :first, :push, :shift, :size
end

q = Thread::Queue.new
q.enq 1, 2, 3, 4, 5
q.push 6

q.shift    # => 1
while q.size > 0
  puts q.deq
end

q.enq "Ruby", "Perl", "Python"
puts q.first
q.clear
puts q.first

Это должно вывести:

2
3
4
5
6
Ruby
nil

Примечания

Обратите внимание, что RDoc не будет обнаруживать делегированные методы.

forwardable.rb предоставляет делегирование одного метода через методы def_delegator и def_delegators. Для делегирования всего класса через DelegateClass см. delegate.rb.

Константы

FORWARDABLE_VERSION
VERSION

Версия forwardable.rb

Атрибуты

debug [RW]

Проигнорировано

Открытые методы экземпляров

def_delegator (accessor, method, ali = method)
Псевдоним для: def_instance_delegator
def_delegators (accessor, *methods)
Псевдоним для: def_instance_delegators
def_instance_delegator (accessor, method, ali = method)
Исходный код
# File lib/forwardable.rb, line 188
def def_instance_delegator(accessor, method, ali = method)
  gen = Forwardable._delegator_method(self, accessor, method, ali)

  # If it's not a class or module, it's an instance
  mod = Module === self ? self : singleton_class
  ret = mod.module_eval(&gen)
  mod.__send__(:ruby2_keywords, ali) if RUBY_VERSION >= '2.7'
  ret
end

Определяет method как делегирующий метод экземпляра с необязательным псевдонимом ali. Вызовы Method к ali будут делегированы accessor.method. accessor должно быть именем метода, именем экземпляра переменной или именем константы. Используйте полное имя константы, если вы предоставляете имя константы. Возвращает имя определенного метода.

class MyQueue
  CONST = 1
  extend Forwardable
  attr_reader :queue
  def initialize
    @queue = []
  end

  def_delegator :@queue, :push, :mypush
  def_delegator 'MyQueue::CONST', :to_i
end

q = MyQueue.new
q.mypush 42
q.queue    #=> [42]
q.push 23  #=> NoMethodError
q.to_i     #=> 1
Также псевдоним для: def_delegator
def_instance_delegators (accessor, *methods)
Исходный код
# File lib/forwardable.rb, line 156
def def_instance_delegators(accessor, *methods)
  methods.each do |method|
    next if /\A__(?:send|id)__\z/ =~ method
    def_instance_delegator(accessor, method)
  end
end

Сокращение для определения нескольких методов делегирования, но без возможности использования другого имени. Два приведенных ниже фрагмента кода имеют одинаковый эффект:

def_delegators :@records, :size, :<<, :map

def_delegator :@records, :size
def_delegator :@records, :<<
def_delegator :@records, :map
Также псевдоним для: def_delegators
delegate method → accessor
delegate [method, method, ...] → accessor
Псевдоним для: instance_delegate
instance_delegate
Исходный код
Также псевдоним для: delegate

Ruby Core © 1993–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API