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.
Files changed (61) hide show
  1. data/AUTHORS +1 -0
  2. data/README.markdown +28 -15
  3. data/VERSION +1 -1
  4. data/init.rb +1 -0
  5. data/lib/remix/stash/auto_detection.rb +27 -0
  6. data/lib/remix/stash/cluster.rb +1 -0
  7. data/lib/remix/stash/protocol.rb +71 -6
  8. data/lib/remix/stash.rb +86 -25
  9. data/remix-stash.gemspec +74 -4
  10. data/spec/auto_detection_spec.rb +29 -0
  11. data/spec/spec.rb +18 -7
  12. data/spec/stash_spec.rb +134 -34
  13. data/spec/support/bar.rb +2 -0
  14. data/spec/support/rails/README +243 -0
  15. data/spec/support/rails/Rakefile +10 -0
  16. data/spec/support/rails/app/controllers/application_controller.rb +10 -0
  17. data/spec/support/rails/app/helpers/application_helper.rb +3 -0
  18. data/spec/support/rails/config/boot.rb +110 -0
  19. data/spec/support/rails/config/database.yml +22 -0
  20. data/spec/support/rails/config/environment.rb +41 -0
  21. data/spec/support/rails/config/environments/development.rb +17 -0
  22. data/spec/support/rails/config/environments/production.rb +28 -0
  23. data/spec/support/rails/config/environments/test.rb +28 -0
  24. data/spec/support/rails/config/initializers/backtrace_silencers.rb +7 -0
  25. data/spec/support/rails/config/initializers/inflections.rb +10 -0
  26. data/spec/support/rails/config/initializers/mime_types.rb +5 -0
  27. data/spec/support/rails/config/initializers/new_rails_defaults.rb +21 -0
  28. data/spec/support/rails/config/initializers/session_store.rb +15 -0
  29. data/spec/support/rails/config/locales/en.yml +5 -0
  30. data/spec/support/rails/config/routes.rb +43 -0
  31. data/spec/support/rails/db/seeds.rb +7 -0
  32. data/spec/support/rails/doc/README_FOR_APP +2 -0
  33. data/spec/support/rails/log/development.log +0 -0
  34. data/spec/support/rails/log/production.log +0 -0
  35. data/spec/support/rails/log/server.log +0 -0
  36. data/spec/support/rails/log/test.log +0 -0
  37. data/spec/support/rails/public/404.html +30 -0
  38. data/spec/support/rails/public/422.html +30 -0
  39. data/spec/support/rails/public/500.html +30 -0
  40. data/spec/support/rails/public/favicon.ico +0 -0
  41. data/spec/support/rails/public/images/rails.png +0 -0
  42. data/spec/support/rails/public/index.html +275 -0
  43. data/spec/support/rails/public/javascripts/application.js +2 -0
  44. data/spec/support/rails/public/javascripts/controls.js +963 -0
  45. data/spec/support/rails/public/javascripts/dragdrop.js +973 -0
  46. data/spec/support/rails/public/javascripts/effects.js +1128 -0
  47. data/spec/support/rails/public/javascripts/prototype.js +4320 -0
  48. data/spec/support/rails/public/robots.txt +5 -0
  49. data/spec/support/rails/script/about +4 -0
  50. data/spec/support/rails/script/console +3 -0
  51. data/spec/support/rails/script/dbconsole +3 -0
  52. data/spec/support/rails/script/destroy +3 -0
  53. data/spec/support/rails/script/generate +3 -0
  54. data/spec/support/rails/script/performance/benchmarker +3 -0
  55. data/spec/support/rails/script/performance/profiler +3 -0
  56. data/spec/support/rails/script/plugin +3 -0
  57. data/spec/support/rails/script/runner +3 -0
  58. data/spec/support/rails/script/server +3 -0
  59. data/spec/support/rails/test/performance/browsing_test.rb +9 -0
  60. data/spec/support/rails/test/test_helper.rb +38 -0
  61. 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
- Real docs coming soon! Check out the examples directory for more.
1
+ # Quick & Dirty Specs
2
2
 
3
- # Quick Specs
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
- # TODO
23
+ gem install binary42-remix-stash --source=http://gems.github.com/
14
24
 
15
- * namespacing
16
- * implement the rest of the memcached 1.4 binary API (replace, append, prepend)
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.9.6
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
@@ -2,6 +2,7 @@ require 'socket'
2
2
  require 'digest/md5'
3
3
 
4
4
  class Remix::Stash::Cluster
5
+ include Enumerable
5
6
  include Socket::Constants
6
7
 
7
8
  @@connections = {}
@@ -58,10 +58,23 @@ module Remix::Stash::Protocol
58
58
  resp[:status] == NO_ERROR
59
59
  end
60
60
 
61
- DECR_PACKET = HEADER_FORMAT + 'NNQNa*'
62
- def decr(io, key, step)
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
- header = [REQUEST, DECREMENT, key.size, 20, 0, 0, key.size + 20, 0, 0, high, low, 0, COUNTER_FAULT_EXPIRATION, key].pack(DECR_PACKET)
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 + 'NNQNa*'
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
- header = [REQUEST, INCREMENT, key.size, 20, 0, 0, key.size + 20, 0, 0, high, low, 0, COUNTER_FAULT_EXPIRATION, key].pack(INCR_PACKET)
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| Protocol.set(io, key, dump_value(value), opts[:ttl])}
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| Protocol.set(io, key, value, opts[:ttl])}
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
- if @scope
200
- "#{implicit_scope}#{keys.join(KEY_SEPARATOR)}#{vector(opts)}"
201
- elsif v
202
- keys.join(KEY_SEPARATOR) << v
203
- else
204
- keys.join(KEY_SEPARATOR)
205
- end
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.9.6"
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-09-22}
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/extension_spec.rb",
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",