Skip to content
This repository
Browse code

Added the batcher class.

  • Loading branch information...
commit 49dfd4ffdf7859cf3977e8efe2be0b03fc31637d 1 parent 48c40a9
Thorbjørn Hermansen authored January 21, 2012 alindeman committed January 28, 2012
76  sunspot/lib/sunspot/batcher.rb
... ...
@@ -0,0 +1,76 @@
  1
+module Sunspot
  2
+
  3
+  #
  4
+  # Keeps a stack of batches and helps out when Indexer is asked to batch documents.
  5
+  #
  6
+  # If the client does something like 
  7
+  #   
  8
+  #   Sunspot.batch do
  9
+  #     some_code_here
  10
+  #     which_triggers_some_other_code
  11
+  #     which_again_calls
  12
+  #     Sunspot.batch { ... }
  13
+  #   end
  14
+  #
  15
+  # it is the Batcher's job to keep track of these nestings. The inner will
  16
+  # be sent of to be indexed first.
  17
+  #
  18
+  class Batcher
  19
+    include Enumerable
  20
+
  21
+    # Raised if you ask to end current, but no current exists
  22
+    class NoCurrentBatchError < StandardError; end
  23
+
  24
+
  25
+    def initialize
  26
+      @stack = []
  27
+    end
  28
+
  29
+
  30
+
  31
+    def current
  32
+      stack.last or start_new
  33
+    end
  34
+
  35
+    def start_new
  36
+      (stack << []).last
  37
+    end
  38
+
  39
+    def end_current
  40
+      fail NoCurrentBatchError if stack.empty?
  41
+
  42
+      stack.pop
  43
+    end
  44
+
  45
+
  46
+
  47
+    def depth
  48
+      stack.length
  49
+    end
  50
+
  51
+    def batching?
  52
+      depth > 0
  53
+    end
  54
+
  55
+
  56
+
  57
+    def each
  58
+      current.each { |v| yield v }
  59
+    end
  60
+
  61
+    def push(value)
  62
+      current << value
  63
+    end
  64
+    alias << push
  65
+
  66
+    def concat(values)
  67
+      current.concat values
  68
+    end
  69
+
  70
+
  71
+
  72
+    private
  73
+
  74
+    attr_reader :stack
  75
+  end
  76
+end
2  sunspot/lib/sunspot/indexer.rb
... ...
@@ -1,3 +1,5 @@
  1
+require 'sunspot/batcher'
  2
+
1 3
 module Sunspot
2 4
   # 
3 5
   # This class presents a service for adding, updating, and removing data
112  sunspot/spec/api/batcher_spec.rb
... ...
@@ -0,0 +1,112 @@
  1
+require File.expand_path('spec_helper', File.dirname(__FILE__))
  2
+
  3
+describe Sunspot::Batcher do
  4
+  it "includes Enumerable" do
  5
+    described_class.should include Enumerable
  6
+  end
  7
+
  8
+  describe "#each" do
  9
+    let(:current) { [:foo, :bar] }
  10
+    before { subject.stub(:current).and_return current }
  11
+
  12
+    it "iterates over current" do
  13
+      yielded_values = []
  14
+
  15
+      subject.each do |value|
  16
+        yielded_values << value
  17
+      end
  18
+
  19
+      yielded_values.should eq current
  20
+    end
  21
+  end
  22
+
  23
+  describe "adding to current batch" do
  24
+    it "#push pushes to current" do
  25
+      subject.push :foo
  26
+      subject.current.should include :foo
  27
+    end
  28
+
  29
+    it "#<< pushes to current" do
  30
+      subject.push :foo
  31
+      subject.current.should include :foo
  32
+    end
  33
+
  34
+    it "#concat concatinates on current batch" do
  35
+      subject << :foo
  36
+      subject.concat [:bar, :mix]
  37
+      should include :foo, :bar, :mix
  38
+    end
  39
+  end
  40
+
  41
+
  42
+  describe "#current" do
  43
+    context "no current" do
  44
+      it "starts a new" do
  45
+        expect { subject.current }.to change(subject, :depth).by 1
  46
+      end
  47
+
  48
+      it "is empty by default" do
  49
+        subject.current.should be_empty
  50
+      end
  51
+    end
  52
+
  53
+    context "with a current" do
  54
+      before { subject.start_new }
  55
+
  56
+      it "does not start a new" do
  57
+        expect { subject.current }.to_not change(subject, :depth)
  58
+      end
  59
+
  60
+      it "returns the same as last time" do
  61
+        subject.current.should eq subject.current
  62
+      end
  63
+    end
  64
+  end
  65
+
  66
+  describe "#start_new" do
  67
+    it "creates a new batches" do
  68
+      expect { 2.times { subject.start_new } }.to change(subject, :depth).by 2
  69
+    end
  70
+
  71
+    it "changes current" do
  72
+      subject << :foo
  73
+      subject.start_new
  74
+      should_not include :foo
  75
+    end
  76
+  end
  77
+
  78
+  describe "#end_current" do
  79
+    context "no current batch" do
  80
+      it "fails" do
  81
+        expect { subject.end_current }.to raise_error Sunspot::Batcher::NoCurrentBatchError
  82
+      end
  83
+    end
  84
+
  85
+    context "with current batch" do
  86
+      before { subject.start_new }
  87
+
  88
+      it "changes current" do
  89
+        subject << :foo
  90
+        subject.end_current
  91
+        should_not include :foo
  92
+      end
  93
+
  94
+      it "returns current" do
  95
+        subject << :foo
  96
+        subject.end_current.should include :foo
  97
+      end
  98
+    end
  99
+  end
  100
+
  101
+  describe "#batching?" do
  102
+    it "is false when depth is 0" do
  103
+      subject.should_receive(:depth).and_return 0
  104
+      should_not be_batching
  105
+    end
  106
+
  107
+    it "is true when depth is more than 0" do
  108
+      subject.should_receive(:depth).and_return 1
  109
+      should be_batching
  110
+    end
  111
+  end
  112
+end

0 notes on commit 49dfd4f

Please sign in to comment.
Something went wrong with that request. Please try again.