flipper-mongo 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Gemfile CHANGED
@@ -15,5 +15,6 @@ group(:test) do
15
15
  gem 'timecop'
16
16
  gem 'bson_ext'
17
17
  gem 'mongo'
18
+ gem 'rack-test'
18
19
  end
19
20
 
@@ -1,7 +1,7 @@
1
1
  module Flipper
2
2
  module Adapters
3
3
  class Mongo
4
- VERSION = "0.2.1"
4
+ VERSION = "0.2.2"
5
5
  end
6
6
  end
7
7
  end
@@ -11,13 +11,43 @@ module Flipper
11
11
  def initialize(collection, options = {})
12
12
  @collection = collection
13
13
  @options = options
14
+ @document_cache = false
14
15
  end
15
16
 
16
17
  def_delegators :document, :read, :write, :delete, :set_members, :set_add, :set_delete
17
18
 
19
+ def using_document_cache?
20
+ @document_cache == true
21
+ end
22
+
23
+ def document_cache=(value)
24
+ reset_document_cache
25
+ @document_cache = value
26
+ end
27
+
28
+ def use_document_cache(&block)
29
+ original = @document_cache
30
+ @document_cache = true
31
+ yield
32
+ ensure
33
+ @document_cache = original
34
+ end
35
+
36
+ def reset_document_cache
37
+ @document = nil
38
+ end
39
+
18
40
  private
19
41
 
20
42
  def document
43
+ if @document_cache == true
44
+ @document ||= fresh_document
45
+ else
46
+ fresh_document
47
+ end
48
+ end
49
+
50
+ def fresh_document
21
51
  Document.new(@collection, :id => @options[:id])
22
52
  end
23
53
  end
@@ -0,0 +1,36 @@
1
+ module Flipper
2
+ module Middleware
3
+ class MongoSingleDocumentQueryCache
4
+ class Body
5
+ def initialize(target, adapter, original)
6
+ @target = target
7
+ @adapter = adapter
8
+ @original = original
9
+ end
10
+
11
+ def each(&block)
12
+ @target.each(&block)
13
+ end
14
+
15
+ def close
16
+ @target.close if @target.respond_to?(:close)
17
+ ensure
18
+ @adapter.document_cache = @original
19
+ end
20
+ end
21
+
22
+ def initialize(app, adapter)
23
+ @app = app
24
+ @adapter = adapter
25
+ end
26
+
27
+ def call(env)
28
+ original = @adapter.using_document_cache?
29
+ @adapter.document_cache = true
30
+
31
+ status, headers, body = @app.call(env)
32
+ [status, headers, Body.new(body, @adapter, original)]
33
+ end
34
+ end
35
+ end
36
+ end
@@ -35,5 +35,59 @@ describe Flipper::Adapters::MongoSingleDocument do
35
35
  collection.update criteria, updates, options
36
36
  end
37
37
 
38
- it_should_behave_like 'a flipper adapter'
38
+ context "with cache" do
39
+ before do
40
+ subject.document_cache = true
41
+ end
42
+
43
+ it_should_behave_like 'a flipper adapter'
44
+
45
+ it "should only query mongo once until reloaded" do
46
+ collection.should_receive(:find_one).with(criteria).once.and_return({})
47
+ subject.read('foo')
48
+ subject.read('foo')
49
+ subject.read('foo')
50
+ subject.set_members('users')
51
+
52
+ subject.reset_document_cache
53
+
54
+ collection.should_receive(:find_one).with(criteria).once.and_return({})
55
+ subject.read('foo')
56
+ subject.read('foo')
57
+ subject.set_members('users')
58
+ end
59
+ end
60
+
61
+ context "without cache" do
62
+ before do
63
+ subject.document_cache = false
64
+ end
65
+
66
+ it_should_behave_like 'a flipper adapter'
67
+ end
68
+
69
+ describe "#use_document_cache" do
70
+ it "turns cache on for block and restores to original after block" do
71
+ subject.using_document_cache?.should be_false
72
+ subject.use_document_cache do
73
+ subject.using_document_cache?.should be_true
74
+ end
75
+ subject.using_document_cache?.should be_false
76
+ end
77
+ end
78
+
79
+ describe "#document_cache=" do
80
+ it "sets document cache" do
81
+ subject.document_cache = true
82
+ subject.using_document_cache?.should be_true
83
+
84
+ subject.document_cache = false
85
+ subject.using_document_cache?.should be_false
86
+ end
87
+
88
+ it "resets cached document" do
89
+ subject.should_receive(:reset_document_cache)
90
+ subject.document_cache = true
91
+ end
92
+ end
39
93
  end
@@ -0,0 +1,121 @@
1
+ require 'helper'
2
+ require 'rack/test'
3
+ require 'flipper/middleware/mongo_single_document_query_cache'
4
+
5
+ describe Flipper::Middleware::MongoSingleDocumentQueryCache do
6
+ include Rack::Test::Methods
7
+
8
+ let(:collection) { Mongo::Connection.new.db('testing')['testing'] }
9
+ let(:adapter) { Flipper::Adapters::MongoSingleDocument.new(collection) }
10
+ let(:flipper) { Flipper.new(adapter) }
11
+
12
+ class Enum < Struct.new(:iter)
13
+ def each(&b)
14
+ iter.call(&b)
15
+ end
16
+ end
17
+
18
+ let(:app) {
19
+ # ensure scoped for builder block, annoying...
20
+ instance = adapter
21
+ middleware = described_class
22
+
23
+ Rack::Builder.new do
24
+ use middleware, instance
25
+
26
+ map "/" do
27
+ run lambda {|env| [200, {}, []] }
28
+ end
29
+
30
+ map "/fail" do
31
+ run lambda {|env| raise "FAIL!" }
32
+ end
33
+ end.to_app
34
+ }
35
+
36
+ it "delegates" do
37
+ called = false
38
+ app = lambda { |env|
39
+ called = true
40
+ [200, {}, nil]
41
+ }
42
+ middleware = described_class.new app, adapter
43
+ middleware.call({})
44
+ called.should be_true
45
+ end
46
+
47
+ it "enables document cache during delegation" do
48
+ app = lambda { |env|
49
+ adapter.using_document_cache?.should be_true
50
+ [200, {}, nil]
51
+ }
52
+ middleware = described_class.new app, adapter
53
+ middleware.call({})
54
+ end
55
+
56
+ it "enables document cache for body each" do
57
+ app = lambda { |env|
58
+ [200, {}, Enum.new(lambda { |&b|
59
+ adapter.using_document_cache?.should be_true
60
+ b.call "hello"
61
+ })]
62
+ }
63
+ middleware = described_class.new app, adapter
64
+ body = middleware.call({}).last
65
+ body.each { |x| x.should eql('hello') }
66
+ end
67
+
68
+ it "disables document cache after body close" do
69
+ app = lambda { |env| [200, {}, []] }
70
+ middleware = described_class.new app, adapter
71
+ body = middleware.call({}).last
72
+
73
+ adapter.using_document_cache?.should be_true
74
+ body.close
75
+ adapter.using_document_cache?.should be_false
76
+ end
77
+
78
+ it "clears document cache after body close" do
79
+ app = lambda { |env| [200, {}, []] }
80
+ middleware = described_class.new app, adapter
81
+ body = middleware.call({}).last
82
+ adapter.write('hello', 'world')
83
+
84
+ adapter.instance_variable_get("@document").should_not be_nil
85
+ body.close
86
+ adapter.instance_variable_get("@document").should be_nil
87
+ end
88
+
89
+ it "really does cache" do
90
+ flipper[:stats].enable
91
+
92
+ collection.should_receive(:find_one).once.and_return({})
93
+
94
+ app = lambda { |env|
95
+ flipper[:stats].enabled?
96
+ flipper[:stats].enabled?
97
+ flipper[:stats].enabled?
98
+ flipper[:stats].enabled?
99
+ flipper[:stats].enabled?
100
+ flipper[:stats].enabled?
101
+
102
+ [200, {}, []]
103
+ }
104
+ middleware = described_class.new app, adapter
105
+ middleware.call({})
106
+ end
107
+
108
+ context "with a successful request" do
109
+ it "clears the document cache" do
110
+ adapter.should_receive(:reset_document_cache).twice
111
+ get '/'
112
+ end
113
+ end
114
+
115
+ context "when the request raises an error" do
116
+ it "clears the document cache" do
117
+ adapter.should_receive(:reset_document_cache).once
118
+ get '/fail' rescue nil
119
+ end
120
+ end
121
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flipper-mongo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-07 00:00:00.000000000 Z
12
+ date: 2012-08-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: flipper
16
- requirement: &70319593304120 !ruby/object:Gem::Requirement
16
+ requirement: &70110164650060 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: '0.2'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70319593304120
24
+ version_requirements: *70110164650060
25
25
  description: Mongo adapter for Flipper
26
26
  email:
27
27
  - nunemaker@gmail.com
@@ -41,9 +41,11 @@ files:
41
41
  - lib/flipper/adapters/mongo/document.rb
42
42
  - lib/flipper/adapters/mongo/version.rb
43
43
  - lib/flipper/adapters/mongo_single_document.rb
44
+ - lib/flipper/middleware/mongo_single_document_query_cache.rb
44
45
  - spec/flipper/adapters/mongo/document_spec.rb
45
46
  - spec/flipper/adapters/mongo_single_document_spec.rb
46
47
  - spec/flipper/adapters/mongo_spec.rb
48
+ - spec/flipper/middleware/mongo_single_document_query_cache_spec.rb
47
49
  - spec/helper.rb
48
50
  - spec/support/accessor_helpers.rb
49
51
  homepage: http://jnunemaker.github.com/flipper-mongo
@@ -60,7 +62,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
60
62
  version: '0'
61
63
  segments:
62
64
  - 0
63
- hash: 3598565635761616349
65
+ hash: -3406714501289693291
64
66
  required_rubygems_version: !ruby/object:Gem::Requirement
65
67
  none: false
66
68
  requirements:
@@ -69,7 +71,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
69
71
  version: '0'
70
72
  segments:
71
73
  - 0
72
- hash: 3598565635761616349
74
+ hash: -3406714501289693291
73
75
  requirements: []
74
76
  rubyforge_project:
75
77
  rubygems_version: 1.8.10
@@ -80,5 +82,6 @@ test_files:
80
82
  - spec/flipper/adapters/mongo/document_spec.rb
81
83
  - spec/flipper/adapters/mongo_single_document_spec.rb
82
84
  - spec/flipper/adapters/mongo_spec.rb
85
+ - spec/flipper/middleware/mongo_single_document_query_cache_spec.rb
83
86
  - spec/helper.rb
84
87
  - spec/support/accessor_helpers.rb