I'm trying to build something that will process an event stream. I want my processors to be side effect free so they are easy to manage, but I also want to ensure I do not run through the stream twice.
class A
def initialize(*processors)
@processors = processors
end
def call(list)
@processors.inject(0) { |acc, p|
acc + p.call(list)
}
end
end
class B
def initialize(multiplier)
@multiplier = multiplier
end
def call(list)
list.map { |i|
i * @multiplier
}.inject(0) { |acc, i|
puts "B with multipler: #{@multiplier}, adding: #{i}"
acc + i
}
end
end
A.new(B.new(1), B.new(2)).call([1, 2, 3, 4, 5].lazy)
# => 45
Class A
is totally wrong as the execution order is:
# B with multipler: 1, adding: 1
# B with multipler: 1, adding: 2
# B with multipler: 1, adding: 3
# B with multipler: 1, adding: 4
# B with multipler: 1, adding: 5
# B with multipler: 2, adding: 2
# B with multipler: 2, adding: 4
# B with multipler: 2, adding: 6
# B with multipler: 2, adding: 8
# B with multipler: 2, adding: 10
How could I modify class A to give me an execution order of:
# B with multipler: 1, adding: 1
# B with multipler: 2, adding: 2
# B with multipler: 1, adding: 2
# B with multipler: 2, adding: 4
# B with multipler: 1, adding: 3
# B with multipler: 2, adding: 6
# B with multipler: 1, adding: 4
# B with multipler: 2, adding: 8
# B with multipler: 1, adding: 5
# B with multipler: 2, adding: 10
Do I need some type of more sophisticated enumerable?
If you want to apply processors to values in order you need to send them one at a time
class A
def initialize(*processors)
@processors = processors
end
def call(list)
list.inject(0) do |acc, item|
acc + @processors.map { |processor| processor.call(item) }.inject(:+)
end
end
end
class B
def initialize(multiplier)
@multiplier = multiplier
end
def call(item)
puts "B with multipler: #{@multiplier}, adding: #{item}"
item * @multiplier
end
end
p A.new(B.new(1), B.new(2)).call([1, 2, 3, 4, 5].lazy)