moneta 0.7.3 → 0.7.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (178) hide show
  1. data/.travis.yml +17 -51
  2. data/CHANGES +13 -0
  3. data/Gemfile +4 -4
  4. data/README.md +79 -40
  5. data/Rakefile +40 -25
  6. data/benchmarks/run.rb +35 -5
  7. data/lib/moneta.rb +5 -5
  8. data/lib/moneta/adapters/activerecord.rb +4 -6
  9. data/lib/moneta/adapters/cassandra.rb +8 -11
  10. data/lib/moneta/adapters/couch.rb +3 -1
  11. data/lib/moneta/adapters/daybreak.rb +28 -0
  12. data/lib/moneta/adapters/fog.rb +3 -3
  13. data/lib/moneta/adapters/hbase.rb +2 -4
  14. data/lib/moneta/adapters/memcached/dalli.rb +8 -7
  15. data/lib/moneta/adapters/memcached/native.rb +8 -9
  16. data/lib/moneta/adapters/mongo.rb +42 -11
  17. data/lib/moneta/adapters/pstore.rb +4 -6
  18. data/lib/moneta/adapters/redis.rb +17 -10
  19. data/lib/moneta/adapters/restclient.rb +19 -10
  20. data/lib/moneta/adapters/sequel.rb +4 -6
  21. data/lib/moneta/adapters/tdb.rb +22 -0
  22. data/lib/moneta/expires.rb +28 -12
  23. data/lib/moneta/mixins.rb +64 -3
  24. data/lib/moneta/pool.rb +37 -0
  25. data/lib/moneta/proxy.rb +18 -7
  26. data/lib/moneta/server.rb +1 -1
  27. data/lib/moneta/shared.rb +2 -2
  28. data/lib/moneta/transformer/helper.rb +1 -1
  29. data/lib/moneta/version.rb +1 -1
  30. data/{spec/generate.rb → script/generate-specs.rb} +195 -91
  31. data/script/install-bundle.rb +35 -0
  32. data/spec/helper.rb +6 -0
  33. data/spec/moneta/adapter_activerecord_spec.rb +1 -1
  34. data/spec/moneta/adapter_cassandra_spec.rb +1 -12
  35. data/spec/moneta/adapter_cassandra_with_default_expires_spec.rb +21 -0
  36. data/spec/moneta/adapter_client_spec.rb +1 -1
  37. data/spec/moneta/adapter_cookie_spec.rb +1 -1
  38. data/spec/moneta/adapter_couch_spec.rb +1 -1
  39. data/spec/moneta/adapter_datamapper_spec.rb +1 -1
  40. data/spec/moneta/adapter_daybreak_spec.rb +19 -0
  41. data/spec/moneta/adapter_dbm_spec.rb +1 -1
  42. data/spec/moneta/adapter_file_spec.rb +1 -1
  43. data/spec/moneta/adapter_fog_spec.rb +1 -1
  44. data/spec/moneta/adapter_gdbm_spec.rb +1 -1
  45. data/spec/moneta/adapter_hbase_spec.rb +1 -1
  46. data/spec/moneta/adapter_leveldb_spec.rb +1 -1
  47. data/spec/moneta/adapter_localmemcache_spec.rb +1 -1
  48. data/spec/moneta/adapter_lruhash_spec.rb +1 -1
  49. data/spec/moneta/adapter_memcached_dalli_spec.rb +1 -12
  50. data/spec/moneta/adapter_memcached_dalli_with_default_expires_spec.rb +21 -0
  51. data/spec/moneta/adapter_memcached_native_spec.rb +1 -13
  52. data/spec/moneta/adapter_memcached_native_with_default_expires_spec.rb +21 -0
  53. data/spec/moneta/adapter_memcached_spec.rb +1 -12
  54. data/spec/moneta/adapter_memcached_with_default_expires_spec.rb +21 -0
  55. data/spec/moneta/adapter_memory_spec.rb +1 -1
  56. data/spec/moneta/adapter_mongo_spec.rb +9 -2
  57. data/spec/moneta/adapter_mongo_with_default_expires_spec.rb +21 -0
  58. data/spec/moneta/adapter_pstore_spec.rb +1 -1
  59. data/spec/moneta/adapter_redis_spec.rb +1 -12
  60. data/spec/moneta/adapter_redis_with_default_expires_spec.rb +21 -0
  61. data/spec/moneta/adapter_restclient_spec.rb +1 -1
  62. data/spec/moneta/adapter_riak_spec.rb +1 -1
  63. data/spec/moneta/adapter_sdbm_spec.rb +1 -1
  64. data/spec/moneta/adapter_sequel_spec.rb +1 -1
  65. data/spec/moneta/adapter_sqlite_spec.rb +1 -1
  66. data/spec/moneta/adapter_tdb_spec.rb +19 -0
  67. data/spec/moneta/adapter_tokyocabinet_bdb_spec.rb +1 -1
  68. data/spec/moneta/adapter_tokyocabinet_hdb_spec.rb +1 -1
  69. data/spec/moneta/adapter_yaml_spec.rb +1 -1
  70. data/spec/moneta/cache_file_memory_spec.rb +1 -1
  71. data/spec/moneta/cache_memory_null_spec.rb +1 -1
  72. data/spec/moneta/expires_file_spec.rb +1 -1
  73. data/spec/moneta/expires_memory_spec.rb +1 -12
  74. data/spec/moneta/expires_memory_with_default_expires_spec.rb +111 -0
  75. data/spec/moneta/lock_spec.rb +1 -1
  76. data/spec/moneta/null_adapter_spec.rb +1 -1
  77. data/spec/moneta/optionmerger_spec.rb +1 -1
  78. data/spec/moneta/pool_spec.rb +23 -0
  79. data/spec/moneta/proxy_expires_memory_spec.rb +1 -1
  80. data/spec/moneta/proxy_redis_spec.rb +1 -1
  81. data/spec/moneta/shared_spec.rb +1 -1
  82. data/spec/moneta/simple_activerecord_spec.rb +1 -1
  83. data/spec/moneta/simple_activerecord_with_expires_spec.rb +1 -1
  84. data/spec/moneta/simple_cassandra_spec.rb +1 -1
  85. data/spec/moneta/simple_client_tcp_spec.rb +1 -1
  86. data/spec/moneta/simple_client_unix_spec.rb +1 -1
  87. data/spec/moneta/simple_couch_spec.rb +1 -1
  88. data/spec/moneta/simple_couch_with_expires_spec.rb +1 -1
  89. data/spec/moneta/simple_datamapper_spec.rb +1 -1
  90. data/spec/moneta/simple_datamapper_with_expires_spec.rb +1 -1
  91. data/spec/moneta/simple_datamapper_with_repository_spec.rb +1 -1
  92. data/spec/moneta/simple_daybreak_spec.rb +144 -0
  93. data/spec/moneta/simple_daybreak_with_expires_spec.rb +145 -0
  94. data/spec/moneta/simple_dbm_spec.rb +1 -1
  95. data/spec/moneta/simple_dbm_with_expires_spec.rb +1 -1
  96. data/spec/moneta/simple_file_spec.rb +1 -1
  97. data/spec/moneta/simple_file_with_expires_spec.rb +1 -1
  98. data/spec/moneta/simple_fog_spec.rb +1 -1
  99. data/spec/moneta/simple_fog_with_expires_spec.rb +1 -1
  100. data/spec/moneta/simple_gdbm_spec.rb +1 -1
  101. data/spec/moneta/simple_gdbm_with_expires_spec.rb +1 -1
  102. data/spec/moneta/simple_hashfile_spec.rb +1 -1
  103. data/spec/moneta/simple_hashfile_with_expires_spec.rb +1 -1
  104. data/spec/moneta/simple_hbase_spec.rb +1 -1
  105. data/spec/moneta/simple_hbase_with_expires_spec.rb +1 -1
  106. data/spec/moneta/simple_leveldb_spec.rb +1 -1
  107. data/spec/moneta/simple_leveldb_with_expires_spec.rb +1 -1
  108. data/spec/moneta/simple_localmemcache_spec.rb +1 -1
  109. data/spec/moneta/simple_localmemcache_with_expires_spec.rb +1 -1
  110. data/spec/moneta/simple_lruhash_spec.rb +1 -1
  111. data/spec/moneta/simple_lruhash_with_expires_spec.rb +1 -1
  112. data/spec/moneta/simple_memcached_dalli_spec.rb +1 -1
  113. data/spec/moneta/simple_memcached_native_spec.rb +1 -1
  114. data/spec/moneta/simple_memcached_spec.rb +1 -1
  115. data/spec/moneta/simple_memory_spec.rb +1 -1
  116. data/spec/moneta/simple_memory_with_compress_spec.rb +1 -1
  117. data/spec/moneta/simple_memory_with_expires_spec.rb +1 -1
  118. data/spec/moneta/simple_memory_with_json_key_serializer_spec.rb +1 -1
  119. data/spec/moneta/simple_memory_with_json_serializer_spec.rb +1 -1
  120. data/spec/moneta/simple_memory_with_json_value_serializer_spec.rb +1 -1
  121. data/spec/moneta/simple_memory_with_prefix_spec.rb +1 -1
  122. data/spec/moneta/simple_memory_with_snappy_compress_spec.rb +1 -1
  123. data/spec/moneta/simple_mongo_spec.rb +3 -2
  124. data/spec/moneta/simple_null_spec.rb +1 -1
  125. data/spec/moneta/simple_pstore_spec.rb +1 -1
  126. data/spec/moneta/simple_pstore_with_expires_spec.rb +1 -1
  127. data/spec/moneta/simple_redis_spec.rb +1 -1
  128. data/spec/moneta/simple_restclient_spec.rb +1 -1
  129. data/spec/moneta/simple_riak_spec.rb +1 -1
  130. data/spec/moneta/simple_riak_with_expires_spec.rb +1 -1
  131. data/spec/moneta/simple_sdbm_spec.rb +1 -1
  132. data/spec/moneta/simple_sdbm_with_expires_spec.rb +1 -1
  133. data/spec/moneta/simple_sequel_spec.rb +1 -1
  134. data/spec/moneta/simple_sequel_with_expires_spec.rb +1 -1
  135. data/spec/moneta/simple_sqlite_spec.rb +1 -1
  136. data/spec/moneta/simple_sqlite_with_expires_spec.rb +1 -1
  137. data/spec/moneta/simple_tdb_spec.rb +144 -0
  138. data/spec/moneta/{simple_mongo_with_expires_spec.rb → simple_tdb_with_expires_spec.rb} +4 -4
  139. data/spec/moneta/simple_tokyocabinet_spec.rb +1 -1
  140. data/spec/moneta/simple_tokyocabinet_with_expires_spec.rb +1 -1
  141. data/spec/moneta/simple_yaml_spec.rb +1 -1
  142. data/spec/moneta/simple_yaml_with_expires_spec.rb +1 -1
  143. data/spec/moneta/stack_file_memory_spec.rb +1 -1
  144. data/spec/moneta/stack_memory_file_spec.rb +1 -1
  145. data/spec/moneta/transformer_bencode_spec.rb +1 -1
  146. data/spec/moneta/transformer_bert_spec.rb +1 -1
  147. data/spec/moneta/transformer_bson_spec.rb +1 -1
  148. data/spec/moneta/transformer_bzip2_spec.rb +1 -1
  149. data/spec/moneta/transformer_json_spec.rb +1 -1
  150. data/spec/moneta/transformer_key_marshal_spec.rb +1 -1
  151. data/spec/moneta/transformer_key_yaml_spec.rb +1 -1
  152. data/spec/moneta/transformer_lzma_spec.rb +1 -1
  153. data/spec/moneta/transformer_lzo_spec.rb +1 -1
  154. data/spec/moneta/transformer_marshal_base64_spec.rb +1 -1
  155. data/spec/moneta/transformer_marshal_escape_spec.rb +1 -1
  156. data/spec/moneta/transformer_marshal_hmac_spec.rb +1 -1
  157. data/spec/moneta/transformer_marshal_md5_spec.rb +1 -1
  158. data/spec/moneta/transformer_marshal_md5_spread_spec.rb +1 -1
  159. data/spec/moneta/transformer_marshal_prefix_spec.rb +1 -1
  160. data/spec/moneta/transformer_marshal_rmd160_spec.rb +1 -1
  161. data/spec/moneta/transformer_marshal_sha1_spec.rb +1 -1
  162. data/spec/moneta/transformer_marshal_sha256_spec.rb +1 -1
  163. data/spec/moneta/transformer_marshal_sha384_spec.rb +1 -1
  164. data/spec/moneta/transformer_marshal_sha512_spec.rb +1 -1
  165. data/spec/moneta/transformer_marshal_spec.rb +1 -1
  166. data/spec/moneta/transformer_marshal_truncate_spec.rb +1 -1
  167. data/spec/moneta/transformer_marshal_uuencode_spec.rb +1 -1
  168. data/spec/moneta/transformer_msgpack_spec.rb +1 -1
  169. data/spec/moneta/transformer_ox_spec.rb +1 -1
  170. data/spec/moneta/transformer_quicklz_spec.rb +1 -1
  171. data/spec/moneta/transformer_snappy_spec.rb +1 -1
  172. data/spec/moneta/transformer_tnet_spec.rb +1 -1
  173. data/spec/moneta/transformer_value_marshal_spec.rb +1 -1
  174. data/spec/moneta/transformer_value_yaml_spec.rb +1 -1
  175. data/spec/moneta/transformer_yaml_spec.rb +1 -1
  176. data/spec/moneta/transformer_zlib_spec.rb +1 -1
  177. data/spec/monetaspecs.rb +105 -3
  178. metadata +35 -6
@@ -1,4 +1,4 @@
1
- require 'httpi'
1
+ require 'net/http'
2
2
 
3
3
  module Moneta
4
4
  module Adapters
@@ -10,38 +10,47 @@ module Moneta
10
10
  # @param [Hash] options
11
11
  # @option options [String] :url URL
12
12
  def initialize(options = {})
13
- raise ArgumentError, 'Option :url is required' unless @url = options[:url]
13
+ raise ArgumentError, 'Option :url is required' unless url = options[:url]
14
+ url = URI(url)
15
+ @path = url.path
16
+ @client = ::Net::HTTP.start(url.host, url.port)
14
17
  end
15
18
 
16
19
  # (see Proxy#key?)
17
20
  def key?(key, options = {})
18
- response = HTTPI.head(@url + key)
19
- response.code == 200
21
+ response = @client.request_head(@path + key)
22
+ response.code == '200'
20
23
  end
21
24
 
22
25
  # (see Proxy#load)
23
26
  def load(key, options = {})
24
- response = HTTPI.get(@url + key)
25
- response.code == 200 ? response.body : nil
27
+ response = @client.request_get(@path + key)
28
+ response.code == '200' ? response.body : nil
26
29
  end
27
30
 
28
31
  # (see Proxy#store)
29
32
  def store(key, value, options = {})
30
- HTTPI.post(@url + key, value)
33
+ response = @client.request_post(@path + key, value)
34
+ raise "HTTP error #{response.code}" unless response.code == '200'
31
35
  value
32
36
  end
33
37
 
34
38
  # (see Proxy#delete)
35
39
  def delete(key, options = {})
36
- response = HTTPI.delete(@url + key)
37
- response.code == 200 ? response.body : nil
40
+ response = @client.request(::Net::HTTP::Delete.new(@path + key))
41
+ response.code == '200' ? response.body : nil
38
42
  end
39
43
 
40
44
  # (see Proxy#clear)
41
45
  def clear(options = {})
42
- HTTPI.delete(@url)
46
+ @client.request(::Net::HTTP::Delete.new(@path))
43
47
  self
44
48
  end
49
+
50
+ def close
51
+ @client.finish
52
+ nil
53
+ end
45
54
  end
46
55
  end
47
56
  end
@@ -6,6 +6,7 @@ module Moneta
6
6
  # @api public
7
7
  class Sequel
8
8
  include Defaults
9
+ include IncrementSupport
9
10
 
10
11
  # @param [Hash] options
11
12
  # @option options [String] :db Sequel database
@@ -50,12 +51,9 @@ module Moneta
50
51
  @db.transaction do
51
52
  locked_table = @table.for_update
52
53
  if record = locked_table[:k => key]
53
- value = record[:v]
54
- intvalue = value.to_i
55
- raise 'Tried to increment non integer value' unless value == nil || intvalue.to_s == value.to_s
56
- intvalue += amount
57
- locked_table.update(:k => key, :v => intvalue.to_s)
58
- intvalue
54
+ value = convert_for_increment(record[:v]) + amount
55
+ locked_table.update(:k => key, :v => value.to_s)
56
+ value
59
57
  else
60
58
  locked_table.insert(:k => key, :v => amount.to_s)
61
59
  amount
@@ -0,0 +1,22 @@
1
+ require 'tdb'
2
+
3
+ module Moneta
4
+ module Adapters
5
+ # TDB backend
6
+ # @api public
7
+ class TDB < Memory
8
+ # @param [Hash] options
9
+ # @option options [String] :file Database file
10
+ def initialize(options = {})
11
+ raise ArgumentError, 'Option :file is required' unless file = options.delete(:file)
12
+ @hash = ::TDB.new(file, options)
13
+ end
14
+
15
+ # (see Proxy#close)
16
+ def close
17
+ @hash.close
18
+ nil
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,17 +1,19 @@
1
1
  module Moneta
2
2
  # Adds expiration support to the underlying store
3
3
  #
4
- # #store and #load support the :expires option to set/update
4
+ # `#store`, `#load` and `#key?` support the `:expires` option to set/update
5
5
  # the expiration time.
6
6
  #
7
7
  # @api public
8
8
  class Expires < Proxy
9
+ include ExpiresSupport
10
+
9
11
  # @param [Moneta store] adapter The underlying store
10
12
  # @param [Hash] options
11
13
  # @option options [String] :expires Default expiration time
12
14
  def initialize(adapter, options = {})
13
15
  super
14
- @expires = options[:expires]
16
+ self.default_expires = options[:expires]
15
17
  end
16
18
 
17
19
  # (see Proxy#key?)
@@ -33,14 +35,12 @@ module Moneta
33
35
  # (see Proxy#store)
34
36
  def store(key, value, options = {})
35
37
  return super if options.include?(:raw)
36
- expires = options.include?(:expires) && (options = options.dup; options.delete(:expires))
37
- if expires ||= @expires
38
- super(key, [value, Time.now.to_i + expires], options)
39
- elsif Array === value || value == nil
40
- super(key, [value], options)
41
- else
42
- super(key, value, options)
38
+ expires = expires_at(options)
39
+ if options.include?(:expires)
40
+ options = options.dup
41
+ options.delete(:expires)
43
42
  end
43
+ store_entry(key, value, expires, options)
44
44
  value
45
45
  end
46
46
 
@@ -54,20 +54,36 @@ module Moneta
54
54
  private
55
55
 
56
56
  def load_entry(key, options)
57
- new_expires = options.include?(:expires) && (options = options.dup; options.delete(:expires))
57
+ new_expires = expires_at(options, nil)
58
+ if options.include?(:expires)
59
+ options = options.dup
60
+ options.delete(:expires)
61
+ end
58
62
  entry = @adapter.load(key, options)
59
63
  if entry != nil
60
64
  value, expires = entry
61
65
  if expires && Time.now.to_i > expires
62
66
  delete(key)
63
67
  nil
64
- elsif new_expires
65
- @adapter.store(key, [value, Time.now.to_i + new_expires], options)
68
+ elsif new_expires != nil
69
+ store_entry(key, value, new_expires, options)
66
70
  entry
67
71
  else
68
72
  entry
69
73
  end
70
74
  end
71
75
  end
76
+
77
+ def store_entry(key, value, expires, options)
78
+ entry =
79
+ if expires
80
+ [value, expires.to_i]
81
+ elsif Array === value || value == nil
82
+ [value]
83
+ else
84
+ value
85
+ end
86
+ @adapter.store(key, entry, options)
87
+ end
72
88
  end
73
89
  end
data/lib/moneta/mixins.rb CHANGED
@@ -51,6 +51,9 @@ module Moneta
51
51
  #
52
52
  # @param [Object] key
53
53
  # @param [Hash] options
54
+ # @option options [Integer] :expires Update expiration time (See `Moneta::Expires`)
55
+ # @option options [String] :prefix Prefix key (See `Moneta::Transformer`)
56
+ # @option options Other options as defined by the adapters or middleware
54
57
  # @return [Boolean]
55
58
  # @api public
56
59
  def key?(key, options = {})
@@ -146,11 +149,16 @@ module Moneta
146
149
  # (see Defaults#increment)
147
150
  # @api public
148
151
  def increment(key, amount = 1, options = {})
149
- value = load(key, options)
152
+ value = convert_for_increment(load(key, options)) + amount
153
+ store(key, value.to_s, options)
154
+ value
155
+ end
156
+
157
+ protected
158
+
159
+ def convert_for_increment(value)
150
160
  intvalue = value.to_i
151
161
  raise 'Tried to increment non integer value' unless value == nil || intvalue.to_s == value.to_s
152
- intvalue += amount
153
- store(key, intvalue.to_s, options)
154
162
  intvalue
155
163
  end
156
164
  end
@@ -204,4 +212,57 @@ module Moneta
204
212
  io.write(pack(o))
205
213
  end
206
214
  end
215
+
216
+ # This mixin handles the calculation of expiration times.
217
+ #
218
+ #
219
+ module ExpiresSupport
220
+ attr_accessor :default_expires
221
+
222
+ protected
223
+
224
+ # Calculates the time when something will expire.
225
+ #
226
+ # This method considers false and 0 as "no-expire" and every positive
227
+ # number as a time to live in seconds.
228
+ #
229
+ # @param [Hash] options Options hash
230
+ # @option options [0,false,nil,Numeric] :expires expires value given by user
231
+ # @param [0,false,nil,Numeric] default default expiration time
232
+ #
233
+ # @return [false] if it should not expire
234
+ # @return [Time] the time when something should expire
235
+ # @return [nil] if it is not known
236
+ def expires_at(options, default = @default_expires)
237
+ value = expires_value(options, default)
238
+ Numeric === value ? Time.now + value : value
239
+ end
240
+
241
+ # Calculates the number of seconds something should last.
242
+ #
243
+ # This method considers false and 0 as "no-expire" and every positive
244
+ # number as a time to live in seconds.
245
+ #
246
+ # @param [Hash] options Options hash
247
+ # @option options [0,false,nil,Numeric] :expires expires value given by user
248
+ # @param [0,false,nil,Numeric] default default expiration time
249
+ #
250
+ # @return [false] if it should not expire
251
+ # @return [Numeric] seconds until expiration
252
+ # @return [nil] if it is not known
253
+ def expires_value(options, default = @default_expires)
254
+ case value = options[:expires]
255
+ when 0, false
256
+ false
257
+ when nil
258
+ default ? default.to_i : nil
259
+ when Numeric
260
+ value = value.to_i
261
+ raise ArgumentError, ":expires must be a positive value, got #{value}" if value < 0
262
+ value
263
+ else
264
+ raise ArgumentError, ":expires must be Numeric or false, got #{value.inspect}"
265
+ end
266
+ end
267
+ end
207
268
  end
@@ -0,0 +1,37 @@
1
+ module Moneta
2
+ # Creates a pool of stores.
3
+ # Each thread gets its own store.
4
+ #
5
+ # @example Add `Moneta::Pool` to proxy stack
6
+ # Moneta.build do
7
+ # use(:Pool) do
8
+ # # Every thread gets its own instance
9
+ # adapter :MemcachedNative
10
+ # end
11
+ # end
12
+ #
13
+ # @api public
14
+ class Pool < Wrapper
15
+ # @param [Moneta store] adapter The underlying store
16
+ # @param [Hash] options
17
+ def initialize(options = {}, &block)
18
+ super(nil)
19
+ @builder = Builder.new(&block)
20
+ @pool, @active = [], {}
21
+ end
22
+
23
+ protected
24
+
25
+ def adapter
26
+ @active[Thread.current]
27
+ end
28
+
29
+ def wrap(*args)
30
+ @pool << @builder.build.last if @pool.empty?
31
+ @active[Thread.current] = @pool.pop
32
+ yield
33
+ ensure
34
+ @pool << @active.delete(Thread.current)
35
+ end
36
+ end
37
+ end
data/lib/moneta/proxy.rb CHANGED
@@ -14,27 +14,31 @@ module Moneta
14
14
 
15
15
  # (see Defaults#key?)
16
16
  def key?(key, options = {})
17
- @adapter.key?(key, options)
17
+ adapter.key?(key, options)
18
18
  end
19
19
 
20
20
  # (see Defaults#increment)
21
21
  def increment(key, amount = 1, options = {})
22
- @adapter.increment(key, amount, options)
22
+ adapter.increment(key, amount, options)
23
23
  end
24
24
 
25
25
  # (see Defaults#close)
26
26
  def close
27
- @adapter.close
27
+ adapter.close
28
28
  end
29
29
 
30
30
  # Fetch value with key. Return nil if the key doesn't exist
31
31
  #
32
32
  # @param [Object] key
33
33
  # @param [Hash] options
34
+ # @option options [Integer] :expires Update expiration time (See `Moneta::Expires`)
35
+ # @option options [Boolean] :raw Raw access without value transformation (See `Moneta::Transformer`)
36
+ # @option options [String] :prefix Prefix key (See `Moneta::Transformer`)
37
+ # @option options Other options as defined by the adapters or middleware
34
38
  # @return [Object] value
35
39
  # @api public
36
40
  def load(key, options = {})
37
- @adapter.load(key, options)
41
+ adapter.load(key, options)
38
42
  end
39
43
 
40
44
  # Store value with key
@@ -42,10 +46,14 @@ module Moneta
42
46
  # @param [Object] key
43
47
  # @param [Object] value
44
48
  # @param [Hash] options
49
+ # @option options [Integer] :expires Set expiration time (See `Moneta::Expires`)
50
+ # @option options [Boolean] :raw Raw access without value transformation (See `Moneta::Transformer`)
51
+ # @option options [String] :prefix Prefix key (See `Moneta::Transformer`)
52
+ # @option options Other options as defined by the adapters or middleware
45
53
  # @return value
46
54
  # @api public
47
55
  def store(key, value, options = {})
48
- @adapter.store(key, value, options)
56
+ adapter.store(key, value, options)
49
57
  end
50
58
 
51
59
  # Delete the key from the store and return the current value
@@ -53,9 +61,12 @@ module Moneta
53
61
  # @param [Object] key
54
62
  # @return [Object] current value
55
63
  # @param [Hash] options
64
+ # @option options [Boolean] :raw Raw access without value transformation (See `Moneta::Transformer`)
65
+ # @option options [String] :prefix Prefix key (See `Moneta::Transformer`)
66
+ # @option options Other options as defined by the adapters or middleware
56
67
  # @api public
57
68
  def delete(key, options = {})
58
- @adapter.delete(key, options)
69
+ adapter.delete(key, options)
59
70
  end
60
71
 
61
72
  # Clear all keys in this store
@@ -64,7 +75,7 @@ module Moneta
64
75
  # @return [void]
65
76
  # @api public
66
77
  def clear(options = {})
67
- @adapter.clear(options)
78
+ adapter.clear(options)
68
79
  self
69
80
  end
70
81
  end
data/lib/moneta/server.rb CHANGED
@@ -59,7 +59,7 @@ module Moneta
59
59
  client = accept
60
60
  handle(client) if client
61
61
  rescue Exception => ex
62
- puts ex.message
62
+ warn ex.message
63
63
  write(client, Error.new(ex.message)) if client
64
64
  end
65
65
 
data/lib/moneta/shared.rb CHANGED
@@ -39,7 +39,7 @@ module Moneta
39
39
  @adapter ||= Adapters::Client.new(@options)
40
40
  yield
41
41
  rescue Exception => ex
42
- puts "Failed to connect: #{ex.message}"
42
+ warn "Failed to connect: #{ex.message}"
43
43
  begin
44
44
  # TODO: Implement this using forking (MRI) and threading (JRuby)
45
45
  # to get maximal performance
@@ -48,7 +48,7 @@ module Moneta
48
48
  @thread = Thread.new { @server.run }
49
49
  sleep 0.1 until @server.running?
50
50
  rescue Exception => ex
51
- puts "Failed to start server: #{ex.message}"
51
+ warn "Failed to start server: #{ex.message}"
52
52
  @adapter.close if @adapter
53
53
  @adapter = nil
54
54
  end
@@ -24,7 +24,7 @@ module Moneta
24
24
  def truncate(value, maxlen)
25
25
  if value.size >= maxlen
26
26
  digest = Digest::MD5.hexdigest(value)
27
- value = value[0, value.size-digest.size] << digest
27
+ value = value[0, maxlen-digest.size] << digest
28
28
  end
29
29
  value
30
30
  end
@@ -1,5 +1,5 @@
1
1
  module Moneta
2
2
  # Moneta version number
3
3
  # @api public
4
- VERSION = '0.7.3'
4
+ VERSION = '0.7.4'
5
5
  end
@@ -1,3 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ PATH = File.expand_path(File.join(__FILE__, '..', '..', 'spec'))
4
+
1
5
  class Specs
2
6
  attr_reader :key, :value, :specs
3
7
 
@@ -93,13 +97,19 @@ class Specs
93
97
  a.delete(:marshallable_value)
94
98
  Specs.new(a, key, value)
95
99
  end
100
+
101
+ def with_default_expires
102
+ a = specs.dup
103
+ a << :default_expires
104
+ Specs.new(a, key, value)
105
+ end
96
106
  end
97
107
 
98
108
  ADAPTER_SPECS = Specs.new([:null, :store, :returndifferent, :increment, :persist], %w(string), %w(string))
99
109
  STANDARD_SPECS = Specs.new([:null, :store, :returndifferent, :marshallable_key, :marshallable_value, :transform_value, :increment, :persist])
100
110
  TRANSFORMER_SPECS = Specs.new([:null, :store, :returndifferent, :transform_value, :increment])
101
111
 
102
- header = "# Generated by #{__FILE__}\n"
112
+ header = "# Generated by #{File.basename(__FILE__)}\n"
103
113
 
104
114
  TESTS = {
105
115
  'simple_client_tcp' => {
@@ -232,6 +242,26 @@ end
232
242
  :options => ':file => File.join(make_tempdir, "simple_dbm_with_expires"), :expires => true',
233
243
  :specs => STANDARD_SPECS.with_expires
234
244
  },
245
+ 'simple_tdb' => {
246
+ :store => :TDB,
247
+ :options => ':file => File.join(make_tempdir, "simple_tdb")',
248
+ :specs => STANDARD_SPECS
249
+ },
250
+ 'simple_tdb_with_expires' => {
251
+ :store => :TDB,
252
+ :options => ':file => File.join(make_tempdir, "simple_tdb_with_expires"), :expires => true',
253
+ :specs => STANDARD_SPECS.with_expires
254
+ },
255
+ 'simple_daybreak' => {
256
+ :store => :Daybreak,
257
+ :options => ':file => File.join(make_tempdir, "simple_daybreak")',
258
+ :specs => STANDARD_SPECS
259
+ },
260
+ 'simple_daybreak_with_expires' => {
261
+ :store => :Daybreak,
262
+ :options => ':file => File.join(make_tempdir, "simple_daybreak_with_expires"), :expires => true',
263
+ :specs => STANDARD_SPECS.with_expires
264
+ },
235
265
  'simple_gdbm' => {
236
266
  :store => :GDBM,
237
267
  :options => ':file => File.join(make_tempdir, "simple_gdbm")',
@@ -364,12 +394,7 @@ end
364
394
  'simple_mongo' => {
365
395
  :store => :Mongo,
366
396
  :options => ":db => 'simple_mongo'",
367
- :specs => STANDARD_SPECS.without_increment
368
- },
369
- 'simple_mongo_with_expires' => {
370
- :store => :Mongo,
371
- :options => ":db => 'simple_mongo_with_expires', :expires => true",
372
- :specs => STANDARD_SPECS.without_increment.with_expires
397
+ :specs => STANDARD_SPECS.with_native_expires
373
398
  },
374
399
  'simple_null' => {
375
400
  :store => :Null,
@@ -453,19 +478,14 @@ end
453
478
  use :Expires
454
479
  adapter :Memory
455
480
  end},
456
- :specs => STANDARD_SPECS.without_transform.with_expires.without_persist,
457
- :tests => %{
458
- it 'supports default expiration time' do
459
- store = Moneta.new(:Memory, :expires => 2)
460
- store.store('key1', 'val1')
461
- store.store('key2', 'val2', :expires => 60)
462
- store.load('key1').should == 'val1'
463
- sleep 1
464
- store.load('key1').should == 'val1'
465
- sleep 2
466
- store.load('key1').should be_nil
467
- store['key2'].should == 'val2'
468
- end}
481
+ :specs => STANDARD_SPECS.without_transform.with_expires.without_persist
482
+ },
483
+ 'expires_memory_with_default_expires' => {
484
+ :build => %{Moneta.build do
485
+ use :Expires, :expires => 1
486
+ adapter :Memory
487
+ end},
488
+ :specs => STANDARD_SPECS.without_transform.with_expires.with_default_expires.without_persist
469
489
  },
470
490
  'expires_file' => {
471
491
  :build => %{Moneta.build do
@@ -580,6 +600,14 @@ end},
580
600
  end},
581
601
  :specs => STANDARD_SPECS.without_transform.without_returndifferent.without_persist
582
602
  },
603
+ 'pool' => {
604
+ :build => %{Moneta.build do
605
+ use :Pool do
606
+ adapter :File, :dir => File.join(make_tempdir, "pool")
607
+ end
608
+ end},
609
+ :specs => ADAPTER_SPECS
610
+ },
583
611
  'transformer_zlib' => {
584
612
  :build => %{Moneta.build do
585
613
  use :Transformer, :value => :zlib
@@ -857,19 +885,11 @@ end
857
885
  },
858
886
  'adapter_cassandra' => {
859
887
  :build => "Moneta::Adapters::Cassandra.new(:keyspace => 'adapter_cassandra')",
860
- :specs => ADAPTER_SPECS.without_increment.with_expires,
861
- :tests => %{
862
- it 'supports default expiration time' do
863
- store = Moneta::Adapters::Cassandra.new(:expires => 2, :keyspace => 'adapter_cassandra')
864
- store.store('key1', 'val1')
865
- store.store('key2', 'val2', :expires => 60)
866
- store.load('key1').should == 'val1'
867
- sleep 1
868
- store.load('key1').should == 'val1'
869
- sleep 2
870
- store.load('key1').should be_nil
871
- store['key2'].should == 'val2'
872
- end}
888
+ :specs => ADAPTER_SPECS.without_increment.with_native_expires
889
+ },
890
+ 'adapter_cassandra_with_default_expires' => {
891
+ :build => %{Moneta::Adapters::Cassandra.new(:expires => 1)},
892
+ :specs => ADAPTER_SPECS.without_increment.with_native_expires.with_default_expires
873
893
  },
874
894
  'adapter_hbase' => {
875
895
  :build => "Moneta::Adapters::HBase.new(:table => 'adapter_hbase')",
@@ -923,6 +943,14 @@ end
923
943
  :build => 'Moneta::Adapters::DBM.new(:file => File.join(make_tempdir, "adapter_dbm"))',
924
944
  :specs => ADAPTER_SPECS
925
945
  },
946
+ 'adapter_tdb' => {
947
+ :build => 'Moneta::Adapters::TDB.new(:file => File.join(make_tempdir, "adapter_tdb"))',
948
+ :specs => ADAPTER_SPECS
949
+ },
950
+ 'adapter_daybreak' => {
951
+ :build => 'Moneta::Adapters::Daybreak.new(:file => File.join(make_tempdir, "adapter_daybreak"))',
952
+ :specs => ADAPTER_SPECS
953
+ },
926
954
  'adapter_file' => {
927
955
  :build => 'Moneta::Adapters::File.new(:dir => File.join(make_tempdir, "adapter_file"))',
928
956
  :specs => ADAPTER_SPECS
@@ -946,52 +974,27 @@ end
946
974
  },
947
975
  'adapter_memcached_dalli' => {
948
976
  :build => 'Moneta::Adapters::MemcachedDalli.new(:namespace => "adapter_memcached_dalli")',
949
- :specs => ADAPTER_SPECS.with_expires,
950
- :tests => %{
951
- it 'supports default expiration time' do
952
- store = Moneta::Adapters::MemcachedDalli.new(:expires => 2, :namespace => "adapter_memcached_dalli")
953
- store.store('key1', 'val1')
954
- store.store('key2', 'val2', :expires => 60)
955
- store.load('key1').should == 'val1'
956
- sleep 1
957
- store.load('key1').should == 'val1'
958
- sleep 2
959
- store.load('key1').should be_nil
960
- store['key2'].should == 'val2'
961
- end}
977
+ :specs => ADAPTER_SPECS.with_native_expires
978
+ },
979
+ 'adapter_memcached_dalli_with_default_expires' => {
980
+ :build => %{Moneta::Adapters::MemcachedDalli.new(:expires => 1)},
981
+ :specs => ADAPTER_SPECS.with_native_expires.with_default_expires
962
982
  },
963
983
  'adapter_memcached_native' => {
964
984
  :build => 'Moneta::Adapters::MemcachedNative.new(:namespace => "adapter_memcached_native")',
965
- :specs => ADAPTER_SPECS.with_expires,
966
- :tests => %{
967
- it 'supports default expiration time' do
968
- store = Moneta::Adapters::MemcachedNative.new(:expires => 2, :namespace => "adapter_memcached_native")
969
- store.store('key1', 'val1')
970
- store.store('key2', 'val2', :expires => 60)
971
- store.load('key1').should == 'val1'
972
- sleep 1
973
- store.load('key1').should == 'val1'
974
- sleep 2
975
- store.load('key1').should be_nil
976
- store['key2'].should == 'val2'
977
- end
978
- }
985
+ :specs => ADAPTER_SPECS.with_native_expires
986
+ },
987
+ 'adapter_memcached_native_with_default_expires' => {
988
+ :build => %{Moneta::Adapters::MemcachedNative.new(:expires => 1)},
989
+ :specs => ADAPTER_SPECS.with_native_expires.with_default_expires
979
990
  },
980
991
  'adapter_memcached' => {
981
992
  :build => 'Moneta::Adapters::Memcached.new(:namespace => "adapter_memcached")',
982
- :specs => ADAPTER_SPECS.with_expires,
983
- :tests => %{
984
- it 'supports default expiration time' do
985
- store = Moneta::Adapters::Memcached.new(:expires => 2, :namespace => "adapter_memcached")
986
- store.store('key1', 'val1')
987
- store.store('key2', 'val2', :expires => 60)
988
- store.load('key1').should == 'val1'
989
- sleep 1
990
- store.load('key1').should == 'val1'
991
- sleep 2
992
- store.load('key1').should be_nil
993
- store['key2'].should == 'val2'
994
- end}
993
+ :specs => ADAPTER_SPECS.with_native_expires
994
+ },
995
+ 'adapter_memcached_with_default_expires' => {
996
+ :build => %{Moneta::Adapters::Memcached.new(:expires => 1)},
997
+ :specs => ADAPTER_SPECS.with_native_expires.with_default_expires
995
998
  },
996
999
  'adapter_memory' => {
997
1000
  :build => 'Moneta::Adapters::Memory.new',
@@ -1017,7 +1020,18 @@ end}
1017
1020
  },
1018
1021
  'adapter_mongo' => {
1019
1022
  :build => 'Moneta::Adapters::Mongo.new(:db => "adapter_mongo")',
1020
- :specs => ADAPTER_SPECS.without_increment
1023
+ :specs => ADAPTER_SPECS.with_native_expires,
1024
+ :tests => %{
1025
+ it 'automatically deletes expired document' do
1026
+ store.store('key', 'val', :expires => 30)
1027
+ store.instance_variable_get(:@collection).find_one('_id' => ::BSON::Binary.new('key')).should_not be_nil
1028
+ sleep 70 # Mongo needs up to 60 seconds
1029
+ store.instance_variable_get(:@collection).find_one('_id' => ::BSON::Binary.new('key')).should be_nil
1030
+ end}
1031
+ },
1032
+ 'adapter_mongo_with_default_expires' => {
1033
+ :build => %{Moneta::Adapters::Mongo.new(:expires => 1)},
1034
+ :specs => ADAPTER_SPECS.with_expires.with_default_expires
1021
1035
  },
1022
1036
  'adapter_pstore' => {
1023
1037
  :build => 'Moneta::Adapters::PStore.new(:file => File.join(make_tempdir, "adapter_pstore"))',
@@ -1025,19 +1039,11 @@ end}
1025
1039
  },
1026
1040
  'adapter_redis' => {
1027
1041
  :build => 'Moneta::Adapters::Redis.new',
1028
- :specs => ADAPTER_SPECS.with_expires,
1029
- :tests => %{
1030
- it 'supports default expiration time' do
1031
- store = Moneta::Adapters::Redis.new(:expires => 2)
1032
- store.store('key1', 'val1')
1033
- store.store('key2', 'val2', :expires => 60)
1034
- store.load('key1').should == 'val1'
1035
- sleep 1
1036
- store.load('key1').should == 'val1'
1037
- sleep 2
1038
- store.load('key1').should be_nil
1039
- store['key2'].should == 'val2'
1040
- end}
1042
+ :specs => ADAPTER_SPECS.with_native_expires
1043
+ },
1044
+ 'adapter_redis_with_default_expires' => {
1045
+ :build => %{Moneta::Adapters::Redis.new(:expires => 1)},
1046
+ :specs => ADAPTER_SPECS.with_native_expires.with_default_expires
1041
1047
  },
1042
1048
  'adapter_riak' => {
1043
1049
  :build => 'Moneta::Adapters::Riak.new',
@@ -1330,6 +1336,20 @@ SPECS['expires'] = %{it 'supports expires on store and #[]' do
1330
1336
  store['key1'].should be_nil
1331
1337
  end
1332
1338
 
1339
+ it 'supports 0 as no-expires on store and #[]' do
1340
+ store.store('key1', 'val1', :expires => 0)
1341
+ store['key1'].should == 'val1'
1342
+ sleep 2
1343
+ store['key1'].should == 'val1'
1344
+ end
1345
+
1346
+ it 'supports false as no-expires on store and #[]' do
1347
+ store.store('key1', 'val1', :expires => false)
1348
+ store['key1'].should == 'val1'
1349
+ sleep 2
1350
+ store['key1'].should == 'val1'
1351
+ end
1352
+
1333
1353
  it 'supports expires on store and load' do
1334
1354
  store.store('key1', 'val1', :expires => 2)
1335
1355
  store.load('key1').should == 'val1'
@@ -1360,6 +1380,20 @@ it 'supports updating the expiration time in load' do
1360
1380
  store['key2'].should be_nil
1361
1381
  end
1362
1382
 
1383
+ it 'supports 0 as no-expires in load' do
1384
+ store.store('key1', 'val1', :expires => 2)
1385
+ store.load('key1', :expires => 0).should == 'val1'
1386
+ sleep 2
1387
+ store.load('key1').should == 'val1'
1388
+ end
1389
+
1390
+ it 'supports false as no-expires in load' do
1391
+ store.store('key1', 'val1', :expires => 2)
1392
+ store.load('key1', :expires => false).should == 'val1'
1393
+ sleep 2
1394
+ store.load('key1').should == 'val1'
1395
+ end
1396
+
1363
1397
  it 'supports updating the expiration time in key?' do
1364
1398
  store.store('key2', 'val2', :expires => 2)
1365
1399
  store['key2'].should == 'val2'
@@ -1372,6 +1406,20 @@ it 'supports updating the expiration time in key?' do
1372
1406
  store['key2'].should be_nil
1373
1407
  end
1374
1408
 
1409
+ it 'supports 0 as no-expires in key?' do
1410
+ store.store('key1', 'val1', :expires => 2)
1411
+ store.key?('key1', :expires => 0).should be_true
1412
+ sleep 2
1413
+ store['key1'].should == 'val1'
1414
+ end
1415
+
1416
+ it 'supports false as no-expires in key?' do
1417
+ store.store('key1', 'val1', :expires => 2)
1418
+ store.key?('key1', :expires => false ).should be_true
1419
+ sleep 2
1420
+ store['key1'].should == 'val1'
1421
+ end
1422
+
1375
1423
  it 'supports updating the expiration time in fetch' do
1376
1424
  store.store('key1', 'val1', :expires => 2)
1377
1425
  store['key1'].should == 'val1'
@@ -1384,6 +1432,20 @@ it 'supports updating the expiration time in fetch' do
1384
1432
  store['key1'].should be_nil
1385
1433
  end
1386
1434
 
1435
+ it 'supports 0 as no-expires in fetch' do
1436
+ store.store('key1', 'val1', :expires => 2)
1437
+ store.fetch('key1', nil, :expires => 0).should == 'val1'
1438
+ sleep 2
1439
+ store.load('key1').should == 'val1'
1440
+ end
1441
+
1442
+ it 'supports false as no-expires in fetch' do
1443
+ store.store('key1', 'val1', :expires => 2)
1444
+ store.fetch('key1', nil, :expires => false).should == 'val1'
1445
+ sleep 2
1446
+ store.load('key1').should == 'val1'
1447
+ end
1448
+
1387
1449
  it 'respects expires in delete' do
1388
1450
  store.store('key2', 'val2', :expires => 2)
1389
1451
  store['key2'].should == 'val2'
@@ -1394,14 +1456,56 @@ it 'respects expires in delete' do
1394
1456
  end
1395
1457
 
1396
1458
  it 'supports the #expires syntactic sugar' do
1397
- store['longlive_key'] = 'longlive_value'
1459
+ store.store('persistent_key', 'persistent_value', :expires => 0)
1398
1460
  store.expires(2).store('key2', 'val2')
1399
1461
  store['key2'].should == 'val2'
1400
1462
  sleep 1
1401
1463
  store['key2'].should == 'val2'
1402
1464
  sleep 2
1403
1465
  store.delete('key2').should be_nil
1404
- store['longlive_key'].should == 'longlive_value'
1466
+ store['persistent_key'].should == 'persistent_value'
1467
+ end
1468
+
1469
+ it 'supports false as no-expires on store and #[]' do
1470
+ store.store('key1', 'val1', :expires => false)
1471
+ store['key1'].should == 'val1'
1472
+ sleep 2
1473
+ store['key1'].should == 'val1'
1474
+ end
1475
+
1476
+ it 'does not update the expiration time in key? when not asked to do so' do
1477
+ store.store('key1', 'val1', :expires => 1)
1478
+ store.key?('key1').should be_true
1479
+ store.key?('key1', :expires => nil).should be_true
1480
+ sleep 2
1481
+ store.key?('key1').should be_false
1482
+ end
1483
+
1484
+ it 'does not update the expiration time in fetch when not asked to do so' do
1485
+ store.store('key1', 'val1', :expires => 1)
1486
+ store.fetch('key1').should == 'val1'
1487
+ store.fetch('key1', :expires => nil).should == 'val1'
1488
+ sleep 2
1489
+ store.fetch('key1').should be_nil
1490
+ end
1491
+
1492
+ it 'does not update the expiration time in load when not asked to do so' do
1493
+ store.store('key1', 'val1', :expires => 1)
1494
+ store.load('key1').should == 'val1'
1495
+ store.load('key1', :expires => nil).should == 'val1'
1496
+ sleep 2
1497
+ store.load('key1').should be_nil
1498
+ end}
1499
+
1500
+ SPECS['default_expires'] = %{it 'does set default expiration time' do
1501
+ store['key1'] = 'val1'
1502
+ store.key?('key1').should be_true
1503
+ store.fetch('key1').should == 'val1'
1504
+ store.load('key1').should == 'val1'
1505
+ sleep 2
1506
+ store.key?('key1').should be_false
1507
+ store.fetch('key1').should be_nil
1508
+ store.load('key1').should be_nil
1405
1509
  end}
1406
1510
 
1407
1511
  SPECS['not_increment'] = %{it 'does not support #increment' do
@@ -1637,7 +1741,7 @@ SPECS.each do |key, code|
1637
1741
  "shared_examples_for '#{key}' do\n " << [code].flatten.join("\n\n").gsub("\n", "\n ") << "\nend\n\n"
1638
1742
  end
1639
1743
  specs_code.gsub!(/\n +\n/, "\n\n")
1640
- File.open(File.join(File.dirname(__FILE__), 'monetaspecs.rb'), 'w') {|out| out << specs_code }
1744
+ File.open(File.join(PATH, 'monetaspecs.rb'), 'w') {|out| out << specs_code }
1641
1745
 
1642
1746
  TESTS.each do |name, options|
1643
1747
  build = options.delete(:build)
@@ -1680,5 +1784,5 @@ end
1680
1784
  }
1681
1785
 
1682
1786
  code.gsub!(/\n +\n/, "\n\n")
1683
- File.open(File.join(File.dirname(__FILE__), 'moneta', "#{name}_spec.rb"), 'w') {|out| out << code }
1787
+ File.open(File.join(PATH, 'moneta', "#{name}_spec.rb"), 'w') {|out| out << code }
1684
1788
  end