Customer = Struct.new(:name, :address, :city) Customers = [ Customer.new("Mr. Foo", "6th Ave", "New York"), Customer.new("Mr. Bar", "8th Ave", "Washington D.C"), Customer.new("Ms. Quux", "42th Ave", "New York"), ] class Statement attr_reader :next def initialize @next = nil end def >>(other) @next = other end def call raise NotImplementedError end def pass_on(*args) @next.call(*args) end def results if @next @next.results else raise "No results available." end end end class Scan < Statement def initialize(table) super() @table = table end def scan @table.each { |row| pass_on row } self end end class Limit < Statement def initialize(limit) super() @limit = limit @count = 0 end def call(row) if @count < @limit @count += 1 pass_on row end end end class Where < Statement def initialize(&clause) @clause = clause end def call(row) if @clause.call(row) pass_on row end end end class Collect < Statement attr_reader :results def initialize(&clause) @clause = clause @results = [] end def call(row) @results << @clause.call(row) end end (query = Scan.new(Customers)) >> Where.new { |c| c.city == "New York" } >> Limit.new(5) >> Collect.new { |c| [c.name, c.address] } p query.scan.results