moneta 0.7.6 → 0.7.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (200) hide show
  1. data/CHANGES +15 -0
  2. data/README.md +160 -50
  3. data/Rakefile +11 -2
  4. data/SPEC.md +7 -2
  5. data/lib/moneta.rb +7 -1
  6. data/lib/moneta/adapters/activerecord.rb +27 -3
  7. data/lib/moneta/adapters/cassandra.rb +1 -1
  8. data/lib/moneta/adapters/client.rb +8 -2
  9. data/lib/moneta/adapters/cookie.rb +1 -1
  10. data/lib/moneta/adapters/couch.rb +2 -1
  11. data/lib/moneta/adapters/datamapper.rb +16 -0
  12. data/lib/moneta/adapters/daybreak.rb +19 -1
  13. data/lib/moneta/adapters/file.rb +12 -0
  14. data/lib/moneta/adapters/hbase.rb +1 -2
  15. data/lib/moneta/adapters/lruhash.rb +4 -1
  16. data/lib/moneta/adapters/memcached.rb +7 -3
  17. data/lib/moneta/adapters/memcached/dalli.rb +8 -2
  18. data/lib/moneta/adapters/memcached/native.rb +10 -3
  19. data/lib/moneta/adapters/memory.rb +1 -0
  20. data/lib/moneta/adapters/mongo.rb +32 -5
  21. data/lib/moneta/adapters/pstore.rb +13 -2
  22. data/lib/moneta/adapters/redis.rb +19 -0
  23. data/lib/moneta/adapters/restclient.rb +1 -1
  24. data/lib/moneta/adapters/sequel.rb +20 -6
  25. data/lib/moneta/adapters/sqlite.rb +13 -1
  26. data/lib/moneta/adapters/tokyocabinet.rb +5 -0
  27. data/lib/moneta/cache.rb +10 -0
  28. data/lib/moneta/expires.rb +19 -22
  29. data/lib/moneta/lock.rb +2 -2
  30. data/lib/moneta/mixins.rb +33 -11
  31. data/lib/moneta/optionmerger.rb +1 -1
  32. data/lib/moneta/proxy.rb +13 -8
  33. data/lib/moneta/server.rb +13 -6
  34. data/lib/moneta/shared.rb +6 -10
  35. data/lib/moneta/synchronize.rb +125 -0
  36. data/lib/moneta/transformer.rb +50 -42
  37. data/lib/moneta/transformer/config.rb +34 -32
  38. data/lib/moneta/utils.rb +20 -0
  39. data/lib/moneta/version.rb +1 -1
  40. data/lib/moneta/weak.rb +17 -0
  41. data/lib/moneta/wrapper.rb +5 -0
  42. data/lib/rack/moneta_cookies.rb +2 -2
  43. data/lib/rack/moneta_store.rb +4 -4
  44. data/script/benchmarks +3 -9
  45. data/script/generate-specs +278 -41
  46. data/script/install-bundle +2 -2
  47. data/spec/moneta/adapter_activerecord_spec.rb +1 -0
  48. data/spec/moneta/adapter_cassandra_spec.rb +1 -0
  49. data/spec/moneta/adapter_cassandra_with_default_expires_spec.rb +1 -0
  50. data/spec/moneta/adapter_client_spec.rb +1 -0
  51. data/spec/moneta/adapter_cookie_spec.rb +1 -0
  52. data/spec/moneta/adapter_couch_spec.rb +1 -0
  53. data/spec/moneta/adapter_datamapper_spec.rb +1 -0
  54. data/spec/moneta/adapter_daybreak_spec.rb +1 -0
  55. data/spec/moneta/adapter_dbm_spec.rb +1 -0
  56. data/spec/moneta/adapter_file_spec.rb +1 -0
  57. data/spec/moneta/adapter_fog_spec.rb +1 -0
  58. data/spec/moneta/adapter_gdbm_spec.rb +1 -1
  59. data/spec/moneta/adapter_hbase_spec.rb +1 -0
  60. data/spec/moneta/adapter_leveldb_spec.rb +1 -0
  61. data/spec/moneta/adapter_localmemcache_spec.rb +1 -0
  62. data/spec/moneta/adapter_lruhash_spec.rb +1 -0
  63. data/spec/moneta/adapter_memcached_dalli_spec.rb +2 -0
  64. data/spec/moneta/adapter_memcached_dalli_with_default_expires_spec.rb +2 -0
  65. data/spec/moneta/adapter_memcached_native_spec.rb +2 -0
  66. data/spec/moneta/adapter_memcached_native_with_default_expires_spec.rb +2 -0
  67. data/spec/moneta/adapter_memcached_spec.rb +2 -0
  68. data/spec/moneta/adapter_memcached_with_default_expires_spec.rb +2 -0
  69. data/spec/moneta/adapter_memory_spec.rb +1 -0
  70. data/spec/moneta/adapter_mongo_spec.rb +2 -0
  71. data/spec/moneta/adapter_mongo_with_default_expires_spec.rb +2 -0
  72. data/spec/moneta/adapter_pstore_spec.rb +1 -0
  73. data/spec/moneta/adapter_redis_spec.rb +2 -0
  74. data/spec/moneta/adapter_redis_with_default_expires_spec.rb +2 -0
  75. data/spec/moneta/adapter_restclient_spec.rb +1 -0
  76. data/spec/moneta/adapter_riak_spec.rb +1 -0
  77. data/spec/moneta/adapter_sdbm_spec.rb +1 -0
  78. data/spec/moneta/adapter_sequel_spec.rb +1 -0
  79. data/spec/moneta/adapter_sqlite_spec.rb +1 -0
  80. data/spec/moneta/adapter_tdb_spec.rb +1 -0
  81. data/spec/moneta/adapter_tokyocabinet_bdb_spec.rb +1 -0
  82. data/spec/moneta/adapter_tokyocabinet_hdb_spec.rb +1 -0
  83. data/spec/moneta/adapter_yaml_spec.rb +1 -0
  84. data/spec/moneta/cache_file_memory_spec.rb +1 -0
  85. data/spec/moneta/cache_memory_null_spec.rb +1 -0
  86. data/spec/moneta/expires_file_spec.rb +3 -1
  87. data/spec/moneta/expires_memory_spec.rb +2 -0
  88. data/spec/moneta/expires_memory_with_default_expires_spec.rb +2 -0
  89. data/spec/moneta/lock_spec.rb +1 -0
  90. data/spec/moneta/mutex_spec.rb +71 -0
  91. data/spec/moneta/null_adapter_spec.rb +1 -0
  92. data/spec/moneta/optionmerger_spec.rb +5 -7
  93. data/spec/moneta/pool_spec.rb +1 -0
  94. data/spec/moneta/proxy_expires_memory_spec.rb +2 -0
  95. data/spec/moneta/proxy_redis_spec.rb +2 -0
  96. data/spec/moneta/semaphore_spec.rb +84 -0
  97. data/spec/moneta/{shared_spec.rb → shared_tcp_spec.rb} +4 -3
  98. data/spec/moneta/shared_unix_spec.rb +37 -0
  99. data/spec/moneta/simple_activerecord_spec.rb +1 -0
  100. data/spec/moneta/simple_activerecord_with_expires_spec.rb +3 -1
  101. data/spec/moneta/simple_cassandra_spec.rb +1 -0
  102. data/spec/moneta/simple_client_tcp_spec.rb +1 -0
  103. data/spec/moneta/simple_client_unix_spec.rb +3 -2
  104. data/spec/moneta/simple_couch_spec.rb +1 -0
  105. data/spec/moneta/simple_couch_with_expires_spec.rb +2 -1
  106. data/spec/moneta/simple_datamapper_spec.rb +1 -0
  107. data/spec/moneta/simple_datamapper_with_expires_spec.rb +3 -1
  108. data/spec/moneta/simple_datamapper_with_repository_spec.rb +1 -0
  109. data/spec/moneta/simple_daybreak_spec.rb +1 -0
  110. data/spec/moneta/simple_daybreak_with_expires_spec.rb +3 -1
  111. data/spec/moneta/simple_dbm_spec.rb +1 -0
  112. data/spec/moneta/simple_dbm_with_expires_spec.rb +3 -1
  113. data/spec/moneta/simple_file_spec.rb +1 -0
  114. data/spec/moneta/simple_file_with_expires_spec.rb +3 -1
  115. data/spec/moneta/simple_fog_spec.rb +1 -0
  116. data/spec/moneta/simple_fog_with_expires_spec.rb +2 -1
  117. data/spec/moneta/simple_gdbm_spec.rb +1 -0
  118. data/spec/moneta/simple_gdbm_with_expires_spec.rb +3 -1
  119. data/spec/moneta/simple_hashfile_spec.rb +1 -0
  120. data/spec/moneta/simple_hashfile_with_expires_spec.rb +3 -1
  121. data/spec/moneta/simple_hbase_spec.rb +1 -0
  122. data/spec/moneta/simple_hbase_with_expires_spec.rb +3 -1
  123. data/spec/moneta/simple_leveldb_spec.rb +1 -0
  124. data/spec/moneta/simple_leveldb_with_expires_spec.rb +3 -1
  125. data/spec/moneta/simple_localmemcache_spec.rb +1 -0
  126. data/spec/moneta/simple_localmemcache_with_expires_spec.rb +2 -1
  127. data/spec/moneta/simple_lruhash_spec.rb +1 -0
  128. data/spec/moneta/simple_lruhash_with_expires_spec.rb +3 -1
  129. data/spec/moneta/simple_memcached_dalli_spec.rb +2 -0
  130. data/spec/moneta/simple_memcached_native_spec.rb +2 -0
  131. data/spec/moneta/simple_memcached_spec.rb +2 -0
  132. data/spec/moneta/simple_memory_spec.rb +1 -0
  133. data/spec/moneta/simple_memory_with_compress_spec.rb +1 -0
  134. data/spec/moneta/simple_memory_with_expires_spec.rb +3 -1
  135. data/spec/moneta/simple_memory_with_json_key_serializer_spec.rb +1 -0
  136. data/spec/moneta/simple_memory_with_json_serializer_spec.rb +1 -0
  137. data/spec/moneta/simple_memory_with_json_value_serializer_spec.rb +1 -0
  138. data/spec/moneta/simple_memory_with_prefix_spec.rb +1 -0
  139. data/spec/moneta/simple_memory_with_snappy_compress_spec.rb +1 -0
  140. data/spec/moneta/simple_mongo_spec.rb +2 -0
  141. data/spec/moneta/simple_null_spec.rb +1 -0
  142. data/spec/moneta/simple_pstore_spec.rb +1 -0
  143. data/spec/moneta/simple_pstore_with_expires_spec.rb +3 -1
  144. data/spec/moneta/simple_redis_spec.rb +2 -0
  145. data/spec/moneta/simple_restclient_spec.rb +1 -0
  146. data/spec/moneta/simple_riak_spec.rb +1 -0
  147. data/spec/moneta/simple_riak_with_expires_spec.rb +2 -1
  148. data/spec/moneta/simple_sdbm_spec.rb +1 -0
  149. data/spec/moneta/simple_sdbm_with_expires_spec.rb +3 -1
  150. data/spec/moneta/simple_sequel_spec.rb +1 -0
  151. data/spec/moneta/simple_sequel_with_expires_spec.rb +3 -1
  152. data/spec/moneta/simple_sqlite_spec.rb +1 -0
  153. data/spec/moneta/simple_sqlite_with_expires_spec.rb +3 -1
  154. data/spec/moneta/simple_tdb_spec.rb +1 -0
  155. data/spec/moneta/simple_tdb_with_expires_spec.rb +3 -1
  156. data/spec/moneta/simple_tokyocabinet_spec.rb +1 -0
  157. data/spec/moneta/simple_tokyocabinet_with_expires_spec.rb +3 -1
  158. data/spec/moneta/simple_yaml_spec.rb +1 -0
  159. data/spec/moneta/simple_yaml_with_expires_spec.rb +3 -1
  160. data/spec/moneta/stack_file_memory_spec.rb +1 -0
  161. data/spec/moneta/stack_memory_file_spec.rb +1 -0
  162. data/spec/moneta/transformer_bencode_spec.rb +1 -0
  163. data/spec/moneta/transformer_bert_spec.rb +1 -0
  164. data/spec/moneta/transformer_bson_spec.rb +1 -0
  165. data/spec/moneta/transformer_bzip2_spec.rb +1 -0
  166. data/spec/moneta/transformer_json_spec.rb +1 -0
  167. data/spec/moneta/transformer_key_inspect_spec.rb +73 -0
  168. data/spec/moneta/transformer_key_marshal_spec.rb +1 -0
  169. data/spec/moneta/transformer_key_to_s_spec.rb +1 -0
  170. data/spec/moneta/transformer_key_yaml_spec.rb +1 -0
  171. data/spec/moneta/transformer_lzma_spec.rb +1 -0
  172. data/spec/moneta/transformer_lzo_spec.rb +1 -0
  173. data/spec/moneta/transformer_marshal_base64_spec.rb +1 -0
  174. data/spec/moneta/transformer_marshal_escape_spec.rb +1 -0
  175. data/spec/moneta/transformer_marshal_hmac_spec.rb +1 -0
  176. data/spec/moneta/transformer_marshal_md5_spec.rb +1 -0
  177. data/spec/moneta/transformer_marshal_md5_spread_spec.rb +1 -0
  178. data/spec/moneta/transformer_marshal_prefix_spec.rb +1 -0
  179. data/spec/moneta/transformer_marshal_rmd160_spec.rb +1 -0
  180. data/spec/moneta/transformer_marshal_sha1_spec.rb +1 -0
  181. data/spec/moneta/transformer_marshal_sha256_spec.rb +1 -0
  182. data/spec/moneta/transformer_marshal_sha384_spec.rb +1 -0
  183. data/spec/moneta/transformer_marshal_sha512_spec.rb +1 -0
  184. data/spec/moneta/transformer_marshal_spec.rb +1 -0
  185. data/spec/moneta/transformer_marshal_truncate_spec.rb +1 -0
  186. data/spec/moneta/transformer_marshal_uuencode_spec.rb +1 -0
  187. data/spec/moneta/transformer_msgpack_spec.rb +1 -0
  188. data/spec/moneta/transformer_ox_spec.rb +1 -0
  189. data/spec/moneta/transformer_quicklz_spec.rb +1 -0
  190. data/spec/moneta/transformer_snappy_spec.rb +1 -0
  191. data/spec/moneta/transformer_tnet_spec.rb +1 -0
  192. data/spec/moneta/transformer_value_marshal_spec.rb +1 -0
  193. data/spec/moneta/transformer_value_yaml_spec.rb +1 -0
  194. data/spec/moneta/transformer_yaml_spec.rb +1 -0
  195. data/spec/moneta/transformer_zlib_spec.rb +1 -0
  196. data/spec/moneta/weak_create_spec.rb +114 -0
  197. data/spec/moneta/weak_increment_spec.rb +114 -0
  198. data/spec/monetaspecs.rb +75 -2
  199. data/spec/rack/moneta_cookies_spec.rb +1 -1
  200. metadata +20 -4
@@ -57,86 +57,91 @@ module Moneta
57
57
  end
58
58
  end_eval
59
59
 
60
- key = compile_transformer(keys, 'key')
61
- dump = compile_transformer(values, 'value')
62
- load = compile_transformer(values.reverse, 'value', 1)
60
+ key, key_opts = compile_transformer(keys, 'key')
61
+ dump, dump_opts = compile_transformer(values, 'value')
62
+ load, load_opts = compile_transformer(values.reverse, 'value', 1)
63
63
 
64
64
  if values.empty?
65
- compile_key_transformer(klass, key)
65
+ compile_key_transformer(klass, key, key_opts)
66
66
  elsif keys.empty?
67
- compile_value_transformer(klass, load, dump)
67
+ compile_value_transformer(klass, load, load_opts, dump, dump_opts)
68
68
  else
69
- compile_key_value_transformer(klass, key, load, dump)
69
+ compile_key_value_transformer(klass, key, key_opts, load, load_opts, dump, dump_opts)
70
70
  end
71
71
 
72
72
  klass
73
73
  end
74
74
 
75
- def compile_key_transformer(klass, key)
75
+ def without(*options)
76
+ options = options.flatten.uniq
77
+ options.empty? ? 'options' : "Utils.without(options, #{options.map(&:to_sym).map(&:inspect).join(', ')})"
78
+ end
79
+
80
+ def compile_key_transformer(klass, key, key_opts)
76
81
  klass.class_eval <<-end_eval, __FILE__, __LINE__
77
82
  def key?(key, options = {})
78
- @adapter.key?(#{key}, options)
83
+ @adapter.key?(#{key}, #{without key_opts})
79
84
  end
80
85
  def increment(key, amount = 1, options = {})
81
- @adapter.increment(#{key}, amount, options)
86
+ @adapter.increment(#{key}, amount, #{without key_opts})
82
87
  end
83
88
  def load(key, options = {})
84
- options.include?(:raw) && (options = options.dup; options.delete(:raw))
85
- @adapter.load(#{key}, options)
89
+ @adapter.load(#{key}, #{without :raw, key_opts})
86
90
  end
87
91
  def store(key, value, options = {})
88
- options.include?(:raw) && (options = options.dup; options.delete(:raw))
89
- @adapter.store(#{key}, value, options)
92
+ @adapter.store(#{key}, value, #{without :raw, key_opts})
90
93
  end
91
94
  def delete(key, options = {})
92
- options.include?(:raw) && (options = options.dup; options.delete(:raw))
93
- @adapter.delete(#{key}, options)
95
+ @adapter.delete(#{key}, #{without :raw, key_opts})
96
+ end
97
+ def create(key, value, options = {})
98
+ @adapter.create(#{key}, value, #{without :raw, key_opts})
94
99
  end
95
100
  end_eval
96
101
  end
97
102
 
98
- def compile_value_transformer(klass, load, dump)
103
+ def compile_value_transformer(klass, load, load_opts, dump, dump_opts)
99
104
  klass.class_eval <<-end_eval, __FILE__, __LINE__
100
105
  def load(key, options = {})
101
- raw = options.include?(:raw) && (options = options.dup; options.delete(:raw))
102
- value = @adapter.load(key, options)
103
- value && !raw ? #{load} : value
106
+ value = @adapter.load(key, #{without :raw, load_opts})
107
+ value && !options[:raw] ? #{load} : value
104
108
  end
105
109
  def store(key, value, options = {})
106
- raw = options.include?(:raw) && (options = options.dup; options.delete(:raw))
107
- @adapter.store(key, raw ? value : #{dump}, options)
110
+ @adapter.store(key, options[:raw] ? value : #{dump}, #{without :raw, dump_opts})
108
111
  value
109
112
  end
110
113
  def delete(key, options = {})
111
- raw = options.include?(:raw) && (options = options.dup; options.delete(:raw))
112
- value = @adapter.delete(key, options)
113
- value && !raw ? #{load} : value
114
+ value = @adapter.delete(key, #{without :raw, load_opts})
115
+ value && !options[:raw] ? #{load} : value
116
+ end
117
+ def create(key, value, options = {})
118
+ @adapter.create(key, options[:raw] ? value : #{dump}, #{without :raw, dump_opts})
114
119
  end
115
120
  end_eval
116
121
  end
117
122
 
118
- def compile_key_value_transformer(klass, key, load, dump)
123
+ def compile_key_value_transformer(klass, key, key_opts, load, load_opts, dump, dump_opts)
119
124
  klass.class_eval <<-end_eval, __FILE__, __LINE__
120
125
  def key?(key, options = {})
121
- @adapter.key?(#{key}, options)
126
+ @adapter.key?(#{key}, #{without key_opts})
122
127
  end
123
128
  def increment(key, amount = 1, options = {})
124
- @adapter.increment(#{key}, amount, options)
129
+ @adapter.increment(#{key}, amount, #{without key_opts})
125
130
  end
126
131
  def load(key, options = {})
127
- raw = options.include?(:raw) && (options = options.dup; options.delete(:raw))
128
- value = @adapter.load(#{key}, options)
129
- value && !raw ? #{load} : value
132
+ value = @adapter.load(#{key}, #{without :raw, key_opts, load_opts})
133
+ value && !options[:raw] ? #{load} : value
130
134
  end
131
135
  def store(key, value, options = {})
132
- raw = options.include?(:raw) && (options = options.dup; options.delete(:raw))
133
- @adapter.store(#{key}, raw ? value : #{dump}, options)
136
+ @adapter.store(#{key}, options[:raw] ? value : #{dump}, #{without :raw, key_opts, dump_opts})
134
137
  value
135
138
  end
136
139
  def delete(key, options = {})
137
- raw = options.include?(:raw) && (options = options.dup; options.delete(:raw))
138
- value = @adapter.delete(#{key}, options)
139
- value && !raw ? #{load} : value
140
+ value = @adapter.delete(#{key}, #{without :raw, key_opts, load_opts})
141
+ value && !options[:raw] ? #{load} : value
142
+ end
143
+ def create(key, value, options = {})
144
+ @adapter.create(#{key}, options[:raw] ? value : #{dump}, #{without :raw, key_opts, dump_opts})
140
145
  end
141
146
  end_eval
142
147
  end
@@ -151,7 +156,6 @@ module Moneta
151
156
  end.join("\n")
152
157
  end
153
158
 
154
- # Compile transformer validator regular expression
155
159
  def compile_validator(s)
156
160
  Regexp.new('\A' + s.gsub(/\w+/) do
157
161
  '(' + TRANSFORMER.select {|k,v| v.first.to_s == $& }.map {|v| ":#{v.first}" }.join('|') + ')'
@@ -160,16 +164,20 @@ module Moneta
160
164
 
161
165
  # Returned compiled transformer code string
162
166
  def compile_transformer(transformer, var, i = 2)
163
- transformer.inject(var) do |value, name|
167
+ value, options = var, []
168
+ transformer.each do |name|
164
169
  raise ArgumentError, "Unknown transformer #{name}" unless t = TRANSFORMER[name]
165
170
  require t[3] if t[3]
166
171
  code = t[i]
167
- if t[0] == :serialize && var == 'key'
168
- "(tmp = #{value}; String === tmp ? tmp : #{code % 'tmp'})"
169
- else
170
- code % value
171
- end
172
+ options += code.scan(/options\[:(\w+)\]/).flatten
173
+ value =
174
+ if t[0] == :serialize && var == 'key'
175
+ "(tmp = #{value}; String === tmp ? tmp : #{code % 'tmp'})"
176
+ else
177
+ code % value
178
+ end
172
179
  end
180
+ return value, options
173
181
  end
174
182
 
175
183
  def class_name(keys, values)
@@ -2,44 +2,46 @@ module Moneta
2
2
  class Transformer
3
3
  # Available key/value transformers
4
4
  TRANSFORMER = {
5
- # Name => [ Type, Load, Dump, Library ],
6
- :bencode => [ :serialize, '::BEncode.load(%s)', '::BEncode.dump(%s)', 'bencode' ],
7
- :bert => [ :serialize, '::BERT.decode(%s)', '::BERT.encode(%s)', 'bert' ],
8
- :bson => [ :serialize, "::BSON.deserialize(%s)['v']", "::BSON.serialize('v'=>%s).to_s", 'bson' ],
9
- :json => [ :serialize, '::MultiJson.load(%s).first', '::MultiJson.dump([%s])', 'multi_json' ],
10
- :marshal => [ :serialize, '::Marshal.load(%s)', '::Marshal.dump(%s)' ],
11
- :msgpack => [ :serialize, '::MessagePack.unpack(%s)', '::MessagePack.pack(%s)', 'msgpack' ],
12
- :ox => [ :serialize, '::Ox.parse_obj(%s)', '::Ox.dump(%s)', 'ox' ],
13
- :tnet => [ :serialize, '::TNetstring.parse(%s).first', '::TNetstring.dump(%s)', 'tnetstring' ],
14
- :yaml => [ :serialize, '::YAML.load(%s)', '::YAML.dump(%s)', 'yaml' ],
15
- :bzip2 => [ :compress, '::Bzip2.uncompress(%s)', '::Bzip2.compress(%s)', 'bzip2' ],
16
- :lzma => [ :compress, '::LZMA.decompress(%s)', '::LZMA.compress(%s)', 'lzma' ],
17
- :lzo => [ :compress, '::LZO.decompress(%s)', '::LZO.compress(%s)', 'lzoruby' ],
18
- :snappy => [ :compress, '::Snappy.inflate(%s)', '::Snappy.deflate(%s)', 'snappy' ],
19
- :quicklz => [ :compress, '::QuickLZ.decompress(%s)', '::QuickLZ.compress(%s)', 'qlzruby' ],
20
- :zlib => [ :compress, '::Zlib::Inflate.inflate(%s)', '::Zlib::Deflate.deflate(%s)', 'zlib' ],
21
- :uuencode => [ :encode, "%s.unpack('u').first", "[%s].pack('u').strip" ],
5
+ # Name => [ Type, Load, Dump, Library ],
6
+ :bencode => [ :serialize, '::BEncode.load(%s)', '::BEncode.dump(%s)', 'bencode' ],
7
+ :bert => [ :serialize, '::BERT.decode(%s)', '::BERT.encode(%s)', 'bert' ],
8
+ :bson => [ :serialize, "::BSON.deserialize(%s)['v']", "::BSON.serialize('v'=>%s).to_s", 'bson' ],
9
+ :json => [ :serialize, '::MultiJson.load(%s).first', '::MultiJson.dump([%s])', 'multi_json' ],
10
+ :marshal => [ :serialize, '::Marshal.load(%s)', '::Marshal.dump(%s)' ],
11
+ :msgpack => [ :serialize, '::MessagePack.unpack(%s)', '::MessagePack.pack(%s)', 'msgpack' ],
12
+ :ox => [ :serialize, '::Ox.parse_obj(%s)', '::Ox.dump(%s)', 'ox' ],
13
+ :tnet => [ :serialize, '::TNetstring.parse(%s).first', '::TNetstring.dump(%s)', 'tnetstring' ],
14
+ :yaml => [ :serialize, '::YAML.load(%s)', '::YAML.dump(%s)', 'yaml' ],
15
+ :bzip2 => [ :compress, '::Bzip2.uncompress(%s)', '::Bzip2.compress(%s)', 'bzip2' ],
16
+ :lzma => [ :compress, '::LZMA.decompress(%s)', '::LZMA.compress(%s)', 'lzma' ],
17
+ :lzo => [ :compress, '::LZO.decompress(%s)', '::LZO.compress(%s)', 'lzoruby' ],
18
+ :snappy => [ :compress, '::Snappy.inflate(%s)', '::Snappy.deflate(%s)', 'snappy' ],
19
+ :quicklz => [ :compress, '::QuickLZ.decompress(%s)', '::QuickLZ.compress(%s)', 'qlzruby' ],
20
+ :zlib => [ :compress, '::Zlib::Inflate.inflate(%s)', '::Zlib::Deflate.deflate(%s)', 'zlib' ],
21
+ :uuencode => [ :encode, "%s.unpack('u').first", "[%s].pack('u').strip" ],
22
22
  :base64 => RUBY_VERSION > '1.9' ?
23
- [ :encode, "%s.unpack('m0').first", "[%s].pack('m0')" ] :
24
- [ :encode, "%s.unpack('m').first", "[%s].pack('m').gsub(\"\n\", '')" ],
25
- :escape => [ :encode, 'Helper.unescape(%s)', 'Helper.escape(%s)' ],
26
- :hmac => [ :hmac, 'Helper.hmacverify(%s, @secret)', 'Helper.hmacsign(%s, @secret)', 'openssl' ],
27
- :truncate => [ :truncate, nil, 'Helper.truncate(%s, @maxlen)', 'digest/md5' ],
28
- :md5 => [ :digest, nil, '::Digest::MD5.hexdigest(%s)', 'digest/md5' ],
29
- :rmd160 => [ :digest, nil, '::Digest::RMD160.hexdigest(%s)', 'digest/rmd160' ],
30
- :sha1 => [ :digest, nil, '::Digest::SHA1.hexdigest(%s)', 'digest/sha1' ],
31
- :sha256 => [ :digest, nil, '::Digest::SHA256.hexdigest(%s)', 'digest/sha2' ],
32
- :sha384 => [ :digest, nil, '::Digest::SHA384.hexdigest(%s)', 'digest/sha2' ],
33
- :sha512 => [ :digest, nil, '::Digest::SHA512.hexdigest(%s)', 'digest/sha2' ],
34
- :prefix => [ :prefix, nil, '(options[:prefix]||@prefix)+%s' ],
35
- :spread => [ :spread, nil, 'Helper.spread(%s)' ],
36
- :to_s => [ :to_s, nil, '%s.to_s' ],
23
+ [ :encode, "%s.unpack('m0').first", "[%s].pack('m0')" ] :
24
+ [ :encode, "%s.unpack('m').first", "[%s].pack('m').gsub(\"\n\", '')" ],
25
+ :escape => [ :encode, 'Helper.unescape(%s)', 'Helper.escape(%s)' ],
26
+ :hmac => [ :hmac, 'Helper.hmacverify(%s, options[:secret] || @secret)',
27
+ 'Helper.hmacsign(%s, options[:secret] || @secret)', 'openssl' ],
28
+ :truncate => [ :truncate, nil, 'Helper.truncate(%s, @maxlen)', 'digest/md5' ],
29
+ :md5 => [ :digest, nil, '::Digest::MD5.hexdigest(%s)', 'digest/md5' ],
30
+ :rmd160 => [ :digest, nil, '::Digest::RMD160.hexdigest(%s)', 'digest/rmd160' ],
31
+ :sha1 => [ :digest, nil, '::Digest::SHA1.hexdigest(%s)', 'digest/sha1' ],
32
+ :sha256 => [ :digest, nil, '::Digest::SHA256.hexdigest(%s)', 'digest/sha2' ],
33
+ :sha384 => [ :digest, nil, '::Digest::SHA384.hexdigest(%s)', 'digest/sha2' ],
34
+ :sha512 => [ :digest, nil, '::Digest::SHA512.hexdigest(%s)', 'digest/sha2' ],
35
+ :prefix => [ :prefix, nil, '(options[:prefix] || @prefix)+%s' ],
36
+ :spread => [ :spread, nil, 'Helper.spread(%s)' ],
37
+ :to_s => [ :string, nil, '%s.to_s' ],
38
+ :inspect => [ :string, nil, '%s.inspect' ],
37
39
  }
38
40
 
39
41
  # Allowed value transformers (Read it like a regular expression!)
40
42
  VALUE_TRANSFORMER = 'serialize? compress? hmac? encode?'
41
43
 
42
44
  # Allowed key transformers (Read it like a regular expression!)
43
- KEY_TRANSFORMER = '(serialize | to_s)? prefix? ((encode? truncate?) | (digest spread?))?'
45
+ KEY_TRANSFORMER = '(serialize | string)? prefix? ((encode? truncate?) | (digest spread?))?'
44
46
  end
45
47
  end
@@ -0,0 +1,20 @@
1
+ module Moneta
2
+ # @api private
3
+ module Utils
4
+ extend self
5
+
6
+ def without(hash, *keys)
7
+ if keys.any? {|k| hash.include?(k) }
8
+ hash = hash.dup
9
+ keys.each {|k| hash.delete(k) }
10
+ end
11
+ hash
12
+ end
13
+
14
+ def to_int(value)
15
+ intvalue = value.to_i
16
+ raise "#{value.inspect} is not an integer value" unless value == nil || intvalue.to_s == value.to_s
17
+ intvalue
18
+ end
19
+ end
20
+ end
@@ -1,5 +1,5 @@
1
1
  module Moneta
2
2
  # Moneta version number
3
3
  # @api public
4
- VERSION = '0.7.6'
4
+ VERSION = '0.7.8'
5
5
  end
@@ -0,0 +1,17 @@
1
+ module Moneta
2
+ # Adds weak create support to the underlying store
3
+ #
4
+ # @note The increment method will not be thread or multi-process safe (this is meant by weak)
5
+ # @api public
6
+ class WeakCreate < Proxy
7
+ include CreateSupport
8
+ end
9
+
10
+ # Adds weak increment support to the underlying store
11
+ #
12
+ # @note The increment method will not be thread or multi-process safe (this is meant by weak)
13
+ # @api public
14
+ class WeakIncrement < Proxy
15
+ include IncrementSupport
16
+ end
17
+ end
@@ -27,6 +27,11 @@ module Moneta
27
27
  wrap(:increment, key, amount, options) { super }
28
28
  end
29
29
 
30
+ # (see Proxy#create)
31
+ def create(key, value, options = {})
32
+ wrap(:create, key, value, options) { super }
33
+ end
34
+
30
35
  # (see Proxy#clear)
31
36
  def clear(options = {})
32
37
  wrap(:clear, options) { super }
@@ -23,7 +23,7 @@ module Rack
23
23
  # adapter :Cookie
24
24
  # end
25
25
  #
26
- # run lambda do |env|
26
+ # run lambda { |env|
27
27
  # req = Rack::Request.new(env)
28
28
  # req.cookies #=> is now a Moneta store!
29
29
  # env['rack.request.cookie_hash'] #=> is now a Moneta store!
@@ -31,7 +31,7 @@ module Rack
31
31
  # req.cookies['key'] = 'value' #=> sets 'moneta.key'
32
32
  # req.cookies.delete('key') #=> removes 'moneta.key'
33
33
  # [200, {}, []]
34
- # end
34
+ # }
35
35
  #
36
36
  # @api public
37
37
  class MonetaCookies
@@ -8,9 +8,9 @@ module Rack
8
8
  # # Add Rack::MonetaStore somewhere in your rack stack
9
9
  # use Rack::MonetaStore, :Memory, :cache => true
10
10
  #
11
- # run lambda do |env|
11
+ # run lambda { |env|
12
12
  # env['rack.moneta_store'] # is a Moneta store with per-request caching
13
- # end
13
+ # }
14
14
  #
15
15
  # @example config.ru
16
16
  # # Pass it a block like the one passed to Moneta.build
@@ -19,9 +19,9 @@ module Rack
19
19
  # adapter :Cookie
20
20
  # end
21
21
  #
22
- # run lambda do |env|
22
+ # run lambda { |env|
23
23
  # env['rack.moneta_store'] # is a Moneta store without caching
24
- # end
24
+ # }
25
25
  #
26
26
  # @api public
27
27
  class MonetaStore
data/script/benchmarks CHANGED
@@ -24,12 +24,6 @@ class Array
24
24
  m = mean
25
25
  Math.sqrt(map {|s| (s - m) ** 2 }.mean)
26
26
  end
27
-
28
- def randomize
29
- rest, result = dup, []
30
- result << rest.slice!(rand(rest.size)) until result.size == size
31
- result
32
- end
33
27
  end
34
28
 
35
29
  class MonetaBenchmarks
@@ -242,7 +236,7 @@ class MonetaBenchmarks
242
236
  puts "\e[31m#{name} not benchmarked - #{ex.message}\e[0m"
243
237
  STORES.delete(name)
244
238
  ensure
245
- cache.close if cache
239
+ (cache.close rescue nil) if cache
246
240
  end
247
241
  end
248
242
  end
@@ -312,14 +306,14 @@ class MonetaBenchmarks
312
306
  store.clear
313
307
  print "%s[%-#{2 * @config[:runs]}s] " % ["\b" * (2 * @config[:runs] + 3), state << 'W']
314
308
 
315
- @data = @data.randomize
309
+ @data.shuffle!
316
310
  m1 = Benchmark.measure do
317
311
  @data.each {|k,v| store[k] = v }
318
312
  end
319
313
 
320
314
  print "%s[%-#{2 * @config[:runs]}s] " % ["\b" * (2 * @config[:runs] + 3), state << 'R']
321
315
 
322
- @data = @data.randomize
316
+ @data.shuffle!
323
317
  error = 0
324
318
  m2 = Benchmark.measure do
325
319
  @data.each do |k, v|
@@ -61,14 +61,17 @@ class Specs
61
61
  a = specs.dup
62
62
  if a.include?(:transform_value)
63
63
  a.delete(:transform_value)
64
- a << :transform_value_with_expires
64
+ a << :transform_value_expires
65
65
  end
66
+ a << :create_expires if a.include?(:create)
66
67
  a << :expires
67
68
  new(:specs => a)
68
69
  end
69
70
 
70
71
  def with_native_expires
71
- new(:specs => specs.with(:expires))
72
+ a = specs.dup
73
+ a << :create_expires if a.include?(:create)
74
+ new(:specs => a.with(:expires))
72
75
  end
73
76
 
74
77
  def without_marshallable
@@ -98,11 +101,15 @@ class Specs
98
101
  def with_default_expires
99
102
  new(:specs => specs.with(:default_expires))
100
103
  end
104
+
105
+ def without_create
106
+ new(:specs => specs.without(:create, :create_expires).with(:not_create))
107
+ end
101
108
  end
102
109
 
103
- ADAPTER_SPECS = Specs.new(:specs => [:null, :store, :returndifferent, :increment, :persist, :multiprocess], :key => %w(string), :value => %w(string))
104
- STANDARD_SPECS = Specs.new(:specs => [:null, :store, :returndifferent, :marshallable_key, :marshallable_value, :transform_value, :increment, :persist, :multiprocess])
105
- TRANSFORMER_SPECS = Specs.new(:specs => [:null, :store, :returndifferent, :transform_value, :increment])
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])
106
113
 
107
114
  header = "# Generated by #{File.basename(__FILE__)}\n"
108
115
 
@@ -129,16 +136,16 @@ end
129
136
  }
130
137
  },
131
138
  'simple_client_unix' => {
132
- :preamble => "start_server(Moneta::Adapters::Memory.new, :file => File.join(make_tempdir, 'simple_client_unix'))\n",
139
+ :preamble => "start_server(Moneta::Adapters::Memory.new, :socket => File.join(make_tempdir, 'simple_client_unix'))\n",
133
140
  :store => :Client,
134
- :options => ":file => File.join(make_tempdir, 'simple_client_unix')",
141
+ :options => ":socket => File.join(make_tempdir, 'simple_client_unix')",
135
142
  :specs => STANDARD_SPECS
136
143
  },
137
144
  'simple_restclient' => {
138
145
  :preamble => "start_restserver\n",
139
146
  :store => :RestClient,
140
147
  :options => ":url => 'http://localhost:8808/moneta/'",
141
- :specs => STANDARD_SPECS.without_increment
148
+ :specs => STANDARD_SPECS.without_increment.without_create
142
149
  },
143
150
  'simple_memory' => {
144
151
  :store => :Memory,
@@ -215,12 +222,12 @@ end
215
222
  'simple_cassandra' => {
216
223
  :store => :Cassandra,
217
224
  :options => ':keyspace => "simple_cassandra"',
218
- :specs => STANDARD_SPECS.without_increment.with_native_expires,
225
+ :specs => STANDARD_SPECS.without_increment.without_create.with_native_expires,
219
226
  },
220
227
  'simple_hbase' => {
221
228
  :store => :HBase,
222
229
  :options => ':table => "simple_hbase"',
223
- :specs => STANDARD_SPECS
230
+ :specs => STANDARD_SPECS.without_create
224
231
  },
225
232
  'simple_hbase_with_expires' => {
226
233
  :store => :HBase,
@@ -314,12 +321,12 @@ end
314
321
  'simple_localmemcache' => {
315
322
  :store => :LocalMemCache,
316
323
  :options => ':file => File.join(make_tempdir, "simple_localmemcache")',
317
- :specs => STANDARD_SPECS.without_increment
324
+ :specs => STANDARD_SPECS.without_increment.without_create
318
325
  },
319
326
  'simple_localmemcache_with_expires' => {
320
327
  :store => :LocalMemCache,
321
328
  :options => ':file => File.join(make_tempdir, "simple_localmemcache_with_expires"), :expires => true',
322
- :specs => STANDARD_SPECS.without_increment.with_expires
329
+ :specs => STANDARD_SPECS.without_increment.without_create.with_expires
323
330
  },
324
331
  'simple_tokyocabinet' => {
325
332
  :store => :TokyoCabinet,
@@ -365,25 +372,25 @@ end
365
372
  :options => ":bucket => 'simple_riak'",
366
373
  # We don't want Riak warnings in tests
367
374
  :preamble => "require 'riak'\n\nRiak.disable_list_keys_warnings = true\n\n",
368
- :specs => STANDARD_SPECS.without_increment
375
+ :specs => STANDARD_SPECS.without_increment.without_create
369
376
  },
370
377
  'simple_riak_with_expires' => {
371
378
  :store => :Riak,
372
379
  :options => ":bucket => 'simple_riak_with_expires', :expires => true",
373
380
  # We don't want Riak warnings in tests
374
381
  :preamble => "require 'riak'\n\nRiak.disable_list_keys_warnings = true\n\n",
375
- :specs => STANDARD_SPECS.without_increment.with_expires
382
+ :specs => STANDARD_SPECS.without_increment.with_expires.without_create
376
383
  },
377
384
  'simple_couch' => {
378
385
  :store => :Couch,
379
386
  :options => ":db => 'simple_couch'",
380
387
  :load_value => '::Marshal.load(value.unpack(\'m\').first)',
381
- :specs => STANDARD_SPECS.without_increment
388
+ :specs => STANDARD_SPECS.without_increment.without_create
382
389
  },
383
390
  'simple_couch_with_expires' => {
384
391
  :store => :Couch,
385
392
  :options => ":db => 'simple_couch_with_expires', :expires => true",
386
- :specs => STANDARD_SPECS.without_increment.with_expires,
393
+ :specs => STANDARD_SPECS.without_increment.without_create.with_expires,
387
394
  :load_value => '::Marshal.load(value.unpack(\'m\').first)'
388
395
  },
389
396
  'simple_mongo' => {
@@ -393,11 +400,11 @@ end
393
400
  },
394
401
  'simple_null' => {
395
402
  :store => :Null,
396
- :specs => STANDARD_SPECS.without_increment.without_store.without_persist
403
+ :specs => STANDARD_SPECS.without_increment.without_create.without_store.without_persist
397
404
  },
398
405
  'null_adapter' => {
399
406
  :build => 'Moneta::Adapters::Null.new',
400
- :specs => Specs.new(:specs => [:null, :not_increment, :not_persist])
407
+ :specs => Specs.new(:specs => [:null, :not_increment, :not_create, :not_persist])
401
408
  },
402
409
  'simple_sequel' => {
403
410
  :store => :Sequel,
@@ -449,7 +456,7 @@ end
449
456
  },
450
457
  'simple_fog' => {
451
458
  :store => :Fog,
452
- :specs => STANDARD_SPECS.without_increment,
459
+ :specs => STANDARD_SPECS.without_increment.without_create,
453
460
  :options => ":aws_access_key_id => 'fake_access_key_id',
454
461
  :aws_secret_access_key => 'fake_secret_access_key',
455
462
  :provider => 'AWS',
@@ -466,7 +473,21 @@ end
466
473
  :expires => true",
467
474
  # Put Fog into testing mode
468
475
  :preamble => "require 'fog'\nFog.mock!\n",
469
- :specs => STANDARD_SPECS.without_increment.with_expires
476
+ :specs => STANDARD_SPECS.without_increment.without_create.with_expires
477
+ },
478
+ 'weak_create' => {
479
+ :build => %{Moneta.build do
480
+ use :WeakCreate
481
+ adapter :Memory
482
+ end},
483
+ :specs => STANDARD_SPECS.without_transform.without_persist.returnsame
484
+ },
485
+ 'weak_increment' => {
486
+ :build => %{Moneta.build do
487
+ use :WeakIncrement
488
+ adapter :Memory
489
+ end},
490
+ :specs => STANDARD_SPECS.without_transform.without_persist.returnsame
470
491
  },
471
492
  'expires_memory' => {
472
493
  :build => %{Moneta.build do
@@ -549,10 +570,27 @@ end
549
570
  end},
550
571
  :specs => ADAPTER_SPECS.without_persist.returnsame
551
572
  },
552
- 'shared' => {
573
+ 'shared_tcp' => {
553
574
  :build => %{Moneta.build do
554
575
  use(:Shared, :port => 9001) do
555
- adapter :PStore, :file => File.join(make_tempdir, 'shared')
576
+ adapter :PStore, :file => File.join(make_tempdir, 'shared_tcp')
577
+ end
578
+ end},
579
+ :specs => ADAPTER_SPECS,
580
+ :tests => %{
581
+ it 'shares values' do
582
+ store['shared_key'] = 'shared_value'
583
+ second = new_store
584
+ second.key?('shared_key').should be_true
585
+ second['shared_key'].should == 'shared_value'
586
+ second.close
587
+ end
588
+ }
589
+ },
590
+ 'shared_unix' => {
591
+ :build => %{Moneta.build do
592
+ use(:Shared, :socket => File.join(make_tempdir, 'shared_unix.socket')) do
593
+ adapter :PStore, :file => File.join(make_tempdir, 'shared_unix')
556
594
  end
557
595
  end},
558
596
  :specs => ADAPTER_SPECS,
@@ -575,7 +613,7 @@ end
575
613
  add { adapter :Memory }
576
614
  end
577
615
  end},
578
- :specs => ADAPTER_SPECS.without_increment
616
+ :specs => ADAPTER_SPECS.without_increment.without_create
579
617
  },
580
618
  'stack_memory_file' => {
581
619
  :build => %{Moneta.build do
@@ -586,7 +624,7 @@ end},
586
624
  add { adapter :File, :dir => File.join(make_tempdir, "stack_memory_file") }
587
625
  end
588
626
  end},
589
- :specs => STANDARD_SPECS.without_increment.returnsame.without_transform.stringkeys_only.stringvalues_only
627
+ :specs => STANDARD_SPECS.without_increment.without_create.returnsame.without_transform.stringkeys_only.stringvalues_only
590
628
  },
591
629
  'lock' => {
592
630
  :build => %{Moneta.build do
@@ -810,6 +848,19 @@ end},
810
848
  it 'compile transformer class' do
811
849
  store.should_not be_nil
812
850
  Moneta::Transformer::To_sKey.should_not be_nil
851
+ end}
852
+ },
853
+ 'transformer_key_inspect' => {
854
+ :build => %{Moneta.build do
855
+ use :Transformer, :key => :inspect
856
+ adapter :Memory
857
+ end},
858
+ :specs => TRANSFORMER_SPECS.returnsame.simplekeys_only,
859
+ :load_value => 'value',
860
+ :tests => %{
861
+ it 'compile transformer class' do
862
+ store.should_not be_nil
863
+ Moneta::Transformer::InspectKey.should_not be_nil
813
864
  end}
814
865
  },
815
866
  'transformer_value_marshal' => {
@@ -1050,19 +1101,19 @@ end
1050
1101
  'adapter_restclient' => {
1051
1102
  :preamble => "start_restserver\n",
1052
1103
  :build => "Moneta::Adapters::RestClient.new(:url => 'http://localhost:8808/moneta/')",
1053
- :specs => ADAPTER_SPECS.without_increment
1104
+ :specs => ADAPTER_SPECS.without_increment.without_create
1054
1105
  },
1055
1106
  'adapter_cassandra' => {
1056
1107
  :build => "Moneta::Adapters::Cassandra.new(:keyspace => 'adapter_cassandra')",
1057
- :specs => ADAPTER_SPECS.without_increment.with_native_expires
1108
+ :specs => ADAPTER_SPECS.without_increment.without_create.with_native_expires
1058
1109
  },
1059
1110
  'adapter_cassandra_with_default_expires' => {
1060
1111
  :build => %{Moneta::Adapters::Cassandra.new(:keyspace => 'adapter_cassandra_with_default_expires', :expires => 1)},
1061
- :specs => ADAPTER_SPECS.without_increment.with_native_expires.with_default_expires
1112
+ :specs => ADAPTER_SPECS.without_increment.without_create.with_native_expires.with_default_expires
1062
1113
  },
1063
1114
  'adapter_hbase' => {
1064
1115
  :build => "Moneta::Adapters::HBase.new(:table => 'adapter_hbase')",
1065
- :specs => ADAPTER_SPECS
1116
+ :specs => ADAPTER_SPECS.without_create
1066
1117
  },
1067
1118
  'adapter_cookie' => {
1068
1119
  :build => 'Moneta::Adapters::Cookie.new',
@@ -1070,7 +1121,7 @@ end
1070
1121
  },
1071
1122
  'adapter_couch' => {
1072
1123
  :build => "Moneta::Adapters::Couch.new(:db => 'adapter_couch')",
1073
- :specs => ADAPTER_SPECS.without_increment
1124
+ :specs => ADAPTER_SPECS.without_increment.without_create
1074
1125
  },
1075
1126
  'adapter_datamapper' => {
1076
1127
  :build => 'Moneta::Adapters::DataMapper.new(:setup => "sqlite3://#{make_tempdir}/adapter_datamapper")',
@@ -1132,15 +1183,15 @@ end
1132
1183
  # Put Fog into testing mode
1133
1184
  :preamble => "require 'fog'\nFog.mock!\n",
1134
1185
  # Fog returns same object in mocking mode (in-memory store)
1135
- :specs => ADAPTER_SPECS.without_increment.returnsame
1186
+ :specs => ADAPTER_SPECS.without_increment.without_create.returnsame
1136
1187
  },
1137
1188
  'adapter_gdbm' => {
1138
1189
  :build => 'Moneta::Adapters::GDBM.new(:file => File.join(make_tempdir, "adapter_gdbm"))',
1139
- :specs => ADAPTER_SPECS
1190
+ :specs => ADAPTER_SPECS.without_multiprocess
1140
1191
  },
1141
1192
  'adapter_localmemcache' => {
1142
1193
  :build => 'Moneta::Adapters::LocalMemCache.new(:file => File.join(make_tempdir, "adapter_localmemcache"))',
1143
- :specs => ADAPTER_SPECS.without_increment
1194
+ :specs => ADAPTER_SPECS.without_increment.without_create
1144
1195
  },
1145
1196
  'adapter_memcached_dalli' => {
1146
1197
  :build => 'Moneta::Adapters::MemcachedDalli.new(:namespace => "adapter_memcached_dalli")',
@@ -1218,7 +1269,7 @@ end}
1218
1269
  'adapter_riak' => {
1219
1270
  :build => 'Moneta::Adapters::Riak.new',
1220
1271
  :options => ":bucket => 'adapter_riak'",
1221
- :specs => ADAPTER_SPECS.without_increment,
1272
+ :specs => ADAPTER_SPECS.without_increment.without_create,
1222
1273
  # We don't want Riak warnings in tests
1223
1274
  :preamble => "require 'riak'\n\nRiak.disable_list_keys_warnings = true\n\n"
1224
1275
  },
@@ -1250,6 +1301,133 @@ end}
1250
1301
  :build => 'Moneta::Adapters::YAML.new(:file => File.join(make_tempdir, "adapter_yaml"))',
1251
1302
  :specs => STANDARD_SPECS.simplevalues_only.simplekeys_only.without_transform
1252
1303
  },
1304
+ 'mutex' => {
1305
+ :store => :Memory,
1306
+ :specs => Specs.new,
1307
+ :tests => %{
1308
+ it 'should have #lock' do
1309
+ mutex = Moneta::Mutex.new(store, 'mutex')
1310
+ mutex.lock.should be_true
1311
+ mutex.locked?.should be_true
1312
+ expect do
1313
+ mutex.lock
1314
+ end.to raise_error(RuntimeError)
1315
+ expect do
1316
+ mutex.try_lock
1317
+ end.to raise_error(RuntimeError)
1318
+ mutex.unlock.should be_nil
1319
+ mutex.locked?.should be_false
1320
+ end
1321
+
1322
+ it 'should have #enter' do
1323
+ mutex = Moneta::Mutex.new(store, 'mutex')
1324
+ mutex.enter.should be_true
1325
+ mutex.locked?.should be_true
1326
+ expect do
1327
+ mutex.enter
1328
+ end.to raise_error(RuntimeError)
1329
+ expect do
1330
+ mutex.try_enter
1331
+ end.to raise_error(RuntimeError)
1332
+ mutex.leave.should be_nil
1333
+ mutex.locked?.should be_false
1334
+ end
1335
+
1336
+ it 'should lock with #lock' do
1337
+ a = Moneta::Mutex.new(store, 'mutex')
1338
+ b = Moneta::Mutex.new(store, 'mutex')
1339
+ a.lock.should be_true
1340
+ b.try_lock.should be_false
1341
+ a.unlock.should be_nil
1342
+ end
1343
+
1344
+ it 'should have lock timeout' do
1345
+ a = Moneta::Mutex.new(store, 'mutex')
1346
+ b = Moneta::Mutex.new(store, 'mutex')
1347
+ a.lock.should be_true
1348
+ b.lock(1).should be_false
1349
+ a.unlock.should be_nil
1350
+ end
1351
+
1352
+ it 'should have #synchronize' do
1353
+ mutex = Moneta::Mutex.new(store, 'mutex')
1354
+ mutex.synchronize do
1355
+ mutex.locked?.should be_true
1356
+ end
1357
+ mutex.locked?.should be_false
1358
+ end
1359
+ }
1360
+ },
1361
+ 'semaphore' => {
1362
+ :store => :Memory,
1363
+ :specs => Specs.new,
1364
+ :tests => %{
1365
+ it 'should have #lock' do
1366
+ mutex = Moneta::Semaphore.new(store, 'semaphore')
1367
+ mutex.lock.should be_true
1368
+ mutex.locked?.should be_true
1369
+ expect do
1370
+ mutex.lock
1371
+ end.to raise_error(RuntimeError)
1372
+ expect do
1373
+ mutex.try_lock
1374
+ end.to raise_error(RuntimeError)
1375
+ mutex.unlock.should be_nil
1376
+ mutex.locked?.should be_false
1377
+ end
1378
+
1379
+ it 'should have #enter' do
1380
+ mutex = Moneta::Semaphore.new(store, 'semaphore')
1381
+ mutex.enter.should be_true
1382
+ mutex.locked?.should be_true
1383
+ expect do
1384
+ mutex.enter
1385
+ end.to raise_error(RuntimeError)
1386
+ expect do
1387
+ mutex.try_enter
1388
+ end.to raise_error(RuntimeError)
1389
+ mutex.leave.should be_nil
1390
+ mutex.locked?.should be_false
1391
+ end
1392
+
1393
+ it 'should lock with #lock' do
1394
+ a = Moneta::Semaphore.new(store, 'semaphore')
1395
+ b = Moneta::Semaphore.new(store, 'semaphore')
1396
+ a.lock.should be_true
1397
+ b.try_lock.should be_false
1398
+ a.unlock.should be_nil
1399
+ end
1400
+
1401
+ it 'should have lock timeout' do
1402
+ a = Moneta::Semaphore.new(store, 'semaphore')
1403
+ b = Moneta::Semaphore.new(store, 'semaphore')
1404
+ a.lock.should be_true
1405
+ b.lock(1).should be_false
1406
+ a.unlock.should be_nil
1407
+ end
1408
+
1409
+ it 'should count concurrent accesses' do
1410
+ a = Moneta::Semaphore.new(store, 'semaphore', 2)
1411
+ b = Moneta::Semaphore.new(store, 'semaphore', 2)
1412
+ c = Moneta::Semaphore.new(store, 'semaphore', 2)
1413
+ a.synchronize do
1414
+ a.locked?.should be_true
1415
+ b.synchronize do
1416
+ b.locked?.should be_true
1417
+ c.try_lock.should be_false
1418
+ end
1419
+ end
1420
+ end
1421
+
1422
+ it 'should have #synchronize' do
1423
+ semaphore = Moneta::Semaphore.new(store, 'semaphore')
1424
+ semaphore.synchronize do
1425
+ semaphore.locked?.should be_true
1426
+ end
1427
+ semaphore.locked?.should be_false
1428
+ end
1429
+ }
1430
+ },
1253
1431
  'optionmerger' => {
1254
1432
  :store => :Memory,
1255
1433
  :specs => Specs.new,
@@ -1314,22 +1492,20 @@ it 'merges options except for some methods' do
1314
1492
  end
1315
1493
 
1316
1494
  it 'has method #raw' do
1317
- store.raw.default_options.should == {:store=>{:raw=>true},:load=>{:raw=>true},:delete=>{:raw=>true}}
1495
+ store.raw.default_options.should == {:store=>{:raw=>true},:create=>{:raw=>true},:load=>{:raw=>true},:delete=>{:raw=>true}}
1318
1496
  store.raw.should equal(store.raw.raw)
1319
1497
  end
1320
1498
 
1321
1499
  it 'has method #prefix' do
1322
- store.prefix('a').default_options.should == {:store=>{:prefix=>'a'},:load=>{:prefix=>'a'},
1500
+ store.prefix('a').default_options.should == {:store=>{:prefix=>'a'},:load=>{:prefix=>'a'},:create=>{:prefix=>'a'},
1323
1501
  :delete=>{:prefix=>'a'},:key? => {:prefix=>'a'},:increment=>{:prefix=>'a'}}
1324
1502
 
1325
- store.prefix('a').prefix('b').default_options.should == {:store=>{:prefix=>'ab'},:load=>{:prefix=>'ab'},
1503
+ store.prefix('a').prefix('b').default_options.should == {:store=>{:prefix=>'ab'},:load=>{:prefix=>'ab'},:create=>{:prefix=>'ab'},
1326
1504
  :delete=>{:prefix=>'ab'},:key? => {:prefix=>'ab'},:increment=>{:prefix=>'ab'}}
1327
1505
 
1328
- store.raw.prefix('b').default_options.should == {:store=>{:raw=>true,:prefix=>'b'},:load=>{:raw=>true,:prefix=>'b'},
1329
- :delete=>{:raw=>true,:prefix=>'b'},:key? => {:prefix=>'b'},:increment=>{:prefix=>'b'}}
1506
+ store.raw.prefix('b').default_options.should == {:store=>{:raw=>true,:prefix=>'b'},:load=>{:raw=>true,:prefix=>'b'},:create=>{:raw=>true,:prefix=>'b'},:delete=>{:raw=>true,:prefix=>'b'},:key? => {:prefix=>'b'},:increment=>{:prefix=>'b'}}
1330
1507
 
1331
- store.prefix('a').raw.default_options.should == {:store=>{:raw=>true,:prefix=>'a'},:load=>{:raw=>true,:prefix=>'a'},
1332
- :delete=>{:raw=>true,:prefix=>'a'},:key? => {:prefix=>'a'},:increment=>{:prefix=>'a'}}
1508
+ store.prefix('a').raw.default_options.should == {:store=>{:raw=>true,:prefix=>'a'},:load=>{:raw=>true,:prefix=>'a'},:create=>{:raw=>true,:prefix=>'a'},:delete=>{:raw=>true,:prefix=>'a'},:key? => {:prefix=>'a'},:increment=>{:prefix=>'a'}}
1333
1509
  end
1334
1510
 
1335
1511
  it 'supports adding proxis using #with' do
@@ -1796,6 +1972,67 @@ it 'raises error in #decrement on non integer value' do
1796
1972
  expect do
1797
1973
  store.decrement('strkey')
1798
1974
  end.to raise_error
1975
+ end
1976
+
1977
+ it 'supports Semaphore' do
1978
+ a = Moneta::Semaphore.new(store, 'semaphore', 2)
1979
+ b = Moneta::Semaphore.new(store, 'semaphore', 2)
1980
+ c = Moneta::Semaphore.new(store, 'semaphore', 2)
1981
+ a.synchronize do
1982
+ a.locked?.should be_true
1983
+ b.synchronize do
1984
+ b.locked?.should be_true
1985
+ c.try_lock.should be_false
1986
+ end
1987
+ end
1988
+ end
1989
+ }
1990
+
1991
+ SPECS['create'] = %{it 'creates the given key' do
1992
+ store.create('key','value').should be_true
1993
+ store['key'].should == 'value'
1994
+ end
1995
+
1996
+ it 'creates raw value with the given key' do
1997
+ store.raw.create('key','value').should be_true
1998
+ store.raw['key'].should == 'value'
1999
+ end
2000
+
2001
+ it 'does not create a key if it exists' do
2002
+ store['key'] = 'value'
2003
+ store.create('key','another value').should be_false
2004
+ store['key'].should == 'value'
2005
+ end
2006
+
2007
+ it 'supports Mutex' do
2008
+ a = Moneta::Mutex.new(store, 'mutex')
2009
+ b = Moneta::Mutex.new(store, 'mutex')
2010
+ a.lock.should be_true
2011
+ b.try_lock.should be_false
2012
+ a.unlock.should be_nil
2013
+ end
2014
+ }
2015
+
2016
+ SPECS['not_create'] = %{it 'does not support #create' do
2017
+ expect do
2018
+ store.create('key','value')
2019
+ end.to raise_error(NotImplementedError)
2020
+ end}
2021
+
2022
+ SPECS['create_expires'] = %{it 'creates the given key and expires it' do
2023
+ store.create('key','value', :expires => 1).should be_true
2024
+ store['key'].should == 'value'
2025
+ sleep 2
2026
+ store.key?('key').should be_false
2027
+ end
2028
+
2029
+ it 'does not change expires if the key exists' do
2030
+ store.store('key', 'value', :expires => false).should == 'value'
2031
+ store.create('key','another value', :expires => 1).should be_false
2032
+ store['key'].should == 'value'
2033
+ sleep 2
2034
+ store['key'].should == 'value'
2035
+ store.key?('key').should be_true
1799
2036
  end}
1800
2037
 
1801
2038
  SPECS['marshallable_key'] = %{it 'refuses to #[] from keys that cannot be marshalled' do
@@ -1889,7 +2126,7 @@ it 'might raise exception on invalid value' do
1889
2126
  end
1890
2127
  end}
1891
2128
 
1892
- SPECS['transform_value_with_expires'] = %{it 'allows to bypass transformer with :raw' do
2129
+ SPECS['transform_value_expires'] = %{it 'allows to bypass transformer with :raw' do
1893
2130
  store['key'] = 'value'
1894
2131
  load_value(store.load('key', :raw => true)).should == 'value'
1895
2132
  store['key'] = [1,2,3]