module Pacer module Routes module RouteOperations def loop(&block) chain_route :filter => :loop, :looping_route => block end # Apply the given path fragment multiple times in succession. If a Range # or Array of numbers is given, the results are a combination of the # results from all of the specified repetition levels. That is useful if # a pattern may be nested to varying depths. def repeat(arg, &block) case arg when Fixnum range = arg..arg arg.to_enum(:times).inject(self) do |route_end, count| yield route_end end when Range if arg.exclude_end? range = arg.begin..(arg.end - 1) else range = arg end r = self.loop(&block).while do |e, depth, p| if depth < range.begin :loop elsif depth < range.end :loop_and_emit elsif depth == range.end :emit else false end end r.while_description = "repeat #{ arg.inspect }" r else fail ArgumentError, "Invalid repeat range" end end end end module Filter module LoopFilter attr_reader :looping_route attr_accessor :while_description def help(section = nil) case section when nil puts < 1 2 3 4 5 6 7 8 9 Why didn't this give me even numbers? [1].to_route.loop { |r| r.map { |n| n + 1 } }.while { |n, depth| n.even? ? :emit : :emit_and_loop } #==> 1 2 Odd numbers: [1].to_route.loop { |r| r.map { |n| n + 1 } }.while { |n, depth| n.even? ? :loop : :emit_and_loop }.limit(10) #==> 1 3 5 7 9 11 13 15 17 19 Fibonacci sequence: [[0, 1]].to_route(element_type: :path). loop { |r| r.map { |a, b| [b, a+b] } }. while { true }.limit(40). tails(element_type: :number) #==> 1 1 2 3 5 8 13 21 #==> 34 55 89 144 233 377 610 987 #==> 1597 2584 4181 6765 10946 17711 28657 46368 #==> 75025 121393 196418 317811 514229 832040 1346269 2178309 #==> 3524578 5702887 9227465 14930352 24157817 39088169 63245986 102334155 You usually won't mean to do these, but you can: [1].to_route.loop { |r| 123 }.while { true }.limit(10) #==> 123 123 123 123 123 123 123 123 123 123 [1].to_route.loop { |r| r }.while { true }.limit(10) #==> 1 1 1 1 1 1 1 1 1 1 HELP else super end description end def looping_route=(route) if route.is_a? Proc @looping_route = Pacer::Route.block_branch(self, route) else @looping_route = route end end def while(&block) @control_block = block self end protected def attach_pipe(end_pipe) unless @control_block fail ClientError, 'No loop control block specified. Use either #while or #until after #loop.' end pipe = Pacer::Pipes::LoopPipe.new(graph, looping_pipe, @control_block) pipe.setStarts(end_pipe) if end_pipe pipe end def looping_pipe Pacer::Route.pipeline(looping_route) end def inspect_string s = "#{ inspect_class_name }(#{ @looping_route.inspect })" if while_description "#{ s }(#{ while_description })" else s end end end end end