flipper-mongo 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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