Class: Object
- Inherits:
- BasicObject
- Defined in:
- lib/coroutines.rb
Instance Method Summary collapse
-
#consum_for(meth, *args) ⇒ Object
:call-seq: consum_for(method, *args) -> consumer.
-
#trans_for(meth, *args) ⇒ Object
:call-seq: trans_for(method, *args) -> transformer.
Instance Method Details
#consum_for(meth, *args) ⇒ Object
:call-seq:
consum_for(method, *args) -> consumer
Creates a new Consumer coroutine from the given method. This is analogous to using Kernel#enum_for to create an Enumerator instance. The method is called immediately (with the given args
). It executes until the first call to #await, at which point consum_for returns the Consumer instance. Calling consumer << obj resumes the consumer at the point where it last executed #await, which evaluates to obj
.
Calling consumer.close raises StopIteration at the point where the consumer last executed #await; it is expected that it will terminate without executing #await again. Consumer#close evaluates to the return value of the method.
Example:
def counter(start)
result = start
loop { result += await }
"Final value: #{result}"
end
co = consum_for :counter, 10 #=> #<Consumer: main:counter (running)>
co << 10 << 1000 << 10000
co.close #=> "Final value: 11020"
128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/coroutines.rb', line 128 def consum_for(meth, *args) cons = Consumer.new do |y| Fiber.current.instance_variable_set(:@yielder, y) send(meth, *args) end description = "#{inspect}:#{meth}" cons.define_singleton_method :inspect do state = if @fiber.alive? then "running" else @result.inspect end "#<Consumer: #{description} (#{state})>" end cons end |
#trans_for(meth, *args) ⇒ Object
:call-seq:
trans_for(method, *args) -> transformer
Creates a new Transformer instance that wraps the given method. This is analogous to using Kernel#enum_for to create an Enumerator instance, or using Object#consum_for to create a Consumer instance. The method is not executed immediately. The resulting Transformer can be connected to an enumerable (using transformer <= enum) or to a sink (using transformer >= sink). The point at which the transformer method gets started depends on how it is connected; in any case however, the method will be called with the args
given to trans_for. See Transformer for details.
Within the transformer method, #await can be used to read the next input value (as in a Consumer, compare Object#consum_for), and yield can be used to produce an output value (i.e., when it is called, the method is given a block which accepts its output).
Example:
def running_sum(start)
result = start
loop { result += await; yield result }
end
tr = trans_for :running_sum, 3 #=> #<Transformer: main:running_sum>
sums = (1..10) >= tr #=> #<Enumerator: #<Transformer: main:running_sum> <= 1..10>
sums.to_a #=> [4, 6, 9, 13, 18, 24, 31, 39, 48, 58]
170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/coroutines.rb', line 170 def trans_for(meth, *args) trans = Transformer.new do |y| Fiber.current.instance_variable_set(:@yielder, y) send(meth, *args, &y.method(:yield)) end description ="#{inspect}:#{meth}" trans.define_singleton_method :inspect do "#<Transformer: #{description}>" end trans end |