moneta 0.7.6 → 0.7.8

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