Permalink
Browse files

Add #ignore and #default to Aggregator.

  • Loading branch information...
1 parent eaff9ec commit 668cadbe311f906d03bea5523b148f2ca4680eca @blambeau committed Sep 17, 2012
@@ -1 +1,2 @@
-require_relative 'utils/decorate'
+require_relative 'utils/decorate'
+require_relative 'utils/aggregator'
@@ -0,0 +1,45 @@
+module Stamina
+ module Utils
+ class Aggregator
+
+ def initialize
+ @functions = {}
+ @default = nil
+ yield(self) if block_given?
+ end
+ attr_reader :functions
+
+ def register(key, function = nil, &bl)
+ functions[key] = function || bl
+ end
+
+ def default(function = nil, &bl)
+ @default = function || bl
+ end
+
+ def ignore(key)
+ register(key, lambda{|v1,v2| throw :ignore })
+ end
+
+ def merge(t1, t2)
+ tuple = {}
+ t1.keys.each do |k|
+ next unless fn = functions[k] || @default
+ catch :ignore do
+ tuple[k] = fn.call(t1[k], t2[k])
+ end
+ end
+ tuple
+ end
+
+ def aggregate(enum)
+ memo = nil
+ enum.each do |tuple|
+ memo = memo ? merge(memo, tuple) : tuple
+ end
+ memo
+ end
+
+ end # class Aggregator
+ end # module Utils
+end # module Stamina
@@ -0,0 +1,46 @@
+require 'stamina_test'
+module Stamina
+ module Utils
+ class AggregatorTest < ::Stamina::StaminaTest
+
+ def aggregator
+ Aggregator.new{|g|
+ g.register :price, &:+
+ g.register :origin, &:|
+ g.ignore :foo
+ g.default{|v1,v2| :def}
+ }
+ end
+
+ def test_merge
+ expected = { :price => 30, :origin => [:s1, :s2] }
+ left = { :price => 10, :origin => [:s1] }
+ right = { :price => 20, :origin => [:s2] }
+ assert_equal expected, aggregator.merge(left, right)
+ end
+
+ def test_merge_with_default
+ expected = { :price => 30, :test => :def }
+ left = { :price => 10, :test => :foo }
+ right = { :price => 20, :test => :bar }
+ assert_equal expected, aggregator.merge(left, right)
+ end
+
+ def test_merge_with_ignore
+ expected = { :price => 30 }
+ left = { :price => 10, :foo => :bar }
+ right = { :price => 20, :foo => :bar2 }
+ assert_equal expected, aggregator.merge(left, right)
+ end
+
+ def test_aggregate
+ expected = { :price => 35, :origin => [:s1, :s2] }
+ t1 = { :price => 10, :origin => [:s1] }
+ t2 = { :price => 20, :origin => [:s2] }
+ t3 = { :price => 5, :origin => [:s2] }
+ assert_equal expected, aggregator.aggregate([t1, t2, t3])
+ end
+
+ end
+ end
+end

0 comments on commit 668cadb

Please sign in to comment.