battle_ship 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6c1a6e6b2bbce4d90f39d7a4d50b9064eb2c25a8
4
+ data.tar.gz: 201bfa26abb91dbfcd900ba21483ef289ab86a70
5
+ SHA512:
6
+ metadata.gz: eb495f4cfce3a23eed57d2a06836a3c100a6548b00c066f1fcf7d578fa581dff4d882d90cef1dc02cec4d334f24bed05e5cd175b17403556f209e615f65b0290
7
+ data.tar.gz: bf4cd384fbb12a719bd81fcbf44865424e5e458528dca3a04c54e61ec3d3cd34e99b370426a1e64b3c8df98840b39b9b71eda28ab9e0277b7710c0a1d1bbe8ed
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in battle_ship.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 DavidRagone
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # BattleShip
2
+
3
+ ### Keep track of your cache hits & misses
4
+
5
+ #### Description
6
+ If you make use of Rails.cache methods (e.g. #fetch, #read, #write), you may be
7
+ curious what your success is with your caching strategies. Perhaps you cache
8
+ some user objects, sessions, etc. How do you know whether it's working? What if
9
+ it's mostly misses?
10
+
11
+ BattleShip provides an api that wraps Rails.cache methods. It takes a namespace
12
+ by which it will aggregate data on your cache hits and misses.
13
+
14
+ #### Warnings, Caveats, etc.
15
+ Battleship is a gem that expects there to be a class called __Rails__ with a .cache
16
+ method. This .cache method must implement the following:
17
+ - fetch
18
+ - read
19
+ - write
20
+ - increment
21
+
22
+ This cache must also be able to complete _atomic increment_ operations with the #increment method
23
+
24
+ This is early development days for BattleShip. Please feel free to open an issue
25
+ here with either questions or suggestions. And, of course, contributions are
26
+ welcome.
27
+
28
+ ## Installation
29
+
30
+ Add this line to your application's Gemfile:
31
+
32
+ gem 'battle_ship'
33
+
34
+ And then execute:
35
+
36
+ $ bundle
37
+
38
+ Or install it yourself as:
39
+
40
+ $ gem install battle_ship
41
+
42
+ ## Usage
43
+
44
+ Instead of calling Rails.cache, call BattleShip. Instead of passing a key, pass
45
+ in both a namespace (e.g., sessions or users) and a unique id (e.g. auth_token
46
+ or user.id).
47
+
48
+ After adding to your Gemfile, use BattleShip where you would previously have
49
+ used Rails.cache.
50
+ * Caching User objects? Call ```BattleShip.write("user", user.id, user)``` for a
51
+ given user object
52
+ * This will store the user object just as if you had called ```Rails.cache.write("user_#{user.id}", user)```
53
+ * The benefit comes when you call read: ```BattleShip.read("user", 1)```
54
+ * If you have a value cached, BattleShip will increment the key at "user_hit" by
55
+ 1 (hence the need for atomic increment operations)
56
+ * If there is no value found, BattleShip will increment the key at "user_miss"
57
+
58
+ At any time, you can access the current number of hits and misses by calling
59
+ BattleShip.hits(:namespace) and BattleShip.misses(:namespace), where :namespace
60
+ is any given namespace you have used (e.g. 'user', as above). This can be passed
61
+ as a symbol or string.
62
+
63
+ ## Contributing
64
+
65
+ 1. Fork it
66
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
67
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
68
+ 4. Push to the branch (`git push origin my-new-feature`)
69
+ 5. Create new Pull Request
70
+
71
+ ## To Do
72
+
73
+ 1. Add config method with any necessary config
74
+ 2. Create specs specifically using redis-store and memcache-store, document here
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new
5
+
6
+ task :default => :spec
7
+ task :test => :spec
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'battle_ship/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "battle_ship"
8
+ spec.version = BattleShip::VERSION
9
+ spec.authors = ["DavidRagone"]
10
+ spec.email = ["dmragone@gmail.com"]
11
+ spec.description = %q{Wrapper class for Rails.cache related methods to track cache hits & misses}
12
+ spec.summary = %q{Wrapper for Rails.cache methods}
13
+ spec.homepage = "http://www.dmragone.com"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ end
@@ -0,0 +1,62 @@
1
+ module BattleShip
2
+ class << self
3
+ def read(namespace, uid)
4
+ value = cache.read(namespaced(namespace, uid))
5
+ increment_hit_or_miss(namespace, value)
6
+ value
7
+ end
8
+
9
+ def write(namespace, uid, value, options = nil)
10
+ cache.write(namespaced(namespace, uid), value, options)
11
+ end
12
+
13
+ def fetch(namespace, uid, options = nil)
14
+ # http://mudge.name/2011/01/26/passing-blocks-in-ruby-without-block.html
15
+ namespaced = namespaced(namespace, uid)
16
+ increment_hit_or_miss(namespace, cache.read(namespaced))
17
+ if block_given?
18
+ cache.fetch(namespaced, options, &Proc.new)
19
+ else
20
+ cache.fetch(namespaced, options)
21
+ end
22
+ end
23
+
24
+ def decrement(namespace, uid, amount = 1, options = nil)
25
+ cache.decrement(namespaced(namespace, uid), amount, options)
26
+ end
27
+
28
+ def delete(namespace, uid, options = nil)
29
+ cache.delete(namespaced(namespace, uid), options)
30
+ end
31
+
32
+ def exist?(namespace, uid, options = nil)
33
+ cache.exist?(namespaced(namespace, uid), options)
34
+ end
35
+
36
+ def increment(namespace, uid, amount = 1, options = nil)
37
+ cache.increment(namespaced(namespace, uid), amount, options)
38
+ end
39
+
40
+ def hits(namespace)
41
+ cache.read("#{namespace}_hit")
42
+ end
43
+
44
+ def misses(namespace)
45
+ cache.read("#{namespace}_miss")
46
+ end
47
+
48
+ private
49
+ def increment_hit_or_miss(namespace, value, amount = 1, options = nil)
50
+ hit_or_miss = value.nil? ? '_miss' : '_hit'
51
+ cache.increment(namespace.to_s << hit_or_miss, amount, options)
52
+ end
53
+
54
+ def namespaced(namespace, uid)
55
+ namespace.to_s << '_' << uid.to_s
56
+ end
57
+
58
+ def cache
59
+ Rails.cache
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,27 @@
1
+ module BattleShip
2
+ class << self
3
+ def cleanup(options = nil)
4
+ cache.cleanup(options)
5
+ end
6
+
7
+ def clear(options = nil)
8
+ cache.clear(options)
9
+ end
10
+
11
+ def delete_matched(matcher, options = nil)
12
+ cache.delete_matched(matcher, options)
13
+ end
14
+
15
+ def mute
16
+ cache.mute
17
+ end
18
+
19
+ def read_multi(*names)
20
+ cache.read_multi(*names)
21
+ end
22
+
23
+ def silence!
24
+ cache.silence!
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ module BattleShip
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,6 @@
1
+ module BattleShip
2
+ end
3
+
4
+ require "battle_ship/version"
5
+ require "battle_ship/core"
6
+ require "battle_ship/pass_through"
@@ -0,0 +1,280 @@
1
+ require 'spec_helper'
2
+
3
+ class Rails
4
+ def self.cache
5
+ Cache
6
+ end
7
+ end
8
+ class Cache
9
+ def self.read(k)
10
+ end
11
+ def self.increment(k,a=1,o=nil)
12
+ end
13
+ def self.fetch(k,o=nil)
14
+ if block_given?
15
+ yield
16
+ end
17
+ end
18
+ end
19
+
20
+ describe BattleShip do
21
+ describe ".read" do
22
+ shared_examples_for :read do
23
+ it "retrieves value from Rails.cache.read" do
24
+ Cache.should_receive(:read).with("namespace_#{uniqueid}")
25
+ BattleShip.read(:namespace, uniqueid)
26
+ end
27
+
28
+ it "returns value from Rails.cache.read" do
29
+ Cache.stub(:read) { 'a value' }
30
+ BattleShip.read(:foo, :bar).should eq 'a value'
31
+ end
32
+
33
+ it "increments namespace hit counter when value is non-nil" do
34
+ Cache.stub(:read) { 'a value' }
35
+ Cache.should_receive(:increment).with('foo_hit', 1, nil)
36
+ BattleShip.read(:foo, :bar)
37
+ end
38
+
39
+ it "increments namespace miss counter when value is nil" do
40
+ Cache.stub(:read) { nil }
41
+ Cache.should_receive(:increment).with('foo_miss', 1, nil)
42
+ BattleShip.read(:foo, :bar)
43
+ end
44
+ end
45
+
46
+ context 'when uniqueid is a symbol' do
47
+ let(:uniqueid) { :foo }
48
+ it_behaves_like :read
49
+ end
50
+
51
+ context 'when uniqueid is a string' do
52
+ let(:uniqueid) { 'foo' }
53
+ it_behaves_like :read
54
+ end
55
+
56
+ context 'when uniqueid is a number' do
57
+ let(:uniqueid) { 4 }
58
+ it_behaves_like :read
59
+ end
60
+ end
61
+
62
+ describe ".write" do
63
+ shared_examples_for :write do
64
+ it "writes value to Rails.cache.write using given key" do
65
+ Cache.should_receive(:write).with("namespace_#{uniqueid}", value, nil)
66
+ BattleShip.write(:namespace, uniqueid, value)
67
+ end
68
+ end
69
+
70
+ context 'when uniqueid is a symbol' do
71
+ let(:uniqueid) { :foo }
72
+ let(:value) { :bar }
73
+ it_behaves_like :write
74
+ end
75
+
76
+ context 'when uniqueid is a string' do
77
+ let(:uniqueid) { 'foo' }
78
+ let(:value) { 'bar' }
79
+ it_behaves_like :write
80
+ end
81
+
82
+ context 'when uniqueid is a number' do
83
+ let(:uniqueid) { 4 }
84
+ let(:value) { 5 }
85
+ it_behaves_like :write
86
+ end
87
+ end
88
+
89
+ describe ".fetch" do
90
+ shared_examples_for :fetch do
91
+ it "retrieves value from Rails.cache.fetch" do
92
+ Cache.should_receive(:fetch)
93
+ subject
94
+ end
95
+
96
+ it "returns value from Rails.cache.fetch" do
97
+ Cache.stub(:fetch) { 'a value' }
98
+ subject.should eq 'a value'
99
+ end
100
+
101
+ it "increments namespace hit counter when value is non-nil" do
102
+ Cache.stub(:fetch) { 'a value' }
103
+ Cache.stub(:read) { 'a value' }
104
+ Cache.should_receive(:increment).with('foo_hit', 1, nil)
105
+ subject
106
+ end
107
+
108
+ it "increments namespace miss counter when value is nil" do
109
+ Cache.stub(:fetch) { nil }
110
+ Cache.should_receive(:increment).with('foo_miss', 1, nil)
111
+ subject
112
+ end
113
+ end
114
+ context "when block given" do
115
+ subject { described_class.fetch(:foo, :bar) { 'a different value' } }
116
+ it_behaves_like :fetch
117
+
118
+ context "when value absent" do
119
+ it "should set the value" do
120
+ subject
121
+ subject.should eq 'a different value'
122
+ end
123
+ end
124
+ end
125
+
126
+ context "when block absent" do
127
+ subject { described_class.fetch(:foo, :bar) }
128
+ it_behaves_like :fetch
129
+ end
130
+ end
131
+
132
+ describe ".cleanup" do
133
+ let(:options) { { } }
134
+ it "passes to underlying" do
135
+ Cache.should_receive(:cleanup).with(options)
136
+ BattleShip.cleanup(options)
137
+ end
138
+
139
+ it "does not require options" do
140
+ Cache.should_receive(:cleanup).with(nil)
141
+ BattleShip.cleanup
142
+ end
143
+ end
144
+
145
+ describe ".clear" do
146
+ let(:options) { { } }
147
+ it "passes to underlying" do
148
+ Cache.should_receive(:clear).with(options)
149
+ BattleShip.clear(options)
150
+ end
151
+
152
+ it "does not require options" do
153
+ Cache.should_receive(:clear).with(nil)
154
+ BattleShip.clear
155
+ end
156
+ end
157
+
158
+ describe ".decrement" do
159
+ let(:options) { { } }
160
+ let(:namespace) { 'name' }
161
+ let(:uid) { '1' }
162
+ let(:amount) { 2 }
163
+ it "passes to underlying" do
164
+ Cache.should_receive(:decrement).with('name_1', amount, options)
165
+ BattleShip.decrement(namespace, uid, amount, options)
166
+ end
167
+
168
+ it "defaults amount to 1" do
169
+ Cache.should_receive(:decrement).with('name_1', 3, options)
170
+ BattleShip.decrement(namespace, uid, 3, options)
171
+ end
172
+
173
+ it "does not require options" do
174
+ Cache.should_receive(:decrement).with('name_1', 1, nil)
175
+ BattleShip.decrement(namespace, uid)
176
+ end
177
+ end
178
+
179
+ describe ".delete" do
180
+ let(:namespace) { 'name' }
181
+ let(:uid) { 1 }
182
+ let(:options) { { } }
183
+ it "passes to underlying" do
184
+ Cache.should_receive(:delete).with('name_1', options)
185
+ BattleShip.delete(namespace, uid, options)
186
+ end
187
+
188
+ it "does not require options" do
189
+ Cache.should_receive(:delete).with('name_1', nil)
190
+ BattleShip.delete(namespace, uid)
191
+ end
192
+ end
193
+
194
+ describe ".delete_matched" do
195
+ let(:matcher) { 'something*' }
196
+ let(:options) { { } }
197
+ it "passes to underlying" do
198
+ Cache.should_receive(:delete_matched).with(matcher, options)
199
+ BattleShip.delete_matched(matcher, options)
200
+ end
201
+
202
+ it "does not require options" do
203
+ Cache.should_receive(:delete_matched).with(matcher, nil)
204
+ BattleShip.delete_matched(matcher)
205
+ end
206
+ end
207
+
208
+ describe ".exist?" do
209
+ let(:namespace) { 'name' }
210
+ let(:uid) { 1 }
211
+ let(:options) { { } }
212
+ it "passes to underlying" do
213
+ Cache.should_receive(:exist?).with('name_1', options)
214
+ BattleShip.exist?(namespace, uid, options)
215
+ end
216
+
217
+ it "does not require options" do
218
+ Cache.should_receive(:exist?).with('name_1', nil)
219
+ BattleShip.exist?(namespace, uid)
220
+ end
221
+ end
222
+
223
+ describe ".increment" do
224
+ let(:options) { { } }
225
+ let(:namespace) { 'name' }
226
+ let(:uid) { '1' }
227
+ let(:amount) { 2 }
228
+ it "passes to underlying" do
229
+ Cache.should_receive(:increment).with('name_1', amount, options)
230
+ BattleShip.increment(namespace, uid, amount, options)
231
+ end
232
+
233
+ it "defaults amount to 1" do
234
+ Cache.should_receive(:increment).with('name_1', 3, options)
235
+ BattleShip.increment(namespace, uid, 3, options)
236
+ end
237
+
238
+ it "does not require options" do
239
+ Cache.should_receive(:increment).with('name_1', 1, nil)
240
+ BattleShip.increment(namespace, uid)
241
+ end
242
+ end
243
+
244
+ describe ".hits" do
245
+ it "returns the hits" do
246
+ Cache.should_receive(:read).with("foo_hit") { 4 }
247
+ BattleShip.hits(:foo).should eq 4
248
+ end
249
+ end
250
+
251
+ describe ".misses" do
252
+ it "returns the hits" do
253
+ Cache.should_receive(:read).with("foo_miss") { 4 }
254
+ BattleShip.misses(:foo).should eq 4
255
+ end
256
+ end
257
+
258
+ describe ".mute" do
259
+ it "passes to underlying" do
260
+ Cache.should_receive(:mute)
261
+ BattleShip.mute
262
+ end
263
+ end
264
+
265
+ describe ".read_multi" do
266
+ # *names - options is last
267
+ let(:names) { ['1', '2', '3'] }
268
+ it "passes to underlying" do
269
+ Cache.should_receive(:read_multi).with(names)
270
+ BattleShip.read_multi(names)
271
+ end
272
+ end
273
+
274
+ describe ".silence!" do
275
+ it "passes to underlying" do
276
+ Cache.should_receive(:silence!)
277
+ BattleShip.silence!
278
+ end
279
+ end
280
+ end
@@ -0,0 +1,12 @@
1
+ require 'battle_ship'
2
+
3
+ RSpec.configure do |config|
4
+ # Use color in STDOUT
5
+ config.color_enabled = true
6
+ #
7
+ # # Use color not only in STDOUT but also in pagers and files
8
+ config.tty = true
9
+ #
10
+ # # Use the specified formatter
11
+ config.formatter = :documentation # :progress, :html, :textmate
12
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: battle_ship
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - DavidRagone
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Wrapper class for Rails.cache related methods to track cache hits & misses
56
+ email:
57
+ - dmragone@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - battle_ship.gemspec
68
+ - lib/battle_ship.rb
69
+ - lib/battle_ship/core.rb
70
+ - lib/battle_ship/pass_through.rb
71
+ - lib/battle_ship/version.rb
72
+ - spec/lib/battle_ship_spec.rb
73
+ - spec/spec_helper.rb
74
+ homepage: http://www.dmragone.com
75
+ licenses:
76
+ - MIT
77
+ metadata: {}
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubyforge_project:
94
+ rubygems_version: 2.0.3
95
+ signing_key:
96
+ specification_version: 4
97
+ summary: Wrapper for Rails.cache methods
98
+ test_files:
99
+ - spec/lib/battle_ship_spec.rb
100
+ - spec/spec_helper.rb