bin 0.6.3 → 0.7.0

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.
@@ -0,0 +1,2 @@
1
+ log
2
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'bson_ext', :require => false
4
+
5
+ gemspec
6
+
7
+ gem 'i18n'
8
+ gem 'rake'
9
+ gem 'rspec'
10
+ gem 'log_buddy'
11
+ gem 'SystemTimer'
@@ -0,0 +1,42 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ bin (0.6.3)
5
+ activesupport (~> 3.1.0)
6
+ mongo (~> 1.3.0)
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ SystemTimer (1.2.1)
12
+ activesupport (3.1.0)
13
+ multi_json (~> 1.0)
14
+ bson (1.3.1)
15
+ bson_ext (1.3.1)
16
+ diff-lcs (1.1.3)
17
+ i18n (0.6.0)
18
+ log_buddy (0.6.0)
19
+ mongo (1.3.1)
20
+ bson (>= 1.3.1)
21
+ multi_json (1.0.3)
22
+ rake (0.9.2)
23
+ rspec (2.6.0)
24
+ rspec-core (~> 2.6.0)
25
+ rspec-expectations (~> 2.6.0)
26
+ rspec-mocks (~> 2.6.0)
27
+ rspec-core (2.6.4)
28
+ rspec-expectations (2.6.0)
29
+ diff-lcs (~> 1.1.2)
30
+ rspec-mocks (2.6.0)
31
+
32
+ PLATFORMS
33
+ ruby
34
+
35
+ DEPENDENCIES
36
+ SystemTimer
37
+ bin!
38
+ bson_ext
39
+ i18n
40
+ log_buddy
41
+ rake
42
+ rspec
@@ -4,8 +4,29 @@ ActiveSupport MongoDB Cache store.
4
4
 
5
5
  == Supports
6
6
 
7
- * Ruby 1.8.7 and Ruby 1.9.1.
8
- * ActiveSupport 2 and 3
7
+ * Ruby 1.8.7 and 1.9.2+
8
+ * ActiveSupport 3+
9
+
10
+ == Installation and Usage
11
+
12
+ gem install bin
13
+
14
+ require 'bin'
15
+
16
+ collection = Mongo::Connection.new.db('testing')['testing']
17
+ collection.remove
18
+
19
+ bin = Bin::Store.new(collection)
20
+ bin.write('abc', 123)
21
+ pp bin.read('abc')
22
+
23
+ pp bin.read('def')
24
+ pp bin.fetch('def') { 456 }
25
+ pp bin.read('def')
26
+
27
+ Using bin with rails is as easy as:
28
+
29
+ config.cache_store = :bin, Mongo::Connection.new.db('myapp')['cache']
9
30
 
10
31
  == Note on Patches/Pull Requests
11
32
 
data/Rakefile CHANGED
@@ -1,45 +1,7 @@
1
- require 'rubygems'
2
- require 'rake'
3
- require 'spec/rake/spectask'
4
- require File.expand_path('../lib/bin/version', __FILE__)
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
5
3
 
6
- namespace :spec do
7
- Spec::Rake::SpecTask.new(:all) do |t|
8
- t.ruby_opts << '-rubygems'
9
- t.verbose = true
10
- end
11
-
12
- task :as2 do
13
- sh 'ACTIVE_SUPPORT_VERSION="<= 2.3.8" rake spec:all'
14
- end
15
-
16
- task :as3 do
17
- sh 'ACTIVE_SUPPORT_VERSION=">= 3.0.0.beta3" rake spec:all'
18
- end
19
- end
20
-
21
- desc 'Runs all specs against Active Support 2 and 3'
22
- task :spec do
23
- Rake::Task['spec:as2'].invoke
24
- Rake::Task['spec:as3'].invoke
25
- end
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new
26
6
 
27
7
  task :default => :spec
28
-
29
- desc 'Builds the gem'
30
- task :build do
31
- sh "gem build bin.gemspec"
32
- end
33
-
34
- desc 'Builds and installs the gem'
35
- task :install => :build do
36
- sh "gem install bin-#{Bin::Version}"
37
- end
38
-
39
- desc 'Tags version, pushes to remote, and pushes gem'
40
- task :release => :build do
41
- sh "git tag v#{Bin::Version}"
42
- sh "git push origin master"
43
- sh "git push origin v#{Bin::Version}"
44
- sh "gem push bin-#{Bin::Version}.gem"
45
- end
@@ -0,0 +1,21 @@
1
+ # encoding: UTF-8
2
+ require File.expand_path('../lib/bin/version', __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'bin'
6
+ s.version = Bin::Version
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ['John Nunemaker']
9
+ s.email = ['nunemaker@gmail.com']
10
+ s.homepage = 'http://github.com/jnunemaker/bin'
11
+ s.summary = 'ActiveSupport MongoDB Cache store.'
12
+ s.description = 'ActiveSupport MongoDB Cache store.'
13
+
14
+ s.add_dependency 'mongo', '~> 1.3.0'
15
+ s.add_dependency 'activesupport', '~> 3.1.0'
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ end
@@ -0,0 +1,18 @@
1
+ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
2
+ require 'active_support/all'
3
+ require 'bin'
4
+ require 'pp'
5
+
6
+ collection = Mongo::Connection.new.db('testing')['testing']
7
+ collection.remove
8
+
9
+ bin = Bin::Store.new(collection)
10
+ bin.write('abc', 123)
11
+ pp bin.read('abc')
12
+
13
+ pp bin.read('def')
14
+ pp bin.fetch('def') { 456 }
15
+ pp bin.read('def')
16
+
17
+ bin.delete('abc')
18
+ bin.delete('def')
@@ -0,0 +1,82 @@
1
+ require 'mongo'
2
+
3
+ module ActiveSupport
4
+ module Cache
5
+ class Bin < Store
6
+ attr_reader :collection, :options
7
+
8
+ def initialize(collection, options={})
9
+ @collection, @options = collection, options
10
+ end
11
+
12
+ def expires_in
13
+ @expires_in ||= options[:expires_in] || 1.year
14
+ end
15
+
16
+ def delete_matched(matcher, options=nil)
17
+ collection.remove(:_id => matcher)
18
+ end
19
+
20
+ def increment(key, amount=1, options=nil)
21
+ counter_key_upsert(:increment, key, amount, options)
22
+ end
23
+
24
+ def decrement(key, amount=1, options=nil)
25
+ counter_key_upsert(:decrement, key, -amount.abs, options)
26
+ end
27
+
28
+ def clear
29
+ collection.remove
30
+ end
31
+
32
+ def stats
33
+ collection.stats
34
+ end
35
+
36
+ private
37
+ def counter_key_upsert(action, key, amount, options)
38
+ options = merged_options(options)
39
+ instrument(action, key, :amount => amount) do
40
+ key = namespaced_key(key, options)
41
+ collection.update(
42
+ {:_id => key}, {
43
+ '$inc' => {:value => amount},
44
+ '$set' => {
45
+ :expires_at => Time.now.utc + 1.year,
46
+ :raw => true
47
+ },
48
+ }, :upsert => true)
49
+ end
50
+ end
51
+
52
+ def deserialize_doc(doc)
53
+ return nil if doc.nil?
54
+
55
+ entry = doc['raw'] ? doc['value'] : Marshal.load(doc['value'].to_s)
56
+ entry.is_a?(Entry) ? entry : Entry.new(entry)
57
+ end
58
+
59
+ def read_entry(key, options)
60
+ query = {:_id => key, :expires_at => {'$gt' => Time.now.utc}}
61
+ deserialize_doc(collection.find_one(query))
62
+ end
63
+
64
+ def write_entry(key, entry, options)
65
+ expires = Time.now.utc + options.fetch(:expires_in, expires_in)
66
+ value = options[:raw] ? entry.value : BSON::Binary.new(Marshal.dump(entry.value))
67
+ query = {:_id => key}
68
+ updates = {'$set' => {
69
+ :value => value,
70
+ :expires_at => expires,
71
+ :raw => options[:raw],
72
+ }}
73
+
74
+ collection.update(query, updates, :upsert => true)
75
+ end
76
+
77
+ def delete_entry(key, options)
78
+ collection.remove(:_id => key)
79
+ end
80
+ end
81
+ end
82
+ end
data/lib/bin.rb CHANGED
@@ -1,10 +1,5 @@
1
- # encoding: UTF-8
2
- require 'active_support/all'
3
- require 'active_support/version'
4
- require 'mongo'
1
+ require 'active_support/cache/bin'
5
2
 
6
3
  module Bin
7
- autoload :Compatibility, 'bin/compatibility'
8
- autoload :Store, 'bin/store'
9
- autoload :Version, 'bin/version'
4
+ Store = ActiveSupport::Cache::Bin
10
5
  end
@@ -1,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  module Bin
3
- Version = '0.6.3'
2
+ Version = '0.7.0'
4
3
  end
@@ -1,15 +1,207 @@
1
1
  require 'helper'
2
2
 
3
- describe Bin do
4
- it "autoloads Store" do
5
- lambda { Bin::Store }.should_not raise_error(NameError)
3
+ describe ActiveSupport::Cache::Bin do
4
+ let(:collection) { DB['bin_cache'] }
5
+ let(:store) { ActiveSupport::Cache::Bin.new(collection) }
6
+
7
+ it "has a collection" do
8
+ store.collection.should == collection
9
+ end
10
+
11
+ it "should also work with Bin::Store for backwards compat" do
12
+ Bin::Store.should == ActiveSupport::Cache::Bin
13
+ end
14
+
15
+ it "defaults expires_in to 1.year" do
16
+ store.expires_in.should == 1.year
17
+ end
18
+
19
+ it "can set default expires_in" do
20
+ ActiveSupport::Cache::Bin.new(collection, :expires_in => 5.minutes).expires_in.should == 5.minutes
21
+ end
22
+
23
+ describe "#write" do
24
+ before(:each) do
25
+ store.write('foo', 'bar')
26
+ end
27
+ let(:document) { collection.find_one(:_id => 'foo') }
28
+
29
+ it "sets _id to key" do
30
+ document['_id'].should == 'foo'
31
+ end
32
+
33
+ it "sets value key to value" do
34
+ store.read('foo').should == 'bar'
35
+ end
36
+
37
+ it "should marshal value by default" do
38
+ document['value'].to_s.should == BSON::Binary.new(Marshal.dump('bar')).to_s
39
+ document['raw'].should be_false
40
+ end
41
+
42
+ it "should be able to store in raw format" do
43
+ store.write('foo', 'bar', :raw => true)
44
+ document['value'].should == 'bar'
45
+ document['raw'].should be_true
46
+ end
47
+
48
+ it "sets expires in to default if not provided" do
49
+ document['expires_at'].to_i.should == (Time.now.utc + 1.year).to_i
50
+ end
51
+
52
+ it "sets expires_at if expires_in provided" do
53
+ store.write('foo', 'bar', :expires_in => 5.seconds)
54
+ document['expires_at'].to_i.should == (Time.now.utc + 5.seconds).to_i
55
+ end
56
+
57
+ it "always sets key as string" do
58
+ store.write(:baz, 'wick')
59
+ doc = collection.find_one(:_id => 'baz')
60
+ doc.should_not be_nil
61
+ doc['_id'].should be_instance_of(String)
62
+ end
6
63
  end
7
64
 
8
- it "autoloads Compatibility" do
9
- lambda { Bin::Compatibility }.should_not raise_error(NameError)
65
+ describe "#read" do
66
+ before(:each) do
67
+ store.write('foo', 'bar')
68
+ end
69
+ let(:document) { collection.find_one(:_id => 'foo') }
70
+
71
+ it "returns nil for key not found" do
72
+ store.read('non:existent:key').should be_nil
73
+ end
74
+
75
+ it "returns unmarshalled value key value for key found" do
76
+ store.read('foo').should == 'bar'
77
+ end
78
+
79
+ it "returns raw value if document raw key is true" do
80
+ store.write('foo', 'bar', :raw => true)
81
+ store.read('foo').should == 'bar'
82
+ end
83
+
84
+ it "returns nil for existing but expired key" do
85
+ collection.save(:_id => 'foo', :value => 'bar', :expires_at => 5.seconds.ago)
86
+ store.read('foo').should be_nil
87
+ end
88
+
89
+ it "return value for existing and not expired key" do
90
+ store.write('foo', 'bar', :expires_in => 20.seconds)
91
+ store.read('foo').should == 'bar'
92
+ end
93
+
94
+ it "works with symbol" do
95
+ store.read(:foo).should == 'bar'
96
+ end
97
+ end
98
+
99
+ describe "#delete" do
100
+ before(:each) do
101
+ store.write('foo', 'bar')
102
+ end
103
+
104
+ it "delete key from cache" do
105
+ store.read('foo').should_not be_nil
106
+ store.delete('foo')
107
+ store.read('foo').should be_nil
108
+ end
109
+
110
+ it "works with symbol" do
111
+ store.read(:foo).should_not be_nil
112
+ store.delete(:foo)
113
+ store.read(:foo).should be_nil
114
+ end
115
+ end
116
+
117
+ describe "#delete_matched" do
118
+ before(:each) do
119
+ store.write('foo1', 'bar')
120
+ store.write('foo2', 'bar')
121
+ store.write('baz', 'wick')
122
+ end
123
+
124
+ it "deletes matching keys" do
125
+ store.read('foo1').should_not be_nil
126
+ store.read('foo2').should_not be_nil
127
+ store.delete_matched(/foo/)
128
+ store.read('foo1').should be_nil
129
+ store.read('foo2').should be_nil
130
+ end
131
+
132
+ it "does not delete unmatching keys" do
133
+ store.delete_matched('foo')
134
+ store.read('baz').should_not be_nil
135
+ end
136
+ end
137
+
138
+ describe "#exist?" do
139
+ before(:each) do
140
+ store.write('foo', 'bar')
141
+ end
142
+
143
+ it "returns true if key found" do
144
+ store.exist?('foo').should be_true
145
+ end
146
+
147
+ it "returns false if key not found" do
148
+ store.exist?('not:found:key').should be_false
149
+ end
150
+
151
+ it "works with symbol" do
152
+ store.exist?(:foo).should be_true
153
+ store.exist?(:notfoundkey).should be_false
154
+ end
155
+ end
156
+
157
+ describe "#clear" do
158
+ before(:each) do
159
+ store.write('foo', 'bar')
160
+ store.write('baz', 'wick')
161
+ end
162
+
163
+ it "clear all keys" do
164
+ collection.count.should == 2
165
+ store.clear
166
+ collection.count.should == 0
167
+ end
168
+ end
169
+
170
+ describe "#increment" do
171
+ it "increment key by amount" do
172
+ store.increment('views', 1)
173
+ store.read('views').should == 1
174
+ store.increment('views', 2)
175
+ store.read('views').should == 3
176
+ end
177
+
178
+ it "works with symbol" do
179
+ store.increment(:views, 2)
180
+ store.read(:views).should == 2
181
+ end
182
+ end
183
+
184
+ describe "#decrement" do
185
+ it "decrement key by amount" do
186
+ store.increment('views', 5)
187
+ store.decrement('views', 2)
188
+ store.read('views').should == 3
189
+ store.decrement('views', 2)
190
+ store.read('views').should == 1
191
+ end
192
+
193
+ it "works with symbol" do
194
+ store.increment(:views, 2)
195
+ store.decrement(:views, 1)
196
+ store.read(:views).should == 1
197
+ end
10
198
  end
11
199
 
12
- it "autoloads Version" do
13
- lambda { Bin::Version }.should_not raise_error(NameError)
200
+ describe "#stats" do
201
+ it "returns stats" do
202
+ %w[ns count size].each do |key|
203
+ store.stats.should have_key(key)
204
+ end
205
+ end
14
206
  end
15
207
  end
@@ -1,11 +1,21 @@
1
- gem 'activesupport', ENV['ACTIVE_SUPPORT_VERSION']
2
-
3
1
  $:.unshift(File.expand_path('../../lib', __FILE__))
4
2
 
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ require 'active_support/all'
6
+
7
+ Bundler.require(:default)
8
+
5
9
  require 'bin'
6
- require 'spec'
7
10
 
8
11
  connection = Mongo::Connection.new
9
- DB = connection.db('bin-store-test')
12
+ DB = connection.db('test')
10
13
 
11
- puts "\n--- Active Support Version: #{ActiveSupport::VERSION::STRING} ---\n"
14
+ RSpec.configure do |c|
15
+ c.before(:each) do
16
+ DB.collections.each do |collection|
17
+ collection.remove
18
+ collection.drop_indexes
19
+ end
20
+ end
21
+ end
@@ -1,4 +1,3 @@
1
1
  --colour
2
2
  --timeout
3
- 20
4
- --diff
3
+ 20
@@ -0,0 +1,46 @@
1
+ def growl(title, msg, img)
2
+ %x{growlnotify -m #{ msg.inspect} -t #{title.inspect} --image ~/.watchr/#{img}.png}
3
+ end
4
+
5
+ def form_growl_message(str)
6
+ msg = str.split("\n").last
7
+ if msg =~ /(\d)\sfailure/
8
+ img = $1.to_i > 0 ? 'fail' : 'pass'
9
+ end
10
+ growl 'Results', msg, img
11
+ end
12
+
13
+ def run(cmd)
14
+ puts cmd
15
+ output = ""
16
+ IO.popen(cmd) do |com|
17
+ com.each_char do |c|
18
+ print c
19
+ output << c
20
+ $stdout.flush
21
+ end
22
+ end
23
+ form_growl_message output
24
+ end
25
+
26
+ def run_spec(path)
27
+ path.gsub!('lib/', 'spec/')
28
+ path.gsub!('_spec', '')
29
+ file_name = File.basename(path, '.rb')
30
+ path.gsub!(file_name, file_name + "_spec")
31
+ run %Q(spec #{path})
32
+ end
33
+
34
+ watch('spec/helper\.rb') { system('clear'); run('rake') }
35
+ watch('lib/.*\.rb') { |m| system('clear'); run_spec(m[0]) }
36
+ watch('spec/.*_spec\.rb') { |m| system('clear'); run_spec(m[0]) }
37
+
38
+ # Ctrl-\
39
+ Signal.trap('QUIT') do
40
+ puts " --- Running all tests ---\n\n"
41
+ run('rake')
42
+ end
43
+
44
+ # Ctrl-C
45
+ Signal.trap('INT') { abort("\n") }
46
+
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bin
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
4
+ hash: 3
5
+ prerelease:
5
6
  segments:
6
7
  - 0
7
- - 6
8
- - 3
9
- version: 0.6.3
8
+ - 7
9
+ - 0
10
+ version: 0.7.0
10
11
  platform: ruby
11
12
  authors:
12
13
  - John Nunemaker
@@ -14,51 +15,41 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-06-15 00:00:00 -04:00
18
- default_executable:
18
+ date: 2011-09-17 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: mongo
22
22
  prerelease: false
23
23
  requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
24
25
  requirements:
25
26
  - - ~>
26
27
  - !ruby/object:Gem::Version
28
+ hash: 27
27
29
  segments:
28
30
  - 1
31
+ - 3
29
32
  - 0
30
- - 1
31
- version: 1.0.1
33
+ version: 1.3.0
32
34
  type: :runtime
33
35
  version_requirements: *id001
34
36
  - !ruby/object:Gem::Dependency
35
37
  name: activesupport
36
38
  prerelease: false
37
39
  requirement: &id002 !ruby/object:Gem::Requirement
38
- requirements:
39
- - - ">="
40
- - !ruby/object:Gem::Version
41
- segments:
42
- - 2
43
- - 3
44
- version: "2.3"
45
- type: :runtime
46
- version_requirements: *id002
47
- - !ruby/object:Gem::Dependency
48
- name: rspec
49
- prerelease: false
50
- requirement: &id003 !ruby/object:Gem::Requirement
40
+ none: false
51
41
  requirements:
52
42
  - - ~>
53
43
  - !ruby/object:Gem::Version
44
+ hash: 3
54
45
  segments:
55
- - 1
56
46
  - 3
47
+ - 1
57
48
  - 0
58
- version: 1.3.0
59
- type: :development
60
- version_requirements: *id003
61
- description:
49
+ version: 3.1.0
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ description: ActiveSupport MongoDB Cache store.
62
53
  email:
63
54
  - nunemaker@gmail.com
64
55
  executables: []
@@ -68,18 +59,21 @@ extensions: []
68
59
  extra_rdoc_files: []
69
60
 
70
61
  files:
71
- - lib/bin/compatibility.rb
72
- - lib/bin/store.rb
73
- - lib/bin/version.rb
62
+ - .gitignore
63
+ - Gemfile
64
+ - Gemfile.lock
65
+ - LICENSE
66
+ - README.rdoc
67
+ - Rakefile
68
+ - bin.gemspec
69
+ - examples/read_write_delete.rb
70
+ - lib/active_support/cache/bin.rb
74
71
  - lib/bin.rb
75
- - spec/bin/store_spec.rb
72
+ - lib/bin/version.rb
76
73
  - spec/bin_spec.rb
77
74
  - spec/helper.rb
78
75
  - spec/spec.opts
79
- - LICENSE
80
- - Rakefile
81
- - README.rdoc
82
- has_rdoc: true
76
+ - specs.watchr
83
77
  homepage: http://github.com/jnunemaker/bin
84
78
  licenses: []
85
79
 
@@ -89,25 +83,31 @@ rdoc_options: []
89
83
  require_paths:
90
84
  - lib
91
85
  required_ruby_version: !ruby/object:Gem::Requirement
86
+ none: false
92
87
  requirements:
93
88
  - - ">="
94
89
  - !ruby/object:Gem::Version
90
+ hash: 3
95
91
  segments:
96
92
  - 0
97
93
  version: "0"
98
94
  required_rubygems_version: !ruby/object:Gem::Requirement
95
+ none: false
99
96
  requirements:
100
97
  - - ">="
101
98
  - !ruby/object:Gem::Version
99
+ hash: 3
102
100
  segments:
103
101
  - 0
104
102
  version: "0"
105
103
  requirements: []
106
104
 
107
105
  rubyforge_project:
108
- rubygems_version: 1.3.6
106
+ rubygems_version: 1.8.9
109
107
  signing_key:
110
108
  specification_version: 3
111
109
  summary: ActiveSupport MongoDB Cache store.
112
- test_files: []
113
-
110
+ test_files:
111
+ - spec/bin_spec.rb
112
+ - spec/helper.rb
113
+ - spec/spec.opts
@@ -1,41 +0,0 @@
1
- # encoding: UTF-8
2
- module Bin
3
- class Compatibility < ActiveSupport::Cache::Store
4
- def increment(key, amount=1)
5
- yield
6
- end
7
-
8
- def decrement(key, amount=1)
9
- yield
10
- end
11
- end
12
-
13
- if ActiveSupport::VERSION::STRING < '3'
14
- class Compatibility
15
- def write(key, value, options=nil, &block)
16
- super(key, value, options)
17
- yield
18
- end
19
-
20
- def read(key, options=nil, &block)
21
- super
22
- yield
23
- end
24
-
25
- def delete(key, options=nil, &block)
26
- super
27
- yield
28
- end
29
-
30
- def delete_matched(matcher, options=nil, &block)
31
- super
32
- yield
33
- end
34
-
35
- def exist?(key, options=nil, &block)
36
- super
37
- yield
38
- end
39
- end
40
- end
41
- end
@@ -1,84 +0,0 @@
1
- # encoding: UTF-8
2
- module Bin
3
- class Store < Compatibility
4
- attr_reader :collection, :options
5
-
6
- def initialize(collection, options={})
7
- @collection, @options = collection, options
8
- end
9
-
10
- def expires_in
11
- @expires_in ||= options[:expires_in] || 1.year
12
- end
13
-
14
- def write(key, value, options={})
15
- key = key.to_s
16
- super do
17
- expires = Time.now.utc + ((options && options[:expires_in]) || expires_in)
18
- raw = !!options[:raw]
19
- value = raw ? value : BSON::Binary.new(Marshal.dump(value))
20
- doc = {:_id => key, :value => value, :expires_at => expires, :raw => raw}
21
- collection.save(doc)
22
- end
23
- end
24
-
25
- def read(key, options=nil)
26
- super do
27
- if doc = collection.find_one(:_id => key.to_s, :expires_at => {'$gt' => Time.now.utc})
28
- doc['raw'] ? doc['value'] : Marshal.load(doc['value'].to_s)
29
- end
30
- end
31
- end
32
-
33
- def delete(key, options=nil)
34
- super do
35
- collection.remove(:_id => key.to_s)
36
- end
37
- end
38
-
39
- def delete_matched(matcher, options=nil)
40
- super do
41
- collection.remove(:_id => matcher)
42
- end
43
- end
44
-
45
- def exist?(key, options=nil)
46
- super do
47
- !read(key, options).nil?
48
- end
49
- end
50
-
51
- def increment(key, amount=1)
52
- super do
53
- counter_key_upsert(key, amount)
54
- end
55
- end
56
-
57
- def decrement(key, amount=1)
58
- super do
59
- counter_key_upsert(key, -amount.abs)
60
- end
61
- end
62
-
63
- def clear
64
- collection.remove
65
- end
66
-
67
- def stats
68
- collection.stats
69
- end
70
-
71
- private
72
- def counter_key_upsert(key, amount)
73
- key = key.to_s
74
- collection.update(
75
- {:_id => key}, {
76
- '$inc' => {:value => amount},
77
- '$set' => {
78
- :expires_at => Time.now.utc + 1.year,
79
- :raw => true
80
- },
81
- }, :upsert => true)
82
- end
83
- end
84
- end
@@ -1,210 +0,0 @@
1
- require 'helper'
2
-
3
- describe Bin::Store do
4
- before(:each) do
5
- DB.collections.each do |collection|
6
- collection.remove
7
- collection.drop_indexes
8
- end
9
- end
10
-
11
- let(:collection) { DB['bin_cache'] }
12
- let(:store) { Bin::Store.new(collection) }
13
-
14
- it "has a collection" do
15
- store.collection.should == collection
16
- end
17
-
18
- it "defaults expires_in to 1.year" do
19
- store.expires_in.should == 1.year
20
- end
21
-
22
- it "can set default expires_in" do
23
- Bin::Store.new(collection, :expires_in => 5.minutes).expires_in.should == 5.minutes
24
- end
25
-
26
- describe "#write" do
27
- before(:each) do
28
- store.write('foo', 'bar')
29
- end
30
- let(:document) { collection.find_one(:_id => 'foo') }
31
-
32
- it "sets _id to key" do
33
- document['_id'].should == 'foo'
34
- end
35
-
36
- it "sets value key to value" do
37
- store.read('foo').should == 'bar'
38
- end
39
-
40
- it "should marshal value by default" do
41
- document['value'].to_s.should == BSON::Binary.new(Marshal.dump('bar')).to_s
42
- document['raw'].should be_false
43
- end
44
-
45
- it "should be able to store in raw format" do
46
- store.write('foo', 'bar', :raw => true)
47
- document['value'].should == 'bar'
48
- document['raw'].should be_true
49
- end
50
-
51
- it "sets expires in to default if not provided" do
52
- document['expires_at'].to_i.should == (Time.now.utc + 1.year).to_i
53
- end
54
-
55
- it "sets expires_at if expires_in provided" do
56
- store.write('foo', 'bar', :expires_in => 5.seconds)
57
- document['expires_at'].to_i.should == (Time.now.utc + 5.seconds).to_i
58
- end
59
-
60
- it "always sets key as string" do
61
- store.write(:baz, 'wick')
62
- doc = collection.find_one(:_id => 'baz')
63
- doc.should_not be_nil
64
- doc['_id'].should be_instance_of(String)
65
- end
66
- end
67
-
68
- describe "#read" do
69
- before(:each) do
70
- store.write('foo', 'bar')
71
- end
72
- let(:document) { collection.find_one(:_id => 'foo') }
73
-
74
- it "returns nil for key not found" do
75
- store.read('non:existent:key').should be_nil
76
- end
77
-
78
- it "returns unmarshalled value key value for key found" do
79
- store.read('foo').should == 'bar'
80
- end
81
-
82
- it "returns raw value if document raw key is true" do
83
- store.write('foo', 'bar', :raw => true)
84
- store.read('foo').should == 'bar'
85
- end
86
-
87
- it "returns nil for existing but expired key" do
88
- collection.save(:_id => 'foo', :value => 'bar', :expires_at => 5.seconds.ago)
89
- store.read('foo').should be_nil
90
- end
91
-
92
- it "return value for existing and not expired key" do
93
- store.write('foo', 'bar', :expires_in => 20.seconds)
94
- store.read('foo').should == 'bar'
95
- end
96
-
97
- it "works with symbol" do
98
- store.read(:foo).should == 'bar'
99
- end
100
- end
101
-
102
- describe "#delete" do
103
- before(:each) do
104
- store.write('foo', 'bar')
105
- end
106
-
107
- it "delete key from cache" do
108
- store.read('foo').should_not be_nil
109
- store.delete('foo')
110
- store.read('foo').should be_nil
111
- end
112
-
113
- it "works with symbol" do
114
- store.read(:foo).should_not be_nil
115
- store.delete(:foo)
116
- store.read(:foo).should be_nil
117
- end
118
- end
119
-
120
- describe "#delete_matched" do
121
- before(:each) do
122
- store.write('foo1', 'bar')
123
- store.write('foo2', 'bar')
124
- store.write('baz', 'wick')
125
- end
126
-
127
- it "deletes matching keys" do
128
- store.read('foo1').should_not be_nil
129
- store.read('foo2').should_not be_nil
130
- store.delete_matched(/foo/)
131
- store.read('foo1').should be_nil
132
- store.read('foo2').should be_nil
133
- end
134
-
135
- it "does not delete unmatching keys" do
136
- store.delete_matched('foo')
137
- store.read('baz').should_not be_nil
138
- end
139
- end
140
-
141
- describe "#exist?" do
142
- before(:each) do
143
- store.write('foo', 'bar')
144
- end
145
-
146
- it "returns true if key found" do
147
- store.exist?('foo').should be_true
148
- end
149
-
150
- it "returns false if key not found" do
151
- store.exist?('not:found:key').should be_false
152
- end
153
-
154
- it "works with symbol" do
155
- store.exist?(:foo).should be_true
156
- store.exist?(:notfoundkey).should be_false
157
- end
158
- end
159
-
160
- describe "#clear" do
161
- before(:each) do
162
- store.write('foo', 'bar')
163
- store.write('baz', 'wick')
164
- end
165
-
166
- it "clear all keys" do
167
- collection.count.should == 2
168
- store.clear
169
- collection.count.should == 0
170
- end
171
- end
172
-
173
- describe "#increment" do
174
- it "increment key by amount" do
175
- store.increment('views', 1)
176
- store.read('views').should == 1
177
- store.increment('views', 2)
178
- store.read('views').should == 3
179
- end
180
-
181
- it "works with symbol" do
182
- store.increment(:views, 2)
183
- store.read(:views).should == 2
184
- end
185
- end
186
-
187
- describe "#decrement" do
188
- it "decrement key by amount" do
189
- store.increment('views', 5)
190
- store.decrement('views', 2)
191
- store.read('views').should == 3
192
- store.decrement('views', 2)
193
- store.read('views').should == 1
194
- end
195
-
196
- it "works with symbol" do
197
- store.increment(:views, 2)
198
- store.decrement(:views, 1)
199
- store.read(:views).should == 1
200
- end
201
- end
202
-
203
- describe "#stats" do
204
- it "returns stats" do
205
- %w[ns count size].each do |key|
206
- store.stats.should have_key(key)
207
- end
208
- end
209
- end
210
- end