moneta 0.7.3 → 0.7.4

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