Class: Object

Inherits:
BasicObject
Defined in:
lib/coroutines.rb

Instance Method Summary collapse

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