battle_ship 0.0.1

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.
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