remix-stash 0.9.6 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +1 -0
- data/README.markdown +28 -15
- data/VERSION +1 -1
- data/init.rb +1 -0
- data/lib/remix/stash/auto_detection.rb +27 -0
- data/lib/remix/stash/cluster.rb +1 -0
- data/lib/remix/stash/protocol.rb +71 -6
- data/lib/remix/stash.rb +86 -25
- data/remix-stash.gemspec +74 -4
- data/spec/auto_detection_spec.rb +29 -0
- data/spec/spec.rb +18 -7
- data/spec/stash_spec.rb +134 -34
- data/spec/support/bar.rb +2 -0
- data/spec/support/rails/README +243 -0
- data/spec/support/rails/Rakefile +10 -0
- data/spec/support/rails/app/controllers/application_controller.rb +10 -0
- data/spec/support/rails/app/helpers/application_helper.rb +3 -0
- data/spec/support/rails/config/boot.rb +110 -0
- data/spec/support/rails/config/database.yml +22 -0
- data/spec/support/rails/config/environment.rb +41 -0
- data/spec/support/rails/config/environments/development.rb +17 -0
- data/spec/support/rails/config/environments/production.rb +28 -0
- data/spec/support/rails/config/environments/test.rb +28 -0
- data/spec/support/rails/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/support/rails/config/initializers/inflections.rb +10 -0
- data/spec/support/rails/config/initializers/mime_types.rb +5 -0
- data/spec/support/rails/config/initializers/new_rails_defaults.rb +21 -0
- data/spec/support/rails/config/initializers/session_store.rb +15 -0
- data/spec/support/rails/config/locales/en.yml +5 -0
- data/spec/support/rails/config/routes.rb +43 -0
- data/spec/support/rails/db/seeds.rb +7 -0
- data/spec/support/rails/doc/README_FOR_APP +2 -0
- data/spec/support/rails/log/development.log +0 -0
- data/spec/support/rails/log/production.log +0 -0
- data/spec/support/rails/log/server.log +0 -0
- data/spec/support/rails/log/test.log +0 -0
- data/spec/support/rails/public/404.html +30 -0
- data/spec/support/rails/public/422.html +30 -0
- data/spec/support/rails/public/500.html +30 -0
- data/spec/support/rails/public/favicon.ico +0 -0
- data/spec/support/rails/public/images/rails.png +0 -0
- data/spec/support/rails/public/index.html +275 -0
- data/spec/support/rails/public/javascripts/application.js +2 -0
- data/spec/support/rails/public/javascripts/controls.js +963 -0
- data/spec/support/rails/public/javascripts/dragdrop.js +973 -0
- data/spec/support/rails/public/javascripts/effects.js +1128 -0
- data/spec/support/rails/public/javascripts/prototype.js +4320 -0
- data/spec/support/rails/public/robots.txt +5 -0
- data/spec/support/rails/script/about +4 -0
- data/spec/support/rails/script/console +3 -0
- data/spec/support/rails/script/dbconsole +3 -0
- data/spec/support/rails/script/destroy +3 -0
- data/spec/support/rails/script/generate +3 -0
- data/spec/support/rails/script/performance/benchmarker +3 -0
- data/spec/support/rails/script/performance/profiler +3 -0
- data/spec/support/rails/script/plugin +3 -0
- data/spec/support/rails/script/runner +3 -0
- data/spec/support/rails/script/server +3 -0
- data/spec/support/rails/test/performance/browsing_test.rb +9 -0
- data/spec/support/rails/test/test_helper.rb +38 -0
- metadata +72 -2
data/AUTHORS
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Brian Mitchell (@binary42) <brian@streampunks.com>
|
data/README.markdown
CHANGED
@@ -1,32 +1,45 @@
|
|
1
|
-
|
1
|
+
# Quick & Dirty Specs
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
New API! I've rethought a lot of the API and this comes with a lot of new capabilities. More work is being done on making it as expressive as possible without terrible overhead. This includes vectorized keys which allow emulation of partial cache clearing as well as nice shortcuts like eval and gate for expressions. Options, clusters, and implicit scope are easy to manage on a stash-by-stash basis. Keys are also easy to pass in as it will create composite keys from whatever you pass in (as long as it has to_s) so no more ugly string interpolation all over the place.
|
3
|
+
New API that doesn't actually suck! I've rethought a lot of the API and this comes with a lot of new capabilities. More work is being done on making it as expressive as possible without terrible overhead. This includes vectorized keys which allow emulation of partial cache clearing as well as nice shortcuts like eval and gate for expressions. Options, clusters, and implicit scope are easy to manage on a stash-by-stash basis. Keys are also easy to pass in as it will create composite keys from whatever you pass in (as long as it has to_s) so no more ugly string interpolation all over the place.
|
6
4
|
|
7
5
|
It's fast (faster than memcache-client). It's simple (pure ruby and only a few hundred lines). It's tested (shoulda). Of course, because it's pure ruby it will run almost anywhere as well unlike many other clients.
|
8
6
|
|
9
7
|
It does require memcached 1.4+ but you should be running that anyway (if you aren't, upgrade already).
|
10
8
|
|
11
|
-
Take a look and let me know what you think!
|
9
|
+
Take a look at the examples and let me know what you think!
|
10
|
+
|
11
|
+
# Installation
|
12
|
+
|
13
|
+
Right now remix-stash is designed to be run as a gem. I've published it to both github and gemcutter (preferred). You can also safely use this as a rails plugin, just check out the source in your plugin directory and it will be automatically loaded.
|
14
|
+
|
15
|
+
## Install via GemCutter
|
16
|
+
|
17
|
+
gem install remix-stash --source=http://gemcutter.org/
|
18
|
+
|
19
|
+
## Install via GitHub
|
20
|
+
|
21
|
+
Warning: THIS IS CURRENTLY LIMITED TO VERSION 0.9.6 (until github reenables gem building).
|
12
22
|
|
13
|
-
|
23
|
+
gem install binary42-remix-stash --source=http://gems.github.com/
|
14
24
|
|
15
|
-
|
16
|
-
|
25
|
+
# Using Remix::Stash
|
26
|
+
|
27
|
+
The examples directory has some simple code snippets that introduce general features of the library. In general, everything should just work after `require 'remix/stash'`. This includes integration with Rails and automatic pick-up of Heroku style memcached environment variables. Of course, this library is completely independent of Rails and does not need environment variables to function or be used.
|
28
|
+
|
29
|
+
# Specifications
|
30
|
+
|
31
|
+
This project is tested with shoulda (install via the thoughtbot-shoulda gem on github) and takes the philosophy that fewer moving parts is better. So to avoid complex runners just run `spec/spec.rb` or the spec you are interested in directly. In order for the specs to function, you should have memcached 1.4+ running locally on port 11211.
|
32
|
+
|
33
|
+
# Future Work
|
34
|
+
|
35
|
+
* add block form to access response headers directly
|
36
|
+
* get/set add/replace read/write should allow a CAS flag to be passed
|
17
37
|
* allow swappable cluster types for consistent hashing, ketama, etc...
|
18
|
-
* failsafe marshal load
|
19
38
|
* support non-marshal value dumps configured per stash
|
20
39
|
* support multi vector sets
|
21
40
|
* thread safe cluster
|
22
|
-
* add block form
|
23
41
|
* quiet/multi command forms (will require a protocol refactoring most likely)
|
24
|
-
* server pings
|
25
|
-
* complete stats API
|
26
|
-
* incr/decr should take default value flags
|
27
|
-
* get/set add/replace read/write should allow a CAS flag to be passed
|
28
42
|
* accelerated binary API implementation with Ruby fallback
|
29
43
|
* redis support for vectors and/or value
|
30
|
-
* large key handling support
|
31
44
|
* UDP support (more experimentation on the tradeoffs)
|
32
45
|
* EventMachine integration (non-blocking?)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
1.0.0
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'remix/stash'
|
@@ -0,0 +1,27 @@
|
|
1
|
+
if defined?(Rails)
|
2
|
+
stash.default(:logger => Rails.logger)
|
3
|
+
|
4
|
+
module Remix::Stash::RailsSupport
|
5
|
+
private
|
6
|
+
|
7
|
+
def cycle_action_vectors
|
8
|
+
Remix::Stash.cycle_action
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
class ActionController::Base
|
14
|
+
include Remix::Stash::RailsSupport
|
15
|
+
after_filter :cycle_action_vectors
|
16
|
+
end
|
17
|
+
|
18
|
+
if servers = ENV['MEMCACHED_SERVERS']
|
19
|
+
Remix::Stash.define_cluster(:environment => servers.split(','))
|
20
|
+
stash.default(:cluster => :environment)
|
21
|
+
end
|
22
|
+
|
23
|
+
if namespace = ENV['MEMCACHED_NAMESPACE']
|
24
|
+
stash.default(:namespace => namespace)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/lib/remix/stash/cluster.rb
CHANGED
data/lib/remix/stash/protocol.rb
CHANGED
@@ -58,10 +58,23 @@ module Remix::Stash::Protocol
|
|
58
58
|
resp[:status] == NO_ERROR
|
59
59
|
end
|
60
60
|
|
61
|
-
|
62
|
-
def
|
61
|
+
APPEND_PACKET = HEADER_FORMAT + 'a*a*'
|
62
|
+
def append(io, key, data)
|
63
|
+
header = [REQUEST, APPEND, key.size, 0, 0, 0, data.size + key.size, 0, 0, key, data].pack(APPEND_PACKET)
|
64
|
+
io.write(header)
|
65
|
+
resp = read_resp(io)
|
66
|
+
resp[:status] == NO_ERROR
|
67
|
+
end
|
68
|
+
|
69
|
+
DECR_PACKET = HEADER_FORMAT + 'NNNNNa*'
|
70
|
+
def decr(io, key, step, default = nil, ttl = nil)
|
63
71
|
low, high = split64(step)
|
64
|
-
|
72
|
+
if default
|
73
|
+
default_low, default_high = split64(default)
|
74
|
+
header = [REQUEST, DECREMENT, key.size, 20, 0, 0, key.size + 20, 0, 0, high, low, default_high, default_low, ttl, key].pack(DECR_PACKET)
|
75
|
+
else
|
76
|
+
header = [REQUEST, DECREMENT, key.size, 20, 0, 0, key.size + 20, 0, 0, high, low, 0, 0, COUNTER_FAULT_EXPIRATION, key].pack(DECR_PACKET)
|
77
|
+
end
|
65
78
|
io.write(header)
|
66
79
|
resp = read_resp(io)
|
67
80
|
if resp[:status] == NO_ERROR
|
@@ -94,10 +107,15 @@ module Remix::Stash::Protocol
|
|
94
107
|
resp[:status] == NO_ERROR ? resp[:body][GET_BODY] : nil
|
95
108
|
end
|
96
109
|
|
97
|
-
INCR_PACKET = HEADER_FORMAT + '
|
98
|
-
def incr(io, key, step)
|
110
|
+
INCR_PACKET = HEADER_FORMAT + 'NNNNNa*'
|
111
|
+
def incr(io, key, step, default = nil, ttl = nil)
|
99
112
|
low, high = split64(step)
|
100
|
-
|
113
|
+
if default
|
114
|
+
default_low, default_high = split64(default)
|
115
|
+
header = [REQUEST, INCREMENT, key.size, 20, 0, 0, key.size + 20, 0, 0, high, low, default_high, default_low, ttl, key].pack(DECR_PACKET)
|
116
|
+
else
|
117
|
+
header = [REQUEST, INCREMENT, key.size, 20, 0, 0, key.size + 20, 0, 0, high, low, 0, 0, COUNTER_FAULT_EXPIRATION, key].pack(INCR_PACKET)
|
118
|
+
end
|
101
119
|
io.write(header)
|
102
120
|
resp = read_resp(io)
|
103
121
|
if resp[:status] == NO_ERROR
|
@@ -105,6 +123,30 @@ module Remix::Stash::Protocol
|
|
105
123
|
end
|
106
124
|
end
|
107
125
|
|
126
|
+
PING_PACKET = HEADER_FORMAT
|
127
|
+
def ping(io)
|
128
|
+
header = [REQUEST, NO_OP, 0, 0, 0, 0, 0, 0, 0].pack(PING_PACKET)
|
129
|
+
io.write(header)
|
130
|
+
resp = read_resp(io)
|
131
|
+
resp[:status] == NO_ERROR
|
132
|
+
end
|
133
|
+
|
134
|
+
PREPEND_PACKET = HEADER_FORMAT + 'a*a*'
|
135
|
+
def prepend(io, key, data)
|
136
|
+
header = [REQUEST, PREPEND, key.size, 0, 0, 0, data.size + key.size, 0, 0, key, data].pack(PREPEND_PACKET)
|
137
|
+
io.write(header)
|
138
|
+
resp = read_resp(io)
|
139
|
+
resp[:status] == NO_ERROR
|
140
|
+
end
|
141
|
+
|
142
|
+
REPLACE_PACKET = HEADER_FORMAT + 'NNa*a*'
|
143
|
+
def replace(io, key, data, ttl = 0)
|
144
|
+
header = [REQUEST, REPLACE, key.size, 8, 0, 0, data.size + key.size + 8, 0, 0, 0, ttl, key, data].pack(REPLACE_PACKET)
|
145
|
+
io.write(header)
|
146
|
+
resp = read_resp(io)
|
147
|
+
resp[:status] == NO_ERROR
|
148
|
+
end
|
149
|
+
|
108
150
|
SET_PACKET = HEADER_FORMAT + 'NNa*a*'
|
109
151
|
def set(io, key, data, ttl = 0)
|
110
152
|
header = [REQUEST, SET, key.size, 8, 0, 0, data.size + key.size + 8, 0, 0, 0, ttl, key, data].pack(SET_PACKET)
|
@@ -113,6 +155,17 @@ module Remix::Stash::Protocol
|
|
113
155
|
resp[:status] == NO_ERROR
|
114
156
|
end
|
115
157
|
|
158
|
+
STAT_PACKET = HEADER_FORMAT + 'a*'
|
159
|
+
def stat(io, info = '')
|
160
|
+
header = [REQUEST, STAT, info.size, 0, 0, 0, info.size, 0, 0, info].pack(STAT_PACKET)
|
161
|
+
io.write(header)
|
162
|
+
loop do
|
163
|
+
stat = read_stat(io, info)
|
164
|
+
break unless stat[:key]
|
165
|
+
yield *stat.values_at(:key, :value)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
116
169
|
private
|
117
170
|
|
118
171
|
COUNTER_SPLIT = 'NN'
|
@@ -132,6 +185,18 @@ private
|
|
132
185
|
{:status => status, :body => io.read(body_length)}
|
133
186
|
end
|
134
187
|
|
188
|
+
STAT_HEADER = '@2n@6nN'
|
189
|
+
def read_stat(io, info)
|
190
|
+
header = io.read(24)
|
191
|
+
header or raise Remix::Stash::ProtocolError,
|
192
|
+
"No data in response header"
|
193
|
+
key_length, status, body_length = *header.unpack(STAT_HEADER)
|
194
|
+
stat = {:status => status}
|
195
|
+
stat[:key] = io.read(key_length) if key_length > 0
|
196
|
+
stat[:value] = io.read(body_length - key_length) if body_length - key_length > 0
|
197
|
+
stat
|
198
|
+
end
|
199
|
+
|
135
200
|
def split64(n)
|
136
201
|
[0xFFFFFFFF & n, n >> 32]
|
137
202
|
end
|
data/lib/remix/stash.rb
CHANGED
@@ -40,13 +40,6 @@ class Remix::Stash
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
def add(*keys)
|
44
|
-
opts = default_opts(keys)
|
45
|
-
value = keys.pop
|
46
|
-
key = canonical_key(keys, opts)
|
47
|
-
cluster(opts).select(key) {|io| Protocol.add(io, key, value, opts[:ttl])}
|
48
|
-
end
|
49
|
-
|
50
43
|
def clear(*keys)
|
51
44
|
opts = default_opts(keys)
|
52
45
|
if keys.empty?
|
@@ -81,7 +74,7 @@ class Remix::Stash
|
|
81
74
|
opts = default_opts(keys)
|
82
75
|
step = keys.pop
|
83
76
|
key = canonical_key(keys, opts)
|
84
|
-
cluster(opts).select(key) {|io| Protocol.decr(io, key, step)}
|
77
|
+
cluster(opts).select(key) {|io| Protocol.decr(io, key, step, opts[:default], opts[:ttl])}
|
85
78
|
end
|
86
79
|
|
87
80
|
def default(opts = nil)
|
@@ -101,12 +94,6 @@ class Remix::Stash
|
|
101
94
|
@opts
|
102
95
|
end
|
103
96
|
|
104
|
-
def delete(*keys)
|
105
|
-
opts = default_opts(keys)
|
106
|
-
key = canonical_key(keys, opts)
|
107
|
-
cluster(opts).select(key) {|io| Protocol.delete(io, key)}
|
108
|
-
end
|
109
|
-
|
110
97
|
def eval(*keys)
|
111
98
|
opts = default_opts(keys)
|
112
99
|
key = canonical_key(keys, opts)
|
@@ -146,7 +133,11 @@ class Remix::Stash
|
|
146
133
|
opts = default_opts(keys)
|
147
134
|
step = keys.pop
|
148
135
|
key = canonical_key(keys, opts)
|
149
|
-
cluster(opts).select(key) {|io| Protocol.incr(io, key, step)}
|
136
|
+
cluster(opts).select(key) {|io| Protocol.incr(io, key, step, opts[:default], opts[:ttl])}
|
137
|
+
end
|
138
|
+
|
139
|
+
def ping(name = default[:cluster])
|
140
|
+
cluster(:cluster => name).map {|io| Protocol.ping(io)}
|
150
141
|
end
|
151
142
|
|
152
143
|
def read(*keys)
|
@@ -168,10 +159,51 @@ class Remix::Stash
|
|
168
159
|
opts = default_opts(keys)
|
169
160
|
value = keys.pop
|
170
161
|
key = canonical_key(keys, opts)
|
171
|
-
cluster(opts).select(key) {|io|
|
162
|
+
cluster(opts).select(key) {|io|
|
163
|
+
case opts[:op]
|
164
|
+
when :add
|
165
|
+
Protocol.add(io, key, dump_value(value), opts[:ttl])
|
166
|
+
when :replace
|
167
|
+
Protocol.replace(io, key, dump_value(value), opts[:ttl])
|
168
|
+
else
|
169
|
+
Protocol.set(io, key, dump_value(value), opts[:ttl])
|
170
|
+
end
|
171
|
+
}
|
172
172
|
end
|
173
173
|
alias []= set
|
174
174
|
|
175
|
+
def stats(name = default[:cluster])
|
176
|
+
cluster(:cluster => name).map do |io|
|
177
|
+
stats = {:settings => {}, :slabs => [], :foo => {}}
|
178
|
+
Protocol.stat(io) {|key, value|
|
179
|
+
stats[key.to_sym] = normalize_stat(value)
|
180
|
+
}
|
181
|
+
Protocol.stat(io, 'settings') {|key, value|
|
182
|
+
stats[:settings][key.to_sym] = normalize_stat(value)
|
183
|
+
}
|
184
|
+
prefix = stats[:settings][:stat_key_prefix]
|
185
|
+
Protocol.stat(io, 'items') {|key, value|
|
186
|
+
part, slab_index, subkey = *key.split(prefix)
|
187
|
+
slab_index = slab_index.to_i
|
188
|
+
stats[:slabs][slab_index] ||= {:index => slab_index}
|
189
|
+
stats[:slabs][slab_index][subkey.to_sym] = normalize_stat(value)
|
190
|
+
}
|
191
|
+
Protocol.stat(io, 'slabs') {|key, value|
|
192
|
+
parts = key.split(prefix)
|
193
|
+
if parts.size == 1
|
194
|
+
stats["slabs_#{key}".to_sym] = normalize_stat(value)
|
195
|
+
else
|
196
|
+
slab_index, subkey = parts.values_at(-2, -1)
|
197
|
+
slab_index = slab_index.to_i
|
198
|
+
stats[:slabs][slab_index] ||= {:index => slab_index}
|
199
|
+
stats[:slabs][slab_index][subkey.to_sym] = normalize_stat(value)
|
200
|
+
end
|
201
|
+
}
|
202
|
+
stats[:slabs].compact!
|
203
|
+
stats
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
175
207
|
def transaction
|
176
208
|
yield self
|
177
209
|
ensure
|
@@ -182,7 +214,20 @@ class Remix::Stash
|
|
182
214
|
opts = default_opts(keys)
|
183
215
|
value = keys.pop
|
184
216
|
key = canonical_key(keys, opts)
|
185
|
-
cluster(opts).select(key) {|io|
|
217
|
+
cluster(opts).select(key) {|io|
|
218
|
+
case opts[:op]
|
219
|
+
when :add
|
220
|
+
Protocol.add(io, key, value, opts[:ttl])
|
221
|
+
when :replace
|
222
|
+
Protocol.replace(io, key, value, opts[:ttl])
|
223
|
+
when :append
|
224
|
+
Protocol.append(io, key, value)
|
225
|
+
when :prepend
|
226
|
+
Protocol.prepend(io, key, value)
|
227
|
+
else
|
228
|
+
Protocol.set(io, key, value, opts[:ttl])
|
229
|
+
end
|
230
|
+
}
|
186
231
|
end
|
187
232
|
|
188
233
|
protected
|
@@ -196,13 +241,16 @@ private
|
|
196
241
|
KEY_SEPARATOR = '/'
|
197
242
|
def canonical_key(keys, opts)
|
198
243
|
v = vector(opts)
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
244
|
+
namespace = opts[:namespace].to_s
|
245
|
+
key = namespace +
|
246
|
+
if @scope
|
247
|
+
"#{implicit_scope}#{keys.join(KEY_SEPARATOR)}#{vector(opts)}"
|
248
|
+
elsif v
|
249
|
+
keys.join(KEY_SEPARATOR) << v
|
250
|
+
else
|
251
|
+
keys.join(KEY_SEPARATOR)
|
252
|
+
end
|
253
|
+
key.size > 250 ? Digest::MD5.hexdigest(key) : key
|
206
254
|
end
|
207
255
|
|
208
256
|
def cluster(opts = {})
|
@@ -223,12 +271,23 @@ private
|
|
223
271
|
|
224
272
|
def load_value(data)
|
225
273
|
Marshal.load(data) if data
|
226
|
-
rescue TypeError, ArgumentError
|
274
|
+
rescue TypeError, ArgumentError => e
|
275
|
+
if e.message =~ /undefined class\/module (.*)/
|
276
|
+
retry if begin
|
277
|
+
$1.split('::').inject(Object) {|m,x|
|
278
|
+
m.const_get(x)}
|
279
|
+
rescue Exception
|
280
|
+
end
|
281
|
+
end
|
227
282
|
logger = default_opts[:logger]
|
228
283
|
logger && logger.error("[stash] Unable to load marshal stream: #{data.inspect}")
|
229
284
|
nil
|
230
285
|
end
|
231
286
|
|
287
|
+
def normalize_stat(value)
|
288
|
+
value == "NULL" ? nil : (Integer(value) rescue Float(value)) rescue value
|
289
|
+
end
|
290
|
+
|
232
291
|
def vector(opts)
|
233
292
|
return if @name == :root
|
234
293
|
return @vector if @vector && opts[:coherency] != :dynamic
|
@@ -254,3 +313,5 @@ end
|
|
254
313
|
|
255
314
|
class Object; include Remix::Stash::Extension end
|
256
315
|
module Remix; extend Remix::Stash::Extension end
|
316
|
+
|
317
|
+
require 'remix/stash/auto_detection'
|
data/remix-stash.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{remix-stash}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "1.0.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Brian Mitchell"]
|
12
|
-
s.date = %q{2009-
|
12
|
+
s.date = %q{2009-10-03}
|
13
13
|
s.email = %q{binary42@gmail.com}
|
14
14
|
s.extra_rdoc_files = [
|
15
15
|
"LICENSE",
|
@@ -17,6 +17,7 @@ Gem::Specification.new do |s|
|
|
17
17
|
]
|
18
18
|
s.files = [
|
19
19
|
".gitignore",
|
20
|
+
"AUTHORS",
|
20
21
|
"LICENSE",
|
21
22
|
"README.markdown",
|
22
23
|
"Rakefile",
|
@@ -29,14 +30,65 @@ Gem::Specification.new do |s|
|
|
29
30
|
"examples/scope.rb",
|
30
31
|
"examples/stash.rb",
|
31
32
|
"harness.rb",
|
33
|
+
"init.rb",
|
32
34
|
"lib/remix/stash.rb",
|
35
|
+
"lib/remix/stash/auto_detection.rb",
|
33
36
|
"lib/remix/stash/cluster.rb",
|
34
37
|
"lib/remix/stash/extension.rb",
|
35
38
|
"lib/remix/stash/protocol.rb",
|
36
39
|
"remix-stash.gemspec",
|
40
|
+
"spec/auto_detection_spec.rb",
|
37
41
|
"spec/extension_spec.rb",
|
38
42
|
"spec/spec.rb",
|
39
|
-
"spec/stash_spec.rb"
|
43
|
+
"spec/stash_spec.rb",
|
44
|
+
"spec/support/bar.rb",
|
45
|
+
"spec/support/rails/README",
|
46
|
+
"spec/support/rails/Rakefile",
|
47
|
+
"spec/support/rails/app/controllers/application_controller.rb",
|
48
|
+
"spec/support/rails/app/helpers/application_helper.rb",
|
49
|
+
"spec/support/rails/config/boot.rb",
|
50
|
+
"spec/support/rails/config/database.yml",
|
51
|
+
"spec/support/rails/config/environment.rb",
|
52
|
+
"spec/support/rails/config/environments/development.rb",
|
53
|
+
"spec/support/rails/config/environments/production.rb",
|
54
|
+
"spec/support/rails/config/environments/test.rb",
|
55
|
+
"spec/support/rails/config/initializers/backtrace_silencers.rb",
|
56
|
+
"spec/support/rails/config/initializers/inflections.rb",
|
57
|
+
"spec/support/rails/config/initializers/mime_types.rb",
|
58
|
+
"spec/support/rails/config/initializers/new_rails_defaults.rb",
|
59
|
+
"spec/support/rails/config/initializers/session_store.rb",
|
60
|
+
"spec/support/rails/config/locales/en.yml",
|
61
|
+
"spec/support/rails/config/routes.rb",
|
62
|
+
"spec/support/rails/db/seeds.rb",
|
63
|
+
"spec/support/rails/doc/README_FOR_APP",
|
64
|
+
"spec/support/rails/log/development.log",
|
65
|
+
"spec/support/rails/log/production.log",
|
66
|
+
"spec/support/rails/log/server.log",
|
67
|
+
"spec/support/rails/log/test.log",
|
68
|
+
"spec/support/rails/public/404.html",
|
69
|
+
"spec/support/rails/public/422.html",
|
70
|
+
"spec/support/rails/public/500.html",
|
71
|
+
"spec/support/rails/public/favicon.ico",
|
72
|
+
"spec/support/rails/public/images/rails.png",
|
73
|
+
"spec/support/rails/public/index.html",
|
74
|
+
"spec/support/rails/public/javascripts/application.js",
|
75
|
+
"spec/support/rails/public/javascripts/controls.js",
|
76
|
+
"spec/support/rails/public/javascripts/dragdrop.js",
|
77
|
+
"spec/support/rails/public/javascripts/effects.js",
|
78
|
+
"spec/support/rails/public/javascripts/prototype.js",
|
79
|
+
"spec/support/rails/public/robots.txt",
|
80
|
+
"spec/support/rails/script/about",
|
81
|
+
"spec/support/rails/script/console",
|
82
|
+
"spec/support/rails/script/dbconsole",
|
83
|
+
"spec/support/rails/script/destroy",
|
84
|
+
"spec/support/rails/script/generate",
|
85
|
+
"spec/support/rails/script/performance/benchmarker",
|
86
|
+
"spec/support/rails/script/performance/profiler",
|
87
|
+
"spec/support/rails/script/plugin",
|
88
|
+
"spec/support/rails/script/runner",
|
89
|
+
"spec/support/rails/script/server",
|
90
|
+
"spec/support/rails/test/performance/browsing_test.rb",
|
91
|
+
"spec/support/rails/test/test_helper.rb"
|
40
92
|
]
|
41
93
|
s.has_rdoc = true
|
42
94
|
s.homepage = %q{http://github.com/binary42/remix-stash}
|
@@ -45,9 +97,27 @@ Gem::Specification.new do |s|
|
|
45
97
|
s.rubygems_version = %q{1.3.1}
|
46
98
|
s.summary = %q{Remix your memcache}
|
47
99
|
s.test_files = [
|
48
|
-
"spec/
|
100
|
+
"spec/auto_detection_spec.rb",
|
101
|
+
"spec/extension_spec.rb",
|
49
102
|
"spec/spec.rb",
|
50
103
|
"spec/stash_spec.rb",
|
104
|
+
"spec/support/bar.rb",
|
105
|
+
"spec/support/rails/app/controllers/application_controller.rb",
|
106
|
+
"spec/support/rails/app/helpers/application_helper.rb",
|
107
|
+
"spec/support/rails/config/boot.rb",
|
108
|
+
"spec/support/rails/config/environment.rb",
|
109
|
+
"spec/support/rails/config/environments/development.rb",
|
110
|
+
"spec/support/rails/config/environments/production.rb",
|
111
|
+
"spec/support/rails/config/environments/test.rb",
|
112
|
+
"spec/support/rails/config/initializers/backtrace_silencers.rb",
|
113
|
+
"spec/support/rails/config/initializers/inflections.rb",
|
114
|
+
"spec/support/rails/config/initializers/mime_types.rb",
|
115
|
+
"spec/support/rails/config/initializers/new_rails_defaults.rb",
|
116
|
+
"spec/support/rails/config/initializers/session_store.rb",
|
117
|
+
"spec/support/rails/config/routes.rb",
|
118
|
+
"spec/support/rails/db/seeds.rb",
|
119
|
+
"spec/support/rails/test/performance/browsing_test.rb",
|
120
|
+
"spec/support/rails/test/test_helper.rb",
|
51
121
|
"examples/eval.rb",
|
52
122
|
"examples/gate.rb",
|
53
123
|
"examples/getset.rb",
|