moneta 0.7.8 → 0.7.9

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