moneta 1.2.1 → 1.3.0

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 (117) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rubocop.yml +1 -1
  4. data/.travis.yml +10 -4
  5. data/CHANGES +9 -0
  6. data/Gemfile +7 -5
  7. data/README.md +9 -6
  8. data/feature_matrix.yaml +2 -1
  9. data/lib/moneta/adapters/client.rb +56 -19
  10. data/lib/moneta/adapters/couch.rb +5 -0
  11. data/lib/moneta/adapters/mongo/moped.rb +4 -1
  12. data/lib/moneta/builder.rb +2 -2
  13. data/lib/moneta/lock.rb +6 -1
  14. data/lib/moneta/pool.rb +12 -0
  15. data/lib/moneta/proxy.rb +1 -1
  16. data/lib/moneta/server.rb +215 -61
  17. data/lib/moneta/shared.rb +13 -7
  18. data/lib/moneta/transformer.rb +50 -8
  19. data/lib/moneta/transformer/config.rb +59 -40
  20. data/lib/moneta/version.rb +1 -1
  21. data/moneta.gemspec +2 -2
  22. data/script/benchmarks +6 -1
  23. data/script/contributors +1 -2
  24. data/script/start-couchdb +27 -0
  25. data/script/start-hbase +2 -2
  26. data/script/start-services +3 -3
  27. data/spec/features/store.rb +3 -3
  28. data/spec/features/transform_value.rb +27 -21
  29. data/spec/helper.rb +52 -53
  30. data/spec/moneta/adapters/activerecord/standard_activerecord_spec.rb +1 -1
  31. data/spec/moneta/adapters/activerecord/standard_activerecord_with_expires_spec.rb +1 -1
  32. data/spec/moneta/adapters/cassandra/standard_cassandra_spec.rb +1 -1
  33. data/spec/moneta/adapters/client/adapter_client_spec.rb +6 -6
  34. data/spec/moneta/adapters/client/client_helper.rb +24 -0
  35. data/spec/moneta/adapters/client/standard_client_tcp_spec.rb +8 -8
  36. data/spec/moneta/adapters/client/standard_client_unix_spec.rb +23 -7
  37. data/spec/moneta/adapters/couch/adapter_couch_spec.rb +1 -1
  38. data/spec/moneta/adapters/couch/standard_couch_spec.rb +2 -2
  39. data/spec/moneta/adapters/couch/standard_couch_with_expires_spec.rb +2 -2
  40. data/spec/moneta/adapters/daybreak/standard_daybreak_spec.rb +1 -1
  41. data/spec/moneta/adapters/daybreak/standard_daybreak_with_expires_spec.rb +1 -1
  42. data/spec/moneta/adapters/dbm/standard_dbm_spec.rb +1 -1
  43. data/spec/moneta/adapters/dbm/standard_dbm_with_expires_spec.rb +1 -1
  44. data/spec/moneta/adapters/file/standard_file_spec.rb +2 -2
  45. data/spec/moneta/adapters/file/standard_file_with_expires_spec.rb +1 -1
  46. data/spec/moneta/adapters/gdbm/standard_gdbm_spec.rb +1 -1
  47. data/spec/moneta/adapters/gdbm/standard_gdbm_with_expires_spec.rb +1 -1
  48. data/spec/moneta/adapters/kyotocabinet/adapter_kyotocabinet_spec.rb +1 -1
  49. data/spec/moneta/adapters/kyotocabinet/standard_kyotocabinet_spec.rb +2 -2
  50. data/spec/moneta/adapters/kyotocabinet/standard_kyotocabinet_with_expires_spec.rb +2 -2
  51. data/spec/moneta/adapters/leveldb/standard_leveldb_spec.rb +1 -1
  52. data/spec/moneta/adapters/leveldb/standard_leveldb_with_expires_spec.rb +1 -1
  53. data/spec/moneta/adapters/lmdb/standard_lmdb_spec.rb +1 -1
  54. data/spec/moneta/adapters/lmdb/standard_lmdb_with_expires_spec.rb +1 -1
  55. data/spec/moneta/adapters/lruhash/standard_lruhash_spec.rb +1 -1
  56. data/spec/moneta/adapters/lruhash/standard_lruhash_with_expires_spec.rb +1 -1
  57. data/spec/moneta/adapters/memory/standard_memory_spec.rb +1 -1
  58. data/spec/moneta/adapters/memory/standard_memory_with_compress_spec.rb +1 -1
  59. data/spec/moneta/adapters/memory/standard_memory_with_expires_spec.rb +1 -1
  60. data/spec/moneta/adapters/memory/standard_memory_with_json_key_serializer_spec.rb +1 -1
  61. data/spec/moneta/adapters/memory/standard_memory_with_json_serializer_spec.rb +1 -1
  62. data/spec/moneta/adapters/memory/standard_memory_with_json_value_serializer_spec.rb +2 -2
  63. data/spec/moneta/adapters/memory/standard_memory_with_prefix_spec.rb +39 -2
  64. data/spec/moneta/adapters/memory/standard_memory_with_snappy_compress_spec.rb +2 -2
  65. data/spec/moneta/adapters/mongo/adapter_mongo_moped_spec.rb +4 -3
  66. data/spec/moneta/adapters/mongo/adapter_mongo_moped_with_default_expires_spec.rb +5 -3
  67. data/spec/moneta/adapters/mongo/adapter_mongo_official_spec.rb +4 -2
  68. data/spec/moneta/adapters/mongo/adapter_mongo_official_with_default_expires_spec.rb +5 -3
  69. data/spec/moneta/adapters/mongo/adapter_mongo_spec.rb +3 -2
  70. data/spec/moneta/adapters/mongo/adapter_mongo_with_default_expires_spec.rb +5 -3
  71. data/spec/moneta/adapters/mongo/standard_mongo_moped_spec.rb +2 -2
  72. data/spec/moneta/adapters/mongo/standard_mongo_official_spec.rb +2 -2
  73. data/spec/moneta/adapters/mongo/standard_mongo_spec.rb +2 -2
  74. data/spec/moneta/adapters/pstore/standard_pstore_spec.rb +1 -1
  75. data/spec/moneta/adapters/pstore/standard_pstore_with_expires_spec.rb +1 -1
  76. data/spec/moneta/adapters/redis/standard_redis_spec.rb +1 -1
  77. data/spec/moneta/adapters/sdbm/standard_sdbm_spec.rb +1 -1
  78. data/spec/moneta/adapters/sdbm/standard_sdbm_with_expires_spec.rb +1 -1
  79. data/spec/moneta/adapters/sequel/standard_sequel_spec.rb +1 -1
  80. data/spec/moneta/adapters/sequel/standard_sequel_with_expires_spec.rb +1 -1
  81. data/spec/moneta/adapters/sqlite/standard_sqlite_spec.rb +1 -1
  82. data/spec/moneta/adapters/sqlite/standard_sqlite_with_expires_spec.rb +1 -1
  83. data/spec/moneta/adapters/tdb/standard_tdb_spec.rb +1 -1
  84. data/spec/moneta/adapters/tdb/standard_tdb_with_expires_spec.rb +1 -1
  85. data/spec/moneta/adapters/tokyocabinet/standard_tokyocabinet_spec.rb +1 -1
  86. data/spec/moneta/adapters/tokyocabinet/standard_tokyocabinet_with_expires_spec.rb +1 -1
  87. data/spec/moneta/adapters/yaml/standard_yaml_spec.rb +1 -1
  88. data/spec/moneta/adapters/yaml/standard_yaml_with_expires_spec.rb +1 -1
  89. data/spec/moneta/builder_spec.rb +22 -0
  90. data/spec/moneta/proxies/expires/expires_file_spec.rb +1 -1
  91. data/spec/moneta/proxies/shared/shared_tcp_spec.rb +14 -4
  92. data/spec/moneta/proxies/shared/shared_unix_spec.rb +4 -4
  93. data/spec/moneta/proxies/transformer/transformer_bencode_spec.rb +1 -1
  94. data/spec/moneta/proxies/transformer/transformer_bert_spec.rb +3 -3
  95. data/spec/moneta/proxies/transformer/transformer_bson_spec.rb +2 -2
  96. data/spec/moneta/proxies/transformer/transformer_json_spec.rb +1 -1
  97. data/spec/moneta/proxies/transformer/transformer_key_marshal_spec.rb +1 -1
  98. data/spec/moneta/proxies/transformer/transformer_key_yaml_spec.rb +1 -1
  99. data/spec/moneta/proxies/transformer/transformer_marshal_base64_spec.rb +1 -1
  100. data/spec/moneta/proxies/transformer/transformer_marshal_escape_spec.rb +1 -1
  101. data/spec/moneta/proxies/transformer/transformer_marshal_hex_spec.rb +1 -1
  102. data/spec/moneta/proxies/transformer/transformer_marshal_hmac_spec.rb +1 -1
  103. data/spec/moneta/proxies/transformer/transformer_marshal_prefix_base64_spec.rb +33 -0
  104. data/spec/moneta/proxies/transformer/transformer_marshal_prefix_spec.rb +1 -1
  105. data/spec/moneta/proxies/transformer/transformer_marshal_qp_spec.rb +1 -1
  106. data/spec/moneta/proxies/transformer/transformer_marshal_spec.rb +1 -1
  107. data/spec/moneta/proxies/transformer/transformer_marshal_urlsafe_base64_spec.rb +1 -1
  108. data/spec/moneta/proxies/transformer/transformer_marshal_uuencode_spec.rb +1 -1
  109. data/spec/moneta/proxies/transformer/transformer_msgpack_spec.rb +1 -1
  110. data/spec/moneta/proxies/transformer/transformer_ox_spec.rb +1 -1
  111. data/spec/moneta/proxies/transformer/transformer_php_spec.rb +1 -1
  112. data/spec/moneta/proxies/transformer/transformer_tnet_spec.rb +1 -1
  113. data/spec/moneta/proxies/transformer/transformer_yaml_spec.rb +2 -2
  114. data/spec/moneta/proxies/weak_each_key/weak_each_key_spec.rb +0 -2
  115. data/spec/support/mongo_helper.rb +12 -0
  116. metadata +18 -12
  117. data/script/reconfigure-couchdb +0 -13
data/lib/moneta/shared.rb CHANGED
@@ -11,8 +11,6 @@ module Moneta
11
11
  #
12
12
  # @api public
13
13
  class Shared < Wrapper
14
- not_supports :each_key
15
-
16
14
  # @param [Hash] options
17
15
  # @option options [Integer] :port (9000) TCP port
18
16
  # @option options [String] :host Server hostname
@@ -25,7 +23,7 @@ module Moneta
25
23
 
26
24
  # (see Proxy#close)
27
25
  def close
28
- if @server
26
+ if server?
29
27
  @server.stop
30
28
  @thread.join
31
29
  @server = @thread = nil
@@ -36,13 +34,20 @@ module Moneta
36
34
  end
37
35
  end
38
36
 
37
+ # Returns true if this wrapper is running as the server
38
+ #
39
+ # @return [Boolean] wrapper is a server
40
+ def server?
41
+ @server != nil
42
+ end
43
+
39
44
  protected
40
45
 
41
46
  def wrap(*args)
42
47
  connect
43
48
  yield
44
49
  rescue Errno::ECONNRESET, Errno::EPIPE, IOError, SystemCallError
45
- @connect_lock.synchronize { close unless @server }
50
+ @connect_lock.synchronize { close unless server? }
46
51
  tries ||= 0
47
52
  (tries += 1) < 3 ? retry : raise
48
53
  end
@@ -52,21 +57,22 @@ module Moneta
52
57
  @connect_lock.synchronize do
53
58
  @adapter ||= Adapters::Client.new(@options)
54
59
  end
55
- rescue Errno::ECONNREFUSED, Errno::ENOENT => ex
60
+ rescue Errno::ECONNREFUSED, Errno::ENOENT, IOError => ex
56
61
  start_server
57
62
  tries ||= 0
58
63
  warn "Moneta::Shared - Failed to connect: #{ex.message}" if tries > 0
59
- (tries += 1) < 3 ? retry : raise
64
+ (tries += 1) < 10 ? retry : raise
60
65
  end
61
66
 
62
67
  # TODO: Implement this using forking (MRI) and threading (JRuby)
63
68
  # to get maximal performance
64
69
  def start_server
65
70
  @connect_lock.synchronize do
71
+ return if server?
66
72
  begin
67
73
  raise "Adapter already set" if @adapter
68
74
  @adapter = Lock.new(@builder.build.last)
69
- raise "Server already set" if @server
75
+ raise "Server already set" if server?
70
76
  @server = Server.new(@adapter, @options)
71
77
  @thread = Thread.new { @server.run }
72
78
  sleep 0.1 until @server.running?
@@ -43,12 +43,15 @@ module Moneta
43
43
 
44
44
  def compile(keys, values)
45
45
  @key_validator ||= compile_validator(KEY_TRANSFORMER)
46
+ @load_key_validator ||= compile_validator(LOAD_KEY_TRANSFORMER)
47
+ @test_key_validator ||= compile_validator(TEST_KEY_TRANSFORMER)
46
48
  @value_validator ||= compile_validator(VALUE_TRANSFORMER)
47
49
 
48
50
  raise ArgumentError, 'Invalid key transformer chain' if @key_validator !~ keys.map(&:inspect).join
49
51
  raise ArgumentError, 'Invalid value transformer chain' if @value_validator !~ values.map(&:inspect).join
50
52
 
51
53
  klass = Class.new(self)
54
+ compile_each_key_support_clause(klass, keys)
52
55
  klass.class_eval <<-END_EVAL, __FILE__, __LINE__ + 1
53
56
  def initialize(adapter, options = {})
54
57
  super
@@ -58,15 +61,17 @@ module Moneta
58
61
  END_EVAL
59
62
 
60
63
  key, key_opts = compile_transformer(keys, 'key')
64
+ key_load, key_load_opts = compile_transformer(keys.reverse, 'key', 1) if @load_key_validator =~ keys.map(&:inspect).join
65
+ key_test, key_test_opts = compile_transformer(keys.reverse, 'key', 4) if @test_key_validator =~ keys.map(&:inspect).join
61
66
  dump, dump_opts = compile_transformer(values, 'value')
62
67
  load, load_opts = compile_transformer(values.reverse, 'value', 1)
63
68
 
64
69
  if values.empty?
65
- compile_key_transformer(klass, key, key_opts)
70
+ compile_key_transformer(klass, key, key_opts, key_load, key_load_opts, key_test, key_test_opts)
66
71
  elsif keys.empty?
67
72
  compile_value_transformer(klass, load, load_opts, dump, dump_opts)
68
73
  else
69
- compile_key_value_transformer(klass, key, key_opts, load, load_opts, dump, dump_opts)
74
+ compile_key_value_transformer(klass, key, key_opts, key_load, key_load_opts, key_test, key_test_opts, load, load_opts, dump, dump_opts)
70
75
  end
71
76
 
72
77
  klass
@@ -77,13 +82,28 @@ module Moneta
77
82
  options.empty? ? 'options' : "Utils.without(options, #{options.map(&:to_sym).map(&:inspect).join(', ')})"
78
83
  end
79
84
 
80
- def compile_key_transformer(klass, key, key_opts)
85
+ def compile_each_key_support_clause(klass, keys)
81
86
  klass.class_eval <<-END_EVAL, __FILE__, __LINE__ + 1
82
- not_supports :each_key
87
+ #{'not_supports :each_key' if @load_key_validator !~ keys.map(&:inspect).join}
88
+ END_EVAL
89
+ end
90
+
91
+ def compile_key_transformer(klass, key, key_opts, key_load, key_load_opts, key_test, key_test_opts)
92
+ if_key_test = key_load && key_test ? "if #{key_test}" : ''
83
93
 
94
+ klass.class_eval <<-END_EVAL, __FILE__, __LINE__ + 1
84
95
  def key?(key, options = {})
85
96
  @adapter.key?(#{key}, #{without key_opts})
86
97
  end
98
+ def each_key(&block)
99
+ raise NotImplementedError, "each_key is not supported on this transformer" \
100
+ unless supports? :each_key
101
+
102
+ return enum_for(:each_key) unless block_given?
103
+ @adapter.each_key.lazy.map{ |key| #{key_load} #{if_key_test} }.reject(&:nil?).each(&block)
104
+
105
+ self
106
+ end
87
107
  def increment(key, amount = 1, options = {})
88
108
  @adapter.increment(#{key}, amount, #{without key_opts})
89
109
  end
@@ -200,13 +220,22 @@ module Moneta
200
220
  END_EVAL
201
221
  end
202
222
 
203
- def compile_key_value_transformer(klass, key, key_opts, load, load_opts, dump, dump_opts)
204
- klass.class_eval <<-END_EVAL, __FILE__, __LINE__ + 1
205
- not_supports :each_key
223
+ def compile_key_value_transformer(klass, key, key_opts, key_load, key_load_opts, key_test, key_test_opts, load, load_opts, dump, dump_opts)
224
+ if_key_test = key_load && key_test ? "if #{key_test}" : ''
206
225
 
226
+ klass.class_eval <<-END_EVAL, __FILE__, __LINE__ + 1
207
227
  def key?(key, options = {})
208
228
  @adapter.key?(#{key}, #{without key_opts})
209
229
  end
230
+ def each_key(&block)
231
+ raise NotImplementedError, "each_key is not supported on this transformer" \
232
+ unless supports? :each_key
233
+
234
+ return enum_for(:each_key) { @adapter.each_key.size } unless block_given?
235
+ @adapter.each_key.lazy.map{ |key| #{key_load} #{if_key_test} }.reject(&:nil?).each(&block)
236
+
237
+ self
238
+ end
210
239
  def increment(key, amount = 1, options = {})
211
240
  @adapter.increment(#{key}, amount, #{without key_opts})
212
241
  end
@@ -320,9 +349,15 @@ module Moneta
320
349
  raise ArgumentError, "Unknown transformer #{name}" unless t = TRANSFORMER[name]
321
350
  require t[3] if t[3]
322
351
  code = t[idx]
352
+ code ||= compile_prefix(name: name, transformer: t, value: value) if idx == 4 && var == 'key'
353
+
354
+ raise "Undefined command for transformer #{name}" unless code
355
+
323
356
  options += code.scan(/options\[:(\w+)\]/).flatten
324
357
  value =
325
- if t[0] == :serialize && var == 'key'
358
+ if t[0] == :serialize && var == 'key' && idx == 4
359
+ "(tmp = #{value}; (false === tmp || '' === tmp) ? false : #{code % 'tmp'})"
360
+ elsif t[0] == :serialize && var == 'key'
326
361
  "(tmp = #{value}; String === tmp ? tmp : #{code % 'tmp'})"
327
362
  else
328
363
  code % value
@@ -336,6 +371,13 @@ module Moneta
336
371
  (keys.empty? ? '' : keys.map(&camel_case).join + 'Key') +
337
372
  (values.empty? ? '' : values.map(&camel_case).join + 'Value')
338
373
  end
374
+
375
+ def compile_prefix(name:, transformer:, value:)
376
+ return unless [:encode, :serialize].include?(transformer[0])
377
+
378
+ load_val, = compile_transformer([name], value, 1)
379
+ "(#{load_val} rescue '')"
380
+ end
339
381
  end
340
382
  end
341
383
  end
@@ -2,48 +2,61 @@ 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, 'Helper::BSON.load(%s)', 'Helper::BSON.dump(%s)', 'bson' ],
9
- json: [ :serialize, '::MultiJson.load(%s)', '::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
- php: [ :serialize, '::PHP.unserialize(%s)', '::PHP.serialize(%s)', 'php_serialize' ],
14
- tnet: [ :serialize, '::TNetstring.parse(%s).first', '::TNetstring.dump(%s)', 'tnetstring' ],
15
- yaml: [ :serialize, '::YAML.load(%s)', '::YAML.dump(%s)', 'yaml' ],
16
- bzip2: [ :compress, 'Helper.bunzip2(%s)', 'Helper.bzip2(%s)', 'rbzip2' ],
17
- lz4: [ :compress, '::LZ4.uncompress(%s)', '::LZ4.compress(%s)', 'lz4-ruby' ],
18
- lzma: [ :compress, '::LZMA.decompress(%s)', '::LZMA.compress(%s)', 'lzma' ],
19
- lzo: [ :compress, '::LZO.decompress(%s)', '::LZO.compress(%s)', 'lzoruby' ],
20
- snappy: [ :compress, '::Snappy.inflate(%s)', '::Snappy.deflate(%s)', 'snappy' ],
21
- quicklz: [ :compress, '::QuickLZ.decompress(%s)', '::QuickLZ.compress(%s)', 'qlzruby' ],
22
- zlib: [ :compress, '::Zlib::Inflate.inflate(%s)', '::Zlib::Deflate.deflate(%s)', 'zlib' ],
23
- base64: [ :encode, "%s.unpack('m0').first", "[%s].pack('m0')" ],
5
+ # Name: [ Type, Load, Dump, Library Test ],
6
+ bencode: [ :serialize, '::BEncode.load(%s)', '::BEncode.dump(%s)', 'bencode' ],
7
+ bert: [ :serialize, '::BERT.decode(%s)', '::BERT.encode(%s)', 'bert' ],
8
+ bson: [ :serialize, 'Helper::BSON.load(%s)', 'Helper::BSON.dump(%s)', 'bson' ],
9
+ json: [ :serialize, '::MultiJson.load(%s)', '::MultiJson.dump(%s)', 'multi_json' ],
10
+ marshal: [ :serialize, '::Marshal.load(%s)', '::Marshal.dump(%s)', nil ],
11
+ msgpack: [ :serialize, '::MessagePack.unpack(%s)', '::MessagePack.pack(%s)', 'msgpack' ],
12
+ ox: [ :serialize, '::Ox.parse_obj(%s)', '::Ox.dump(%s)', 'ox' ],
13
+ php: [ :serialize, '::PHP.unserialize(%s)', '::PHP.serialize(%s)', 'php_serialize'],
14
+ tnet: [ :serialize, '::TNetstring.parse(%s).first', '::TNetstring.dump(%s)', 'tnetstring' ],
15
+ yaml: [ :serialize, '::YAML.load(%s)', '::YAML.dump(%s)', 'yaml' ],
16
+ bzip2: [ :compress, 'Helper.bunzip2(%s)', 'Helper.bzip2(%s)', 'rbzip2' ],
17
+ lz4: [ :compress, '::LZ4.uncompress(%s)', '::LZ4.compress(%s)', 'lz4-ruby' ],
18
+ lzma: [ :compress, '::LZMA.decompress(%s)', '::LZMA.compress(%s)', 'lzma' ],
19
+ lzo: [ :compress, '::LZO.decompress(%s)', '::LZO.compress(%s)', 'lzoruby' ],
20
+ snappy: [ :compress, '::Snappy.inflate(%s)', '::Snappy.deflate(%s)', 'snappy' ],
21
+ quicklz: [ :compress, '::QuickLZ.decompress(%s)', '::QuickLZ.compress(%s)', 'qlzruby' ],
22
+ zlib: [ :compress, '::Zlib::Inflate.inflate(%s)', '::Zlib::Deflate.deflate(%s)', 'zlib' ],
23
+ base64: [ :encode, "%s.unpack('m0').first", "[%s].pack('m0')" ],
24
24
  urlsafe_base64: [
25
- :encode, 'Base64.urlsafe_decode64(%s)', 'Base64.urlsafe_encode64(%s)', 'base64'
25
+ :encode,
26
+ 'Base64.urlsafe_decode64(%s)',
27
+ 'Base64.urlsafe_encode64(%s)',
28
+ 'base64'
26
29
  ],
27
- escape: [ :encode, 'Helper.unescape(%s)', 'Helper.escape(%s)' ],
28
- hex: [ :encode, "[%s].pack('H*')", "%s.unpack('H*').first" ],
29
- qp: [ :encode, "%s.unpack('M').first", "[%s].pack('M')" ],
30
- uuencode: [ :encode, "%s.unpack('u').first", "[%s].pack('u')" ],
31
- hmac: [ :hmac, 'Helper.hmacverify(%s, options[:secret] || @secret)',
32
- 'Helper.hmacsign(%s, options[:secret] || @secret)', 'openssl' ],
33
- truncate: [ :truncate, nil, 'Helper.truncate(%s, @maxlen)', 'digest/md5' ],
34
- md5: [ :digest, nil, '::Digest::MD5.hexdigest(%s)', 'digest/md5' ],
35
- rmd160: [ :digest, nil, '::Digest::RMD160.hexdigest(%s)', 'digest/rmd160' ],
36
- sha1: [ :digest, nil, '::Digest::SHA1.hexdigest(%s)', 'digest/sha1' ],
37
- sha256: [ :digest, nil, '::Digest::SHA256.hexdigest(%s)', 'digest/sha2' ],
38
- sha384: [ :digest, nil, '::Digest::SHA384.hexdigest(%s)', 'digest/sha2' ],
39
- sha512: [ :digest, nil, '::Digest::SHA512.hexdigest(%s)', 'digest/sha2' ],
40
- city32: [ :digest, nil, '::CityHash.hash32(%s).to_s(16)', 'cityhash' ],
41
- city64: [ :digest, nil, '::CityHash.hash64(%s).to_s(16)', 'cityhash' ],
42
- city128: [ :digest, nil, '::CityHash.hash128(%s).to_s(16)', 'cityhash' ],
43
- prefix: [ :prefix, nil, '(options[:prefix] || @prefix)+%s' ],
44
- spread: [ :spread, nil, 'Helper.spread(%s)' ],
45
- to_s: [ :string, nil, '%s.to_s' ],
46
- inspect: [ :string, nil, '%s.inspect' ]
30
+ escape: [ :encode, 'Helper.unescape(%s)', 'Helper.escape(%s)' ],
31
+ hex: [ :encode, "[%s].pack('H*')", "%s.unpack('H*').first" ],
32
+ qp: [ :encode, "%s.unpack('M').first", "[%s].pack('M')" ],
33
+ uuencode: [ :encode, "%s.unpack('u').first", "[%s].pack('u')" ],
34
+ hmac: [
35
+ :hmac,
36
+ 'Helper.hmacverify(%s, options[:secret] || @secret)',
37
+ 'Helper.hmacsign(%s, options[:secret] || @secret)',
38
+ 'openssl'
39
+ ],
40
+ prefix: [
41
+ :prefix,
42
+ "%s.sub(@prefix, '')",
43
+ '(options[:prefix] || @prefix)+%s',
44
+ nil,
45
+ "%s.start_with?(@prefix)"
46
+ ],
47
+ truncate: [ :truncate, nil, 'Helper.truncate(%s, @maxlen)', 'digest/md5' ],
48
+ md5: [ :digest, nil, '::Digest::MD5.hexdigest(%s)', 'digest/md5' ],
49
+ rmd160: [ :digest, nil, '::Digest::RMD160.hexdigest(%s)', 'digest/rmd160'],
50
+ sha1: [ :digest, nil, '::Digest::SHA1.hexdigest(%s)', 'digest/sha1' ],
51
+ sha256: [ :digest, nil, '::Digest::SHA256.hexdigest(%s)', 'digest/sha2' ],
52
+ sha384: [ :digest, nil, '::Digest::SHA384.hexdigest(%s)', 'digest/sha2' ],
53
+ sha512: [ :digest, nil, '::Digest::SHA512.hexdigest(%s)', 'digest/sha2' ],
54
+ city32: [ :digest, nil, '::CityHash.hash32(%s).to_s(16)', 'cityhash' ],
55
+ city64: [ :digest, nil, '::CityHash.hash64(%s).to_s(16)', 'cityhash' ],
56
+ city128: [ :digest, nil, '::CityHash.hash128(%s).to_s(16)', 'cityhash' ],
57
+ spread: [ :spread, nil, 'Helper.spread(%s)' ],
58
+ to_s: [ :string, nil, '%s.to_s' ],
59
+ inspect: [ :string, nil, '%s.inspect' ]
47
60
  }.freeze
48
61
 
49
62
  # Allowed value transformers (Read it like a regular expression!)
@@ -51,5 +64,11 @@ module Moneta
51
64
 
52
65
  # Allowed key transformers (Read it like a regular expression!)
53
66
  KEY_TRANSFORMER = '(serialize | string)? prefix? ((encode? truncate?) | (digest spread?))?'.freeze
67
+
68
+ # Key transformers that can be "loaded" (e.g. reversed) and can be used by the key enumeration feature
69
+ LOAD_KEY_TRANSFORMER = 'serialize? prefix? encode?'.freeze
70
+
71
+ # Key transformers that can be "tested for success" with a dumped key and can be used by the key enumeration feature
72
+ TEST_KEY_TRANSFORMER = 'serialize? prefix? encode?'.freeze
54
73
  end
55
74
  end
@@ -1,5 +1,5 @@
1
1
  module Moneta
2
2
  # Moneta version number
3
3
  # @api public
4
- VERSION = '1.2.1'.freeze
4
+ VERSION = '1.3.0'.freeze
5
5
  end
data/moneta.gemspec CHANGED
@@ -25,7 +25,7 @@ Gem::Specification.new do |s|
25
25
  'source_code_uri' => "https://github.com/moneta-rb/moneta/tree/v#{s.version}",
26
26
  }
27
27
 
28
- s.required_ruby_version = '>= 2.2.2'
28
+ s.required_ruby_version = '>= 2.3.0'
29
29
 
30
30
  s.add_development_dependency 'rspec', '~> 3.0'
31
31
  s.add_development_dependency 'rspec-retry', '~> 0.6.1'
@@ -33,5 +33,5 @@ Gem::Specification.new do |s|
33
33
  s.add_development_dependency 'parallel_tests', '~> 2.29.2'
34
34
  s.add_development_dependency 'timecop', '~> 0.9.1'
35
35
  s.add_development_dependency 'rubocop', '~> 0.67.2'
36
- s.add_development_dependency 'irb', '~> 1.0.0'
36
+ s.add_development_dependency 'irb', '1.2.1'
37
37
  end
data/script/benchmarks CHANGED
@@ -36,6 +36,9 @@ class MonetaBenchmarks
36
36
  postgres_database1 = ENV['MONETA_POSTGRES_DATABSASE1'] || 'moneta1'
37
37
  postgres_database2 = ENV['MONETA_POSTGRES_DATABSASE1'] || 'moneta2'
38
38
 
39
+ couch_login = ENV['COUCH_LOGIN'] || 'admin'
40
+ couch_password = ENV['COUCH_PASSWORD'] || 'password'
41
+
39
42
  STORES = [
40
43
  # SDBM accepts only very short key/value pairs (1k for both)
41
44
  {name: "SDBM", sizes: [:small], options: {file: "#{DIR}/sdbm"}},
@@ -112,7 +115,9 @@ class MonetaBenchmarks
112
115
  backend: if defined?(JRUBY_VERSION)
113
116
  require 'faraday/adapter/manticore'
114
117
  ::Faraday.new("http://127.0.0.1:5984/moneta") { |f| f.adapter :manticore }
115
- end
118
+ end,
119
+ login: couch_login,
120
+ password: couch_password
116
121
  },
117
122
  clear_options: { compact: true, await_compact: true },
118
123
  },
data/script/contributors CHANGED
@@ -2,7 +2,6 @@
2
2
  git log --format='%aN <%aE>' |\
3
3
  sed -e 's/hiddenbek/Scott Wadden/g' |\
4
4
  sed -e 's/Asmod4n/Hendrik Beskow/' |\
5
- sed -e 's/asppsa@gmail.com/me@asph.dev/' |\
6
- grep -v 'hannes.georg@xing.com\|spotapov\|yehuda-katzs-mac\|wycats ' |\
5
+ grep -v 'asppsa@gmail.com\|hannes.georg@xing.com\|spotapov\|yehuda-katzs-mac\|wycats ' |\
7
6
  sort -u | sort > CONTRIBUTORS
8
7
 
@@ -0,0 +1,27 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ # Copied from https://github.com/apache/couchdb-pkg/blob/master/debian/README.Debian
5
+ COUCHDB_PASSWORD=password
6
+ echo "couchdb couchdb/mode select standalone
7
+ couchdb couchdb/mode seen true
8
+ couchdb couchdb/bindaddress string 127.0.0.1
9
+ couchdb couchdb/bindaddress seen true
10
+ couchdb couchdb/adminpass password ${COUCHDB_PASSWORD}
11
+ couchdb couchdb/adminpass seen true
12
+ couchdb couchdb/adminpass_again password ${COUCHDB_PASSWORD}
13
+ couchdb couchdb/adminpass_again seen true" | sudo debconf-set-selections
14
+ DEBIAN_FRONTEND=noninteractive sudo apt-get install -y --force-yes couchdb
15
+
16
+ # Reconfigure CouchDB to use delayed commits for speed: http://guide.couchdb.org/draft/performance.html
17
+ sudo sed -i '/\[couchdb\]/a delayed_commits = true' /etc/couchdb/local.ini
18
+
19
+ # (Re)start couchdb
20
+ sudo systemctl restart couchdb
21
+
22
+ # Display some info about CouchDB
23
+ sudo systemctl status couchdb
24
+ until curl http://localhost:5984/; do
25
+ sleep 1
26
+ done
27
+
data/script/start-hbase CHANGED
@@ -8,13 +8,13 @@ mkdir -p zookeeper
8
8
  mkdir -p downloads
9
9
  root=$(pwd)
10
10
 
11
- version=$(curl -sS https://www-us.apache.org/dist/hbase/stable/ | grep -oP '(?<=hbase-)(\d+\.?)+' | head -n1)
11
+ version=$(curl -sS https://downloads.apache.org/hbase/stable/RELEASENOTES.md | grep -oP '(?<=# HBASE\s\s)(\d+\.?)+' | head -n1)
12
12
 
13
13
  echo HBase stable version is $version
14
14
 
15
15
  if [ ! -f downloads/hbase-$version-bin.tar.gz ]; then
16
16
  echo Downloading HBase ...
17
- wget -P downloads http://www-us.apache.org/dist/hbase/stable/hbase-$version-bin.tar.gz
17
+ wget -P downloads https://downloads.apache.org/hbase/stable/hbase-$version-bin.tar.gz
18
18
  fi
19
19
 
20
20
  echo Extracting HBase ...
@@ -1,9 +1,9 @@
1
1
  #!/bin/bash
2
2
 
3
- # Restart CouchDB
4
- $(dirname $0)/reconfigure-couchdb
3
+ # Install and start CouchDB
4
+ $(dirname $0)/start-couchdb
5
5
 
6
- # Start HBase
6
+ # Install and start HBase
7
7
  $(dirname $0)/start-hbase
8
8
 
9
9
  # Waiting for servers to start
@@ -178,7 +178,7 @@ shared_examples :store do
178
178
  shared_examples :merge! do
179
179
  it 'stores values' do
180
180
  moneta_property_of(keys: 3, values: 3).check do |keys:, values:|
181
- expect(store.public_send(method, pairs.call(keys[0] => values[0], keys[1] => values[1], keys[2] => values[2]))).to be store
181
+ expect(store.public_send(method, pairs.call({ keys[0] => values[0], keys[1] => values[1], keys[2] => values[2] }))).to be store
182
182
  expect(store.key?(keys[0])).to be true
183
183
  expect(store[keys[0]]).to eq values[0]
184
184
  expect(store.key?(keys[1])).to be true
@@ -192,7 +192,7 @@ shared_examples :store do
192
192
  it 'overwrites existing values' do
193
193
  moneta_property_of(keys: 2, values: 3).check do |keys:, values:|
194
194
  expect(store[keys[0]] = values[0]).to eq values[0]
195
- expect(store.public_send(method, pairs.call(keys[0] => values[1], keys[1] => values[2]))).to be store
195
+ expect(store.public_send(method, pairs.call({ keys[0] => values[1], keys[1] => values[2] }))).to be store
196
196
  expect(store.key?(keys[0])).to be true
197
197
  expect(store[keys[0]]).to eq values[1]
198
198
  expect(store.key?(keys[1])).to be true
@@ -204,7 +204,7 @@ shared_examples :store do
204
204
  it 'stores the return value of the block, if given, for keys that will be overwritten' do
205
205
  moneta_property_of(keys: 2, values: 4).check do |keys:, values:|
206
206
  expect(store[keys[0]] = values[0]).to eq values[0]
207
- expect(store.public_send(method, pairs.call(keys[0] => values[1], keys[1] => values[2])) do |key, old_val, new_val|
207
+ expect(store.public_send(method, pairs.call({ keys[0] => values[1], keys[1] => values[2] })) do |key, old_val, new_val|
208
208
  expect(key).to eq keys[0]
209
209
  expect(old_val).to eq values[0]
210
210
  expect(new_val).to eq values[1]
@@ -1,26 +1,11 @@
1
1
  shared_examples :transform_value do
2
- describe 'with the :raw option' do
3
- it 'can load without transforming the value' do
4
- moneta_property_of(values: 1).check do |values:|
5
- store['key'] = values[0]
6
- load_value(store.load('key', raw: true)).should == values[0]
7
- end
8
- end
9
-
10
- it 'can store without transforming the value' do
11
- moneta_property_of(values: 1).check do |values:|
12
- store['key'] = values[0]
13
- store.store('key', store.load('key', raw: true), raw: true)
14
- store.load('key').should == values[0]
15
- end
16
- end
2
+ it 'allows to bypass transformer with :raw' do
3
+ store['key'] = 'value'
4
+ load_value(store.load('key', raw: true)).should == 'value'
17
5
 
18
- it 'can delete without transforming the value' do
19
- moneta_property_of(values: 1).check do |values:|
20
- store['key'] = values[0]
21
- load_value(store.delete('key', raw: true)).should == values[0]
22
- end
23
- end
6
+ store.store('key', 'value', raw: true)
7
+ store.load('key', raw: true).should == 'value'
8
+ store.delete('key', raw: true).should == 'value'
24
9
  end
25
10
 
26
11
  it 'allows to bypass transformer with raw syntactic sugar' do
@@ -35,4 +20,25 @@ shared_examples :transform_value do
35
20
  store.raw['key'] = 'value2'
36
21
  store.raw['key'].should == 'value2'
37
22
  end
23
+
24
+ it 'returns unmarshalled value' do
25
+ store.store('key', 'unmarshalled value', raw: true)
26
+ store.load('key', raw: true).should == 'unmarshalled value'
27
+ end
28
+
29
+ it 'might raise exception on invalid value' do
30
+ store.store('key', 'unmarshalled value', raw: true)
31
+
32
+ begin
33
+ store['key'].should == load_value('unmarshalled value')
34
+ store.delete('key').should == load_value('unmarshalled value')
35
+ rescue Exception => ex
36
+ expect do
37
+ store['key']
38
+ end.to raise_error
39
+ expect do
40
+ store.delete('key')
41
+ end.to raise_error
42
+ end
43
+ end
38
44
  end