Модуль 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, <
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!"
Другой пример
Мы хотим полагаться на то, что было прежде, очевидно, но с делегированием мы можем взять только те методы, которые нам нужны, и даже переименовать их должным образом. Во многих случаях это предпочтительнее наследования, которое предоставляет нам весь старый интерфейс, даже если большая часть из него не нужна.
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 = 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.
Константы
- FILE_REGEXP
- FORWARDABLE_VERSION
-
Версия
forwardable.rb
Атрибуты
Если true, __FILE__ останется в стеке вызовов в случае возникновения Исключения.
Публичные методы класса
# File lib/forwardable.rb, line 191
def self._delegator_method(obj, accessor, method, ali)
accessor = accessor.to_s unless Symbol === accessor
if Module === obj ?
obj.method_defined?(accessor) || obj.private_method_defined?(accessor) :
obj.respond_to?(accessor, true)
accessor = "#{accessor}()"
end
line_no = __LINE__+1; str = "#{<<-"begin;"}\n#{<<-"end;"}"
begin;
proc do
def #{ali}(*args, &block)
begin
#{accessor}
ensure
$@.delete_if {|s| ::Forwardable::FILE_REGEXP =~ s} if $@ and !::Forwardable::debug
end..__send__ #{method}, *args, &block
end
end
end Публичные методы экземпляра
# File lib/forwardable.rb, line 180 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 (Module === self ? self : singleton_class).module_eval(&gen) end
Определите method как метод делегата экземпляра с необязательным именем псевдонима ali. Вызовы метода ali будут делегированы accessor.method.
class MyQueue
extend Forwardable
attr_reader :queue
def initialize
@queue = []
end
def_delegator :@queue, :push, :mypush
end
q = MyQueue.new
q.mypush 42
q.queue #=> [42]
q.push 23 #=> NoMethodError
# File lib/forwardable.rb, line 153
def def_instance_delegators(accessor, *methods)
methods.delete("__send__")
methods.delete("__id__")
for method in methods
def_instance_delegator(accessor, method)
end
end Сокращение для определения нескольких методов делегата, но без возможности использовать другое имя. Два следующих примера кода имеют одинаковый эффект:
def_delegators :@records, :size, :<<, :map def_delegator :@records, :size def_delegator :@records, :<< def_delegator :@records, :map
# File lib/forwardable.rb, line 133
def instance_delegate(hash)
hash.each{ |methods, accessor|
methods = [methods] unless methods.respond_to?(:each)
methods.each{ |method|
def_instance_delegator(accessor, method)
}
}
end Принимает хэш в качестве аргумента. Ключ — символ или массив символов. Эти символы соответствуют именам методов. Значение — обработчик, к которому будут делегированы методы.
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.