Last active
August 29, 2015 13:57
-
-
Save andrewtimberlake/9462561 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
require 'fiber' | |
module EachGroup | |
def each_group(*fields, &block) | |
loop_fiber = Fiber.new do | |
current_value = nil | |
group_fiber = nil | |
each do |result| | |
group_value = Array(fields).map{|f| result.public_send(f) } | |
unless current_value == group_value | |
current_value = group_value | |
group_fiber = Fiber.new do |first_result| | |
group = Group.new(group_value) | |
block.call(group) | |
end | |
group_fiber.resume(nil) # Start the fiber and wait for its first yield | |
end | |
group_fiber.resume(result) if group_fiber.alive? # Send the result to the group fiber | |
end | |
group_fiber.resume(nil) if group_fiber && group_fiber.alive? # Final yield to finish off the group's internal loop | |
end | |
loop_fiber.resume(nil) # Start the outer loop | |
end | |
class Group | |
def initialize(value) | |
@value = value | |
end | |
attr_reader :value | |
def each(&block) | |
while result = Fiber.yield | |
block.call(result) | |
end | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
require 'spec_helper' | |
require 'ostruct' | |
spec_require 'lib/each_group' | |
describe EachGroup do | |
before(:all) do | |
Array.send(:include, EachGroup) | |
end | |
let(:data) { [ | |
OpenStruct.new(year: 2014, month: 1), | |
OpenStruct.new(year: 2014, month: 11), | |
OpenStruct.new(year: 2013, month: 2), | |
OpenStruct.new(year: 2012, month: 2), | |
] } | |
it "returns the data in groups" do | |
results = [] | |
data.each_group(:year) do |group| | |
results << group.value | |
group.each do |value| | |
results << value | |
end | |
end | |
expect(results).to eq([ | |
[2014], | |
#<OpenStruct year=2014, month=1>, | |
#<OpenStruct year=2014, month=11>, | |
[2013], | |
#<OpenStruct year=2013, month=2>, | |
[2012], | |
#<OpenStruct year=2012, month=2>, | |
]) | |
end | |
it "returns the data in groups without checking the group values" do | |
results = [] | |
data.each_group(:year) do |group| | |
results << group.value | |
end | |
expect(results).to eq([ | |
[2014], | |
[2013], | |
[2012], | |
]) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment