moneta 0.7.8 → 0.7.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (191) hide show
  1. data/.travis.yml +1 -0
  2. data/CHANGES +6 -0
  3. data/Gemfile +1 -0
  4. data/README.md +107 -40
  5. data/SPEC.md +8 -0
  6. data/lib/moneta.rb +6 -7
  7. data/lib/moneta/adapters/activerecord.rb +2 -0
  8. data/lib/moneta/adapters/client.rb +9 -0
  9. data/lib/moneta/adapters/datamapper.rb +2 -0
  10. data/lib/moneta/adapters/file.rb +2 -0
  11. data/lib/moneta/adapters/kyotocabinet.rb +39 -0
  12. data/lib/moneta/adapters/lruhash.rb +1 -1
  13. data/lib/moneta/adapters/memcached/dalli.rb +3 -5
  14. data/lib/moneta/adapters/memcached/native.rb +2 -0
  15. data/lib/moneta/adapters/mongo.rb +2 -0
  16. data/lib/moneta/adapters/pstore.rb +2 -0
  17. data/lib/moneta/adapters/redis.rb +3 -3
  18. data/lib/moneta/adapters/sequel.rb +2 -0
  19. data/lib/moneta/adapters/sqlite.rb +2 -0
  20. data/lib/moneta/adapters/tokyocabinet.rb +2 -3
  21. data/lib/moneta/adapters/yaml.rb +1 -1
  22. data/lib/moneta/cache.rb +5 -0
  23. data/lib/moneta/expires.rb +1 -0
  24. data/lib/moneta/mixins.rb +68 -1
  25. data/lib/moneta/proxy.rb +5 -0
  26. data/lib/moneta/server.rb +1 -1
  27. data/lib/moneta/stack.rb +16 -0
  28. data/lib/moneta/synchronize.rb +3 -1
  29. data/lib/moneta/version.rb +1 -1
  30. data/lib/moneta/weak.rb +15 -1
  31. data/lib/moneta/wrapper.rb +5 -0
  32. data/script/benchmarks +2 -0
  33. data/script/generate-specs +64 -37
  34. data/script/install-bundle +2 -1
  35. data/script/install-kyotocabinet +17 -0
  36. data/spec/moneta/adapter_activerecord_spec.rb +5 -0
  37. data/spec/moneta/adapter_cassandra_spec.rb +5 -0
  38. data/spec/moneta/adapter_cassandra_with_default_expires_spec.rb +5 -0
  39. data/spec/moneta/adapter_client_spec.rb +5 -0
  40. data/spec/moneta/adapter_cookie_spec.rb +5 -0
  41. data/spec/moneta/adapter_couch_spec.rb +5 -0
  42. data/spec/moneta/adapter_datamapper_spec.rb +5 -0
  43. data/spec/moneta/adapter_daybreak_spec.rb +5 -0
  44. data/spec/moneta/adapter_dbm_spec.rb +5 -0
  45. data/spec/moneta/adapter_file_spec.rb +5 -0
  46. data/spec/moneta/adapter_fog_spec.rb +5 -0
  47. data/spec/moneta/adapter_gdbm_spec.rb +5 -0
  48. data/spec/moneta/adapter_hbase_spec.rb +5 -0
  49. data/spec/moneta/adapter_kyotocabinet_spec.rb +29 -0
  50. data/spec/moneta/adapter_leveldb_spec.rb +5 -0
  51. data/spec/moneta/adapter_localmemcache_spec.rb +5 -0
  52. data/spec/moneta/adapter_lruhash_spec.rb +5 -0
  53. data/spec/moneta/adapter_memcached_dalli_spec.rb +5 -0
  54. data/spec/moneta/adapter_memcached_dalli_with_default_expires_spec.rb +5 -0
  55. data/spec/moneta/adapter_memcached_native_spec.rb +5 -0
  56. data/spec/moneta/adapter_memcached_native_with_default_expires_spec.rb +5 -0
  57. data/spec/moneta/adapter_memcached_spec.rb +5 -0
  58. data/spec/moneta/adapter_memcached_with_default_expires_spec.rb +5 -0
  59. data/spec/moneta/adapter_memory_spec.rb +5 -0
  60. data/spec/moneta/adapter_mongo_spec.rb +5 -0
  61. data/spec/moneta/adapter_mongo_with_default_expires_spec.rb +5 -0
  62. data/spec/moneta/adapter_pstore_spec.rb +5 -0
  63. data/spec/moneta/adapter_redis_spec.rb +5 -0
  64. data/spec/moneta/adapter_redis_with_default_expires_spec.rb +5 -0
  65. data/spec/moneta/adapter_restclient_spec.rb +5 -0
  66. data/spec/moneta/adapter_riak_spec.rb +5 -0
  67. data/spec/moneta/adapter_sdbm_spec.rb +5 -0
  68. data/spec/moneta/adapter_sequel_spec.rb +5 -0
  69. data/spec/moneta/adapter_sqlite_spec.rb +5 -0
  70. data/spec/moneta/adapter_tdb_spec.rb +5 -0
  71. data/spec/moneta/adapter_tokyocabinet_bdb_spec.rb +5 -0
  72. data/spec/moneta/adapter_tokyocabinet_hdb_spec.rb +5 -0
  73. data/spec/moneta/adapter_yaml_spec.rb +5 -0
  74. data/spec/moneta/cache_file_memory_spec.rb +5 -0
  75. data/spec/moneta/cache_memory_null_spec.rb +5 -0
  76. data/spec/moneta/expires_file_spec.rb +5 -0
  77. data/spec/moneta/expires_memory_spec.rb +5 -0
  78. data/spec/moneta/expires_memory_with_default_expires_spec.rb +5 -0
  79. data/spec/moneta/lock_spec.rb +5 -0
  80. data/spec/moneta/mutex_spec.rb +4 -0
  81. data/spec/moneta/null_adapter_spec.rb +4 -0
  82. data/spec/moneta/optionmerger_spec.rb +8 -0
  83. data/spec/moneta/pool_spec.rb +5 -0
  84. data/spec/moneta/proxy_expires_memory_spec.rb +5 -0
  85. data/spec/moneta/proxy_redis_spec.rb +5 -0
  86. data/spec/moneta/semaphore_spec.rb +4 -0
  87. data/spec/moneta/shared_tcp_spec.rb +5 -0
  88. data/spec/moneta/shared_unix_spec.rb +5 -0
  89. data/spec/moneta/simple_activerecord_spec.rb +5 -0
  90. data/spec/moneta/simple_activerecord_with_expires_spec.rb +5 -0
  91. data/spec/moneta/simple_cassandra_spec.rb +5 -0
  92. data/spec/moneta/simple_client_tcp_spec.rb +5 -0
  93. data/spec/moneta/simple_client_unix_spec.rb +5 -0
  94. data/spec/moneta/simple_couch_spec.rb +5 -0
  95. data/spec/moneta/simple_couch_with_expires_spec.rb +5 -0
  96. data/spec/moneta/simple_datamapper_spec.rb +5 -0
  97. data/spec/moneta/simple_datamapper_with_expires_spec.rb +5 -0
  98. data/spec/moneta/simple_datamapper_with_repository_spec.rb +5 -0
  99. data/spec/moneta/simple_daybreak_spec.rb +5 -0
  100. data/spec/moneta/simple_daybreak_with_expires_spec.rb +5 -0
  101. data/spec/moneta/simple_dbm_spec.rb +5 -0
  102. data/spec/moneta/simple_dbm_with_expires_spec.rb +5 -0
  103. data/spec/moneta/simple_file_spec.rb +5 -0
  104. data/spec/moneta/simple_file_with_expires_spec.rb +5 -0
  105. data/spec/moneta/simple_fog_spec.rb +5 -0
  106. data/spec/moneta/simple_fog_with_expires_spec.rb +5 -0
  107. data/spec/moneta/simple_gdbm_spec.rb +5 -0
  108. data/spec/moneta/simple_gdbm_with_expires_spec.rb +5 -0
  109. data/spec/moneta/simple_hashfile_spec.rb +5 -0
  110. data/spec/moneta/simple_hashfile_with_expires_spec.rb +5 -0
  111. data/spec/moneta/simple_hbase_spec.rb +5 -0
  112. data/spec/moneta/simple_hbase_with_expires_spec.rb +5 -0
  113. data/spec/moneta/simple_kyotocabinet_spec.rb +154 -0
  114. data/spec/moneta/simple_kyotocabinet_with_expires_spec.rb +156 -0
  115. data/spec/moneta/simple_leveldb_spec.rb +5 -0
  116. data/spec/moneta/simple_leveldb_with_expires_spec.rb +5 -0
  117. data/spec/moneta/simple_localmemcache_spec.rb +5 -0
  118. data/spec/moneta/simple_localmemcache_with_expires_spec.rb +5 -0
  119. data/spec/moneta/simple_lruhash_spec.rb +5 -0
  120. data/spec/moneta/simple_lruhash_with_expires_spec.rb +5 -0
  121. data/spec/moneta/simple_memcached_dalli_spec.rb +5 -0
  122. data/spec/moneta/simple_memcached_native_spec.rb +5 -0
  123. data/spec/moneta/simple_memcached_spec.rb +5 -0
  124. data/spec/moneta/simple_memory_spec.rb +5 -0
  125. data/spec/moneta/simple_memory_with_compress_spec.rb +5 -0
  126. data/spec/moneta/simple_memory_with_expires_spec.rb +5 -0
  127. data/spec/moneta/simple_memory_with_json_key_serializer_spec.rb +5 -0
  128. data/spec/moneta/simple_memory_with_json_serializer_spec.rb +5 -0
  129. data/spec/moneta/simple_memory_with_json_value_serializer_spec.rb +5 -0
  130. data/spec/moneta/simple_memory_with_prefix_spec.rb +5 -0
  131. data/spec/moneta/simple_memory_with_snappy_compress_spec.rb +5 -0
  132. data/spec/moneta/simple_mongo_spec.rb +5 -0
  133. data/spec/moneta/simple_null_spec.rb +5 -0
  134. data/spec/moneta/simple_pstore_spec.rb +5 -0
  135. data/spec/moneta/simple_pstore_with_expires_spec.rb +5 -0
  136. data/spec/moneta/simple_redis_spec.rb +5 -0
  137. data/spec/moneta/simple_restclient_spec.rb +5 -0
  138. data/spec/moneta/simple_riak_spec.rb +5 -0
  139. data/spec/moneta/simple_riak_with_expires_spec.rb +5 -0
  140. data/spec/moneta/simple_sdbm_spec.rb +5 -0
  141. data/spec/moneta/simple_sdbm_with_expires_spec.rb +5 -0
  142. data/spec/moneta/simple_sequel_spec.rb +5 -0
  143. data/spec/moneta/simple_sequel_with_expires_spec.rb +5 -0
  144. data/spec/moneta/simple_sqlite_spec.rb +5 -0
  145. data/spec/moneta/simple_sqlite_with_expires_spec.rb +5 -0
  146. data/spec/moneta/simple_tdb_spec.rb +5 -0
  147. data/spec/moneta/simple_tdb_with_expires_spec.rb +5 -0
  148. data/spec/moneta/simple_tokyocabinet_spec.rb +5 -0
  149. data/spec/moneta/simple_tokyocabinet_with_expires_spec.rb +5 -0
  150. data/spec/moneta/simple_yaml_spec.rb +5 -0
  151. data/spec/moneta/simple_yaml_with_expires_spec.rb +5 -0
  152. data/spec/moneta/stack_file_memory_spec.rb +5 -0
  153. data/spec/moneta/stack_memory_file_spec.rb +7 -4
  154. data/spec/moneta/transformer_bencode_spec.rb +5 -0
  155. data/spec/moneta/transformer_bert_spec.rb +5 -0
  156. data/spec/moneta/transformer_bson_spec.rb +5 -0
  157. data/spec/moneta/transformer_bzip2_spec.rb +5 -0
  158. data/spec/moneta/transformer_json_spec.rb +5 -0
  159. data/spec/moneta/transformer_key_inspect_spec.rb +5 -0
  160. data/spec/moneta/transformer_key_marshal_spec.rb +5 -0
  161. data/spec/moneta/transformer_key_to_s_spec.rb +5 -0
  162. data/spec/moneta/transformer_key_yaml_spec.rb +5 -0
  163. data/spec/moneta/transformer_lzma_spec.rb +5 -0
  164. data/spec/moneta/transformer_lzo_spec.rb +5 -0
  165. data/spec/moneta/transformer_marshal_base64_spec.rb +5 -0
  166. data/spec/moneta/transformer_marshal_escape_spec.rb +5 -0
  167. data/spec/moneta/transformer_marshal_hmac_spec.rb +5 -0
  168. data/spec/moneta/transformer_marshal_md5_spec.rb +5 -0
  169. data/spec/moneta/transformer_marshal_md5_spread_spec.rb +5 -0
  170. data/spec/moneta/transformer_marshal_prefix_spec.rb +5 -0
  171. data/spec/moneta/transformer_marshal_rmd160_spec.rb +5 -0
  172. data/spec/moneta/transformer_marshal_sha1_spec.rb +5 -0
  173. data/spec/moneta/transformer_marshal_sha256_spec.rb +5 -0
  174. data/spec/moneta/transformer_marshal_sha384_spec.rb +5 -0
  175. data/spec/moneta/transformer_marshal_sha512_spec.rb +5 -0
  176. data/spec/moneta/transformer_marshal_spec.rb +5 -0
  177. data/spec/moneta/transformer_marshal_truncate_spec.rb +5 -0
  178. data/spec/moneta/transformer_marshal_uuencode_spec.rb +5 -0
  179. data/spec/moneta/transformer_msgpack_spec.rb +5 -0
  180. data/spec/moneta/transformer_ox_spec.rb +5 -0
  181. data/spec/moneta/transformer_quicklz_spec.rb +5 -0
  182. data/spec/moneta/transformer_snappy_spec.rb +5 -0
  183. data/spec/moneta/transformer_tnet_spec.rb +5 -0
  184. data/spec/moneta/transformer_value_marshal_spec.rb +5 -0
  185. data/spec/moneta/transformer_value_yaml_spec.rb +5 -0
  186. data/spec/moneta/transformer_yaml_spec.rb +5 -0
  187. data/spec/moneta/transformer_zlib_spec.rb +5 -0
  188. data/spec/moneta/weak_create_spec.rb +10 -91
  189. data/spec/moneta/weak_increment_spec.rb +10 -91
  190. data/spec/monetaspecs.rb +19 -0
  191. metadata +10 -2
@@ -8,6 +8,8 @@ module Moneta
8
8
  include Defaults
9
9
  include ExpiresSupport
10
10
 
11
+ supports :create, :increment
12
+
11
13
  # @param [Hash] options
12
14
  # @option options [String] :server ('127.0.0.1:11211') Memcached server
13
15
  # @option options [String] :namespace Key namespace
@@ -12,6 +12,8 @@ module Moneta
12
12
  include Defaults
13
13
  include ExpiresSupport
14
14
 
15
+ supports :create, :increment
16
+
15
17
  # @param [Hash] options
16
18
  # @option options [String] :collection ('moneta') MongoDB collection name
17
19
  # @option options [String] :host ('127.0.0.1') MongoDB server host
@@ -7,6 +7,8 @@ module Moneta
7
7
  class PStore
8
8
  include Defaults
9
9
 
10
+ supports :create, :increment
11
+
10
12
  # @param [Hash] options
11
13
  # @option options [String] :file PStore file
12
14
  def initialize(options = {})
@@ -8,6 +8,8 @@ module Moneta
8
8
  include Defaults
9
9
  include ExpiresSupport
10
10
 
11
+ supports :create, :increment
12
+
11
13
  # @param [Hash] options
12
14
  # @option options [Integer] :expires Default expiration time
13
15
  # @option options Other options passed to `Redis#new`
@@ -56,9 +58,7 @@ module Moneta
56
58
 
57
59
  # (see Proxy#increment)
58
60
  def increment(key, amount = 1, options = {})
59
- value = @redis.incrby(key, amount)
60
- update_expires(key, options)
61
- value
61
+ @redis.incrby(key, amount)
62
62
  end
63
63
 
64
64
  # (see Proxy#clear)
@@ -7,6 +7,8 @@ module Moneta
7
7
  class Sequel
8
8
  include Defaults
9
9
 
10
+ supports :create, :increment
11
+
10
12
  # @param [Hash] options
11
13
  # @option options [String] :db Sequel database
12
14
  # @option options [String/Symbol] :table (:moneta) Table name
@@ -8,6 +8,8 @@ module Moneta
8
8
  include Defaults
9
9
  include IncrementSupport
10
10
 
11
+ supports :create
12
+
11
13
  # @param [Hash] options
12
14
  # @option options [String] :file Database file
13
15
  # @option options [String] :table ('moneta') Table name
@@ -9,14 +9,13 @@ module Moneta
9
9
  # @option options [String] :file Database file
10
10
  # @option options [Symbol] :type (:hdb) Database type (:bdb and :hdb possible)
11
11
  def initialize(options = {})
12
- file = options[:file]
13
12
  raise ArgumentError, 'Option :file is required' unless options[:file]
14
13
  if options[:type] == :bdb
15
14
  @hash = ::TokyoCabinet::BDB.new
16
- @hash.open(file, ::TokyoCabinet::BDB::OWRITER | ::TokyoCabinet::BDB::OCREAT)
15
+ @hash.open(options[:file], ::TokyoCabinet::BDB::OWRITER | ::TokyoCabinet::BDB::OCREAT)
17
16
  else
18
17
  @hash = ::TokyoCabinet::HDB.new
19
- @hash.open(file, ::TokyoCabinet::HDB::OWRITER | ::TokyoCabinet::HDB::OCREAT)
18
+ @hash.open(options[:file], ::TokyoCabinet::HDB::OWRITER | ::TokyoCabinet::HDB::OCREAT)
20
19
  end or raise @hash.errmsg(@hash.ecode)
21
20
  end
22
21
 
@@ -4,7 +4,7 @@ module Moneta
4
4
  module Adapters
5
5
  # YAML::Store backend
6
6
  # @api public
7
- class YAML < Moneta::Adapters::PStore
7
+ class YAML < PStore
8
8
  protected
9
9
 
10
10
  def new_store(options)
data/lib/moneta/cache.rb CHANGED
@@ -101,5 +101,10 @@ module Moneta
101
101
  @cache.close
102
102
  @backend.close
103
103
  end
104
+
105
+ # (see Proxy#features)
106
+ def features
107
+ @features ||= ((@cache.features + [:create, :increment]) & @backend.features).freeze
108
+ end
104
109
  end
105
110
  end
@@ -12,6 +12,7 @@ module Moneta
12
12
  # @param [Hash] options
13
13
  # @option options [String] :expires Default expiration time
14
14
  def initialize(adapter, options = {})
15
+ raise 'Store already supports feature :expires' if adapter.supports?(:expires)
15
16
  super
16
17
  self.default_expires = options[:expires]
17
18
  end
data/lib/moneta/mixins.rb CHANGED
@@ -45,7 +45,7 @@ module Moneta
45
45
  # @return [OptionMerger]
46
46
  # @api public
47
47
  def expires(expires)
48
- with(:expires => expires, :only => [:store, :create, :increment])
48
+ with(:expires => expires, :only => [:store, :create])
49
49
  end
50
50
  end
51
51
 
@@ -54,6 +54,34 @@ module Moneta
54
54
  module Defaults
55
55
  include OptionSupport
56
56
 
57
+ # @api private
58
+ module ClassMethods
59
+ # Returns features list
60
+ #
61
+ # @return [Array<Symbol>] list of features
62
+ def features
63
+ @features ||= superclass.respond_to?(:features) ? superclass.features : [].freeze
64
+ end
65
+
66
+ # Declares that this adapter supports the given feature.
67
+ #
68
+ # @example
69
+ # class MyAdapter
70
+ # include Moneta::Defaults
71
+ # supports :create
72
+ # def create(key, value, options = {})
73
+ # # implement create!
74
+ # end
75
+ # end
76
+ def supports(*features)
77
+ @features = (self.features + features).uniq.freeze
78
+ end
79
+ end
80
+
81
+ def self.included(base)
82
+ base.extend(ClassMethods)
83
+ end
84
+
57
85
  # Exists the value with key
58
86
  #
59
87
  # @param [Object] key
@@ -76,6 +104,8 @@ module Moneta
76
104
  # @param [Object] key
77
105
  # @param [Integer] amount
78
106
  # @param [Hash] options
107
+ # @option options [String] :prefix Prefix key (See {Transformer})
108
+ # @option options Other options as defined by the adapters or middleware
79
109
  # @return [Object] value from store
80
110
  # @api public
81
111
  def increment(key, amount = 1, options = {})
@@ -91,6 +121,8 @@ module Moneta
91
121
  # @param [Object] key
92
122
  # @param [Integer] amount
93
123
  # @param [Hash] options
124
+ # @option options [String] :prefix Prefix key (See {Transformer})
125
+ # @option options Other options as defined by the adapters or middleware
94
126
  # @return [Object] value from store
95
127
  # @api public
96
128
  def decrement(key, amount = 1, options = {})
@@ -110,6 +142,9 @@ module Moneta
110
142
  # block and return its return value.
111
143
  # @param [Object] key
112
144
  # @param [Hash] options
145
+ # @option options [Integer] :expires Update expiration time (See {Expires})
146
+ # @option options [Boolean] :raw Raw access without value transformation (See {Transformer})
147
+ # @option options [String] :prefix Prefix key (See {Transformer})
113
148
  # @return [Object] value from store
114
149
  #
115
150
  # @overload fetch(key, default, options = {})
@@ -117,6 +152,9 @@ module Moneta
117
152
  # @param [Object] key
118
153
  # @param [Object] default Default value
119
154
  # @param [Hash] options
155
+ # @option options [Integer] :expires Update expiration time (See {Expires})
156
+ # @option options [Boolean] :raw Raw access without value transformation (See {Transformer})
157
+ # @option options [String] :prefix Prefix key (See {Transformer})
120
158
  # @return [Object] value from store
121
159
  #
122
160
  # @api public
@@ -157,11 +195,28 @@ module Moneta
157
195
  # @param [Object] key
158
196
  # @param [Object] value
159
197
  # @param [Hash] options
198
+ # @option options [Integer] :expires Update expiration time (See {Expires})
199
+ # @option options [Boolean] :raw Raw access without value transformation (See {Transformer})
200
+ # @option options [String] :prefix Prefix key (See {Transformer})
160
201
  # @return [Boolean] key was set
161
202
  # @api public
162
203
  def create(key, value, options = {})
163
204
  raise NotImplementedError, 'create is not supported'
164
205
  end
206
+
207
+ # Returns features list
208
+ #
209
+ # @return [Array<Symbol>] list of features
210
+ def features
211
+ self.class.features
212
+ end
213
+
214
+ # Return true if adapter supports the given feature.
215
+ #
216
+ # @return [Boolean]
217
+ def supports?(feature)
218
+ features.include?(feature)
219
+ end
165
220
  end
166
221
 
167
222
  # @api private
@@ -173,6 +228,10 @@ module Moneta
173
228
  store(key, value.to_s, options)
174
229
  value
175
230
  end
231
+
232
+ def self.included(base)
233
+ base.supports(:increment) if base.respond_to?(:supports)
234
+ end
176
235
  end
177
236
 
178
237
  # Implements simple create using key? and store.
@@ -190,6 +249,10 @@ module Moneta
190
249
  true
191
250
  end
192
251
  end
252
+
253
+ def self.included(base)
254
+ base.supports(:create) if base.respond_to?(:supports)
255
+ end
193
256
  end
194
257
 
195
258
  # @api private
@@ -293,5 +356,9 @@ module Moneta
293
356
  raise ArgumentError, ":expires must be Numeric or false, got #{value.inspect}"
294
357
  end
295
358
  end
359
+
360
+ def self.included(base)
361
+ base.supports(:expires) if base.respond_to?(:supports)
362
+ end
296
363
  end
297
364
  end
data/lib/moneta/proxy.rb CHANGED
@@ -83,5 +83,10 @@ module Moneta
83
83
  adapter.clear(options)
84
84
  self
85
85
  end
86
+
87
+ # (see Default#features)
88
+ def features
89
+ @features ||= (self.class.features + adapter.features).uniq.freeze
90
+ end
86
91
  end
87
92
  end
data/lib/moneta/server.rb CHANGED
@@ -92,7 +92,7 @@ module Moneta
92
92
  def handle(client)
93
93
  method, *args = read(client)
94
94
  case method
95
- when :key?, :load, :delete, :increment, :create
95
+ when :key?, :load, :delete, :increment, :create, :features
96
96
  write(client, @store.send(method, *args))
97
97
  when :store, :clear
98
98
  @store.send(method, *args)
data/lib/moneta/stack.rb CHANGED
@@ -67,6 +67,13 @@ module Moneta
67
67
  last
68
68
  end
69
69
 
70
+ # (see Proxy#create)
71
+ def create(key, value, options = {})
72
+ last = false
73
+ @stack.each {|s| last = s.create(key, value, options) }
74
+ last
75
+ end
76
+
70
77
  # (see Proxy#delete)
71
78
  def delete(key, options = {})
72
79
  @stack.inject(nil) do |value, s|
@@ -86,5 +93,14 @@ module Moneta
86
93
  @stack.each {|s| s.close }
87
94
  nil
88
95
  end
96
+
97
+ # (see Proxy#features)
98
+ def features
99
+ @features ||=
100
+ begin
101
+ features = @stack.map(&:features)
102
+ features.inject(features.first, &:&).freeze
103
+ end
104
+ end
89
105
  end
90
106
  end
@@ -74,6 +74,7 @@ module Moneta
74
74
  # @param [Moneta store] store The store we want to lock
75
75
  # @param [Object] lock Key of the lock entry
76
76
  def initialize(store, lock)
77
+ raise 'Store must support feature :create' unless store.supports?(:create)
77
78
  @store, @lock = store, lock
78
79
  end
79
80
 
@@ -94,7 +95,7 @@ module Moneta
94
95
  # semaphore = Moneta::Semaphore.new(store, 'semaphore', 2)
95
96
  # semaphore.synchronize do
96
97
  # # Synchronized access
97
- # ...
98
+ # # ...
98
99
  # end
99
100
  #
100
101
  # @api public
@@ -103,6 +104,7 @@ module Moneta
103
104
  # @param [Object] counter Key of the counter entry
104
105
  # @param [Fixnum] max Maximum number of threads which are allowed to enter the critical section
105
106
  def initialize(store, counter, max = 1)
107
+ raise 'Store must support feature :increment' unless store.supports?(:increment)
106
108
  @store, @counter, @max = store, counter, max
107
109
  @store.increment(@counter, 0, :expires => false) # Ensure that counter exists
108
110
  end
@@ -1,5 +1,5 @@
1
1
  module Moneta
2
2
  # Moneta version number
3
3
  # @api public
4
- VERSION = '0.7.8'
4
+ VERSION = '0.7.9'
5
5
  end
data/lib/moneta/weak.rb CHANGED
@@ -1,10 +1,17 @@
1
1
  module Moneta
2
2
  # Adds weak create support to the underlying store
3
3
  #
4
- # @note The increment method will not be thread or multi-process safe (this is meant by weak)
4
+ # @note The create method will not be thread or multi-process safe (this is meant by weak)
5
5
  # @api public
6
6
  class WeakCreate < Proxy
7
7
  include CreateSupport
8
+
9
+ # @param [Moneta store] adapter The underlying store
10
+ # @param [Hash] options
11
+ def initialize(adapter, options = {})
12
+ raise 'Store already supports feature :create' if adapter.supports?(:create)
13
+ super
14
+ end
8
15
  end
9
16
 
10
17
  # Adds weak increment support to the underlying store
@@ -13,5 +20,12 @@ module Moneta
13
20
  # @api public
14
21
  class WeakIncrement < Proxy
15
22
  include IncrementSupport
23
+
24
+ # @param [Moneta store] adapter The underlying store
25
+ # @param [Hash] options
26
+ def initialize(adapter, options = {})
27
+ raise 'Store already supports feature :increment' if adapter.supports?(:increment)
28
+ super
29
+ end
16
30
  end
17
31
  end
@@ -41,5 +41,10 @@ module Moneta
41
41
  def close
42
42
  wrap(:close) { super }
43
43
  end
44
+
45
+ # (see Proxy#features)
46
+ def features
47
+ wrap(:features) { super }
48
+ end
44
49
  end
45
50
  end
data/script/benchmarks CHANGED
@@ -46,6 +46,7 @@ class MonetaBenchmarks
46
46
  :GDBM => { :file => "#{DIR}/gdbm" },
47
47
  :HBase => {},
48
48
  :HashFile => { :dir => "#{DIR}/hashfile" },
49
+ :KyotoCabinet => { :file => 'kyotocabinet.kch' },
49
50
  :LRUHash => {},
50
51
  :LevelDB => { :dir => "#{DIR}/leveldb" },
51
52
  :LocalMemCache => { :file => "#{DIR}/lmc" },
@@ -60,6 +61,7 @@ class MonetaBenchmarks
60
61
  :Sequel => { :db => 'sqlite:/' },
61
62
  :Sqlite => { :file => ':memory:' },
62
63
  :TDB => { :file => "#{DIR}/tdb" },
64
+ :TokyoCabinet => { :file => 'tokyocabinet' },
63
65
  }
64
66
 
65
67
  CONFIGS = {
@@ -2,27 +2,19 @@
2
2
 
3
3
  PATH = File.expand_path(File.join(__FILE__, '..', '..', 'spec'))
4
4
 
5
- class Array
6
- def without(*x)
7
- a = dup
8
- x.each {|y| a.delete(y) }
9
- a
10
- end
11
-
12
- def with(*x)
13
- a = dup
14
- x.each {|y| a << y }
15
- a
16
- end
17
- end
18
-
19
5
  class Specs
20
- attr_reader :key, :value, :specs
6
+ attr_reader :key, :value, :specs, :features
21
7
 
22
8
  def initialize(options = {})
23
9
  @specs = options.delete(:specs).to_a
24
10
  @key = options.delete(:key) || %w(object string hash boolean nil integer)
25
11
  @value = options.delete(:value) || %w(object string hash boolean nil integer)
12
+ @features = []
13
+ [:expires, :expires_native, :increment, :create].each do |feature|
14
+ @features << feature if @specs.include?(feature)
15
+ end
16
+ @features.sort_by!(&:to_s)
17
+ @features.uniq!
26
18
  end
27
19
 
28
20
  def new(options)
@@ -46,15 +38,15 @@ class Specs
46
38
  end
47
39
 
48
40
  def without_increment
49
- new(:specs => specs.without(:increment).with(:not_increment))
41
+ new(:specs => specs - [:increment] + [:not_increment])
50
42
  end
51
43
 
52
44
  def without_persist
53
- new(:specs => specs.without(:persist).without(:multiprocess).with(:not_persist))
45
+ new(:specs => specs - [:persist, :multiprocess] + [:not_persist])
54
46
  end
55
47
 
56
48
  def without_multiprocess
57
- new(:specs => specs.without(:multiprocess))
49
+ new(:specs => specs - [:multiprocess])
58
50
  end
59
51
 
60
52
  def with_expires
@@ -71,45 +63,45 @@ class Specs
71
63
  def with_native_expires
72
64
  a = specs.dup
73
65
  a << :create_expires if a.include?(:create)
74
- new(:specs => a.with(:expires))
66
+ new(:specs => a + [:expires])
75
67
  end
76
68
 
77
69
  def without_marshallable
78
- new(:specs => specs.without(:marshallable_value, :marshallable_key))
70
+ new(:specs => specs - [:marshallable_value, :marshallable_key])
79
71
  end
80
72
 
81
73
  def without_transform
82
- new(:specs => specs.without(:marshallable_value, :marshallable_key, :transform_value))
74
+ new(:specs => specs - [:marshallable_value, :marshallable_key, :transform_value])
83
75
  end
84
76
 
85
77
  def returnsame
86
- new(:specs => specs.without(:returndifferent).with(:returnsame))
78
+ new(:specs => specs - [:returndifferent] + [:returnsame])
87
79
  end
88
80
 
89
81
  def without_marshallable_key
90
- new(:specs => specs.without(:marshallable_key))
82
+ new(:specs => specs - [:marshallable_key])
91
83
  end
92
84
 
93
85
  def without_marshallable_value
94
- new(:specs => specs.without(:marshallable_value))
86
+ new(:specs => specs - [:marshallable_value])
95
87
  end
96
88
 
97
89
  def without_store
98
- new(:specs => specs.without(:store, :transform_value, :marshallable_value))
90
+ new(:specs => specs - [:store, :transform_value, :marshallable_value])
99
91
  end
100
92
 
101
93
  def with_default_expires
102
- new(:specs => specs.with(:default_expires))
94
+ new(:specs => specs + [:default_expires])
103
95
  end
104
96
 
105
97
  def without_create
106
- new(:specs => specs.without(:create, :create_expires).with(:not_create))
98
+ new(:specs => specs - [:create, :create_expires] + [:not_create])
107
99
  end
108
100
  end
109
101
 
110
- ADAPTER_SPECS = Specs.new(:specs => [:null, :store, :returndifferent, :increment, :persist, :multiprocess, :create], :key => %w(string), :value => %w(string))
111
- STANDARD_SPECS = Specs.new(:specs => [:null, :store, :returndifferent, :marshallable_key, :marshallable_value, :transform_value, :increment, :persist, :multiprocess, :create])
112
- TRANSFORMER_SPECS = Specs.new(:specs => [:null, :store, :returndifferent, :transform_value, :increment, :create])
102
+ ADAPTER_SPECS = Specs.new(:specs => [:null, :store, :returndifferent, :increment, :persist, :multiprocess, :create, :features], :key => %w(string), :value => %w(string))
103
+ STANDARD_SPECS = Specs.new(:specs => [:null, :store, :returndifferent, :marshallable_key, :marshallable_value, :transform_value, :increment, :persist, :multiprocess, :create, :features])
104
+ TRANSFORMER_SPECS = Specs.new(:specs => [:null, :store, :returndifferent, :transform_value, :increment, :create, :features])
113
105
 
114
106
  header = "# Generated by #{File.basename(__FILE__)}\n"
115
107
 
@@ -338,6 +330,16 @@ end
338
330
  :options => ':file => File.join(make_tempdir, "simple_tokyocabinet_with_expires"), :expires => true',
339
331
  :specs => STANDARD_SPECS.without_multiprocess.with_expires
340
332
  },
333
+ 'simple_kyotocabinet' => {
334
+ :store => :KyotoCabinet,
335
+ :options => ':file => File.join(make_tempdir, "simple_kyotocabinet.kch")',
336
+ :specs => STANDARD_SPECS.without_multiprocess
337
+ },
338
+ 'simple_kyotocabinet_with_expires' => {
339
+ :store => :KyotoCabinet,
340
+ :options => ':file => File.join(make_tempdir, "simple_kyotocabinet_with_expires.kch"), :expires => true',
341
+ :specs => STANDARD_SPECS.without_multiprocess.with_expires
342
+ },
341
343
  'simple_sqlite' => {
342
344
  :store => :Sqlite,
343
345
  :options => ':file => File.join(make_tempdir, "simple_sqlite")',
@@ -478,16 +480,16 @@ end
478
480
  'weak_create' => {
479
481
  :build => %{Moneta.build do
480
482
  use :WeakCreate
481
- adapter :Memory
483
+ adapter :Couch, :db => 'weak_create'
482
484
  end},
483
- :specs => STANDARD_SPECS.without_transform.without_persist.returnsame
485
+ :specs => ADAPTER_SPECS.without_increment
484
486
  },
485
487
  'weak_increment' => {
486
488
  :build => %{Moneta.build do
487
489
  use :WeakIncrement
488
- adapter :Memory
490
+ adapter :Couch, :db => 'weak_increment'
489
491
  end},
490
- :specs => STANDARD_SPECS.without_transform.without_persist.returnsame
492
+ :specs => ADAPTER_SPECS.without_create
491
493
  },
492
494
  'expires_memory' => {
493
495
  :build => %{Moneta.build do
@@ -618,13 +620,11 @@ end},
618
620
  'stack_memory_file' => {
619
621
  :build => %{Moneta.build do
620
622
  use(:Stack) do
621
- add(Moneta.new(:Null))
622
- add(Moneta::Adapters::Null.new)
623
623
  add { adapter :Memory }
624
624
  add { adapter :File, :dir => File.join(make_tempdir, "stack_memory_file") }
625
625
  end
626
626
  end},
627
- :specs => STANDARD_SPECS.without_increment.without_create.returnsame.without_transform.stringkeys_only.stringvalues_only
627
+ :specs => ADAPTER_SPECS.returnsame
628
628
  },
629
629
  'lock' => {
630
630
  :build => %{Moneta.build do
@@ -1289,6 +1289,10 @@ end}
1289
1289
  :build => 'Moneta::Adapters::Sqlite.new(:file => File.join(make_tempdir, "adapter_sqlite"))',
1290
1290
  :specs => ADAPTER_SPECS
1291
1291
  },
1292
+ 'adapter_kyotocabinet' => {
1293
+ :build => 'Moneta::Adapters::KyotoCabinet.new(:file => File.join(make_tempdir, "adapter_kyotocabinet.kch"))',
1294
+ :specs => ADAPTER_SPECS.without_multiprocess
1295
+ },
1292
1296
  'adapter_tokyocabinet_bdb' => {
1293
1297
  :build => 'Moneta::Adapters::TokyoCabinet.new(:file => File.join(make_tempdir, "adapter_tokyocabinet_bdb"), :type => :bdb)',
1294
1298
  :specs => ADAPTER_SPECS.without_multiprocess
@@ -1496,6 +1500,10 @@ it 'has method #raw' do
1496
1500
  store.raw.should equal(store.raw.raw)
1497
1501
  end
1498
1502
 
1503
+ it 'has method #expires' do
1504
+ store.expires(10).default_options.should == {:store=>{:expires=>10},:create=>{:expires=>10}}
1505
+ end
1506
+
1499
1507
  it 'has method #prefix' do
1500
1508
  store.prefix('a').default_options.should == {:store=>{:prefix=>'a'},:load=>{:prefix=>'a'},:create=>{:prefix=>'a'},
1501
1509
  :delete=>{:prefix=>'a'},:key? => {:prefix=>'a'},:increment=>{:prefix=>'a'}}
@@ -2166,6 +2174,21 @@ it 'might raise exception on invalid value' do
2166
2174
  end
2167
2175
  end}
2168
2176
 
2177
+ SPECS['features'] = %{it 'should report correct features' do
2178
+ store.features.sort_by(&:to_s).should == features
2179
+ end
2180
+
2181
+ it 'should have frozen features' do
2182
+ store.features.frozen?.should be_true
2183
+ end
2184
+
2185
+ it 'should have #supports?' do
2186
+ features.each do |f|
2187
+ store.supports?(f).should be_true
2188
+ end
2189
+ store.supports?(:unknown).should be_false
2190
+ end}
2191
+
2169
2192
  specs_code = "#{header}\n"
2170
2193
  SPECS.each do |key, code|
2171
2194
  specs_code << "#################### #{key} ####################\n\n" <<
@@ -2205,6 +2228,10 @@ describe_moneta #{name.inspect} do
2205
2228
  @log ||= File.open(File.join(make_tempdir, '#{name}.log'), 'a')
2206
2229
  end
2207
2230
 
2231
+ def features
2232
+ #{specs.features.to_a.inspect}
2233
+ end
2234
+
2208
2235
  #{preamble}def new_store
2209
2236
  #{build.gsub("\n", "\n ")}
2210
2237
  end