moneta 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +415 -0
  3. data/CHANGES +18 -0
  4. data/CONTRIBUTORS +2 -0
  5. data/Gemfile +144 -56
  6. data/README.md +21 -17
  7. data/lib/moneta/adapter.rb +52 -0
  8. data/lib/moneta/adapters/activerecord.rb +77 -68
  9. data/lib/moneta/adapters/activesupportcache.rb +22 -31
  10. data/lib/moneta/adapters/cassandra.rb +114 -116
  11. data/lib/moneta/adapters/client.rb +17 -18
  12. data/lib/moneta/adapters/couch.rb +31 -26
  13. data/lib/moneta/adapters/datamapper.rb +9 -5
  14. data/lib/moneta/adapters/daybreak.rb +15 -21
  15. data/lib/moneta/adapters/dbm.rb +6 -12
  16. data/lib/moneta/adapters/file.rb +21 -13
  17. data/lib/moneta/adapters/fog.rb +5 -6
  18. data/lib/moneta/adapters/gdbm.rb +6 -12
  19. data/lib/moneta/adapters/hbase.rb +10 -12
  20. data/lib/moneta/adapters/kyotocabinet.rb +22 -27
  21. data/lib/moneta/adapters/leveldb.rb +14 -20
  22. data/lib/moneta/adapters/lmdb.rb +19 -22
  23. data/lib/moneta/adapters/localmemcache.rb +7 -13
  24. data/lib/moneta/adapters/lruhash.rb +20 -20
  25. data/lib/moneta/adapters/memcached/dalli.rb +25 -33
  26. data/lib/moneta/adapters/memcached/native.rb +14 -20
  27. data/lib/moneta/adapters/memory.rb +5 -7
  28. data/lib/moneta/adapters/mongo.rb +59 -50
  29. data/lib/moneta/adapters/pstore.rb +21 -27
  30. data/lib/moneta/adapters/redis.rb +42 -37
  31. data/lib/moneta/adapters/restclient.rb +17 -25
  32. data/lib/moneta/adapters/riak.rb +8 -9
  33. data/lib/moneta/adapters/sdbm.rb +6 -12
  34. data/lib/moneta/adapters/sequel/mysql.rb +8 -8
  35. data/lib/moneta/adapters/sequel/postgres.rb +17 -17
  36. data/lib/moneta/adapters/sequel/postgres_hstore.rb +47 -47
  37. data/lib/moneta/adapters/sequel/sqlite.rb +9 -9
  38. data/lib/moneta/adapters/sequel.rb +56 -65
  39. data/lib/moneta/adapters/sqlite.rb +37 -35
  40. data/lib/moneta/adapters/tdb.rb +8 -14
  41. data/lib/moneta/adapters/tokyocabinet.rb +19 -17
  42. data/lib/moneta/adapters/tokyotyrant.rb +29 -30
  43. data/lib/moneta/adapters/yaml.rb +1 -5
  44. data/lib/moneta/config.rb +101 -0
  45. data/lib/moneta/expires.rb +0 -1
  46. data/lib/moneta/expires_support.rb +3 -4
  47. data/lib/moneta/pool.rb +27 -7
  48. data/lib/moneta/proxy.rb +29 -0
  49. data/lib/moneta/server.rb +21 -14
  50. data/lib/moneta/version.rb +1 -1
  51. data/lib/moneta/wrapper.rb +5 -0
  52. data/lib/moneta.rb +2 -0
  53. data/moneta.gemspec +1 -0
  54. data/spec/active_support/cache_moneta_store_spec.rb +13 -13
  55. data/spec/helper.rb +14 -3
  56. data/spec/moneta/adapters/activerecord/adapter_activerecord_existing_connection_spec.rb +3 -1
  57. data/spec/moneta/adapters/activerecord/adapter_activerecord_spec.rb +15 -7
  58. data/spec/moneta/adapters/activerecord/standard_activerecord_spec.rb +5 -2
  59. data/spec/moneta/adapters/activerecord/standard_activerecord_with_expires_spec.rb +5 -2
  60. data/spec/moneta/adapters/activesupportcache/adapter_activesupportcache_spec.rb +3 -3
  61. data/spec/moneta/adapters/activesupportcache/adapter_activesupportcache_with_default_expires_spec.rb +2 -2
  62. data/spec/moneta/adapters/client/client_helper.rb +4 -3
  63. data/spec/moneta/adapters/datamapper/adapter_datamapper_spec.rb +25 -8
  64. data/spec/moneta/adapters/datamapper/standard_datamapper_spec.rb +2 -2
  65. data/spec/moneta/adapters/datamapper/standard_datamapper_with_expires_spec.rb +2 -2
  66. data/spec/moneta/adapters/datamapper/standard_datamapper_with_repository_spec.rb +2 -2
  67. data/spec/moneta/adapters/faraday_helper.rb +3 -2
  68. data/spec/moneta/adapters/lruhash/adapter_lruhash_spec.rb +10 -6
  69. data/spec/moneta/adapters/memcached/dalli/adapter_memcached_dalli_spec.rb +13 -3
  70. data/spec/moneta/adapters/memcached/native/adapter_memcached_native_spec.rb +13 -3
  71. data/spec/moneta/adapters/mongo/adapter_mongo_spec.rb +17 -3
  72. data/spec/moneta/adapters/mongo/adapter_mongo_with_default_expires_spec.rb +4 -4
  73. data/spec/moneta/adapters/mongo/standard_mongo_spec.rb +1 -1
  74. data/spec/moneta/adapters/redis/adapter_redis_spec.rb +13 -3
  75. data/spec/moneta/adapters/redis/standard_redis_spec.rb +8 -1
  76. data/spec/moneta/adapters/sequel/adapter_sequel_spec.rb +4 -4
  77. data/spec/moneta/adapters/sequel/helper.rb +10 -5
  78. data/spec/moneta/adapters/sequel/standard_sequel_spec.rb +1 -1
  79. data/spec/moneta/adapters/sequel/standard_sequel_with_expires_spec.rb +1 -1
  80. data/spec/moneta/adapters/sqlite/adapter_sqlite_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/config_spec.rb +219 -0
  84. data/spec/moneta/proxies/pool/pool_spec.rb +31 -3
  85. data/spec/moneta/proxies/transformer/transformer_bson_spec.rb +3 -1
  86. data/spec/moneta/proxies/transformer/transformer_marshal_escape_spec.rb +2 -0
  87. data/spec/rack/session_moneta_spec.rb +44 -25
  88. data/spec/restserver.rb +3 -14
  89. metadata +25 -17
  90. data/.travis.yml +0 -146
  91. data/spec/moneta/adapters/memcached/dalli/adapter_memcached_dalli_with_default_expires_spec.rb +0 -15
  92. data/spec/moneta/adapters/memcached/native/adapter_memcached_native_with_default_expires_spec.rb +0 -15
  93. data/spec/moneta/adapters/redis/adapter_redis_with_default_expires_spec.rb +0 -10
  94. data/spec/moneta/proxies/proxy/proxy_redis_spec.rb +0 -13
  95. data/spec/support/mongo_helper.rb +0 -12
@@ -4,14 +4,34 @@ module Moneta
4
4
  module Adapters
5
5
  # Cassandra backend
6
6
  # @api public
7
- class Cassandra
8
- include Defaults
7
+ class Cassandra < Adapter
9
8
  include ExpiresSupport
10
9
 
11
- attr_reader :backend
12
-
13
10
  supports :each_key
14
11
 
12
+ config :table, default: 'moneta'
13
+ config :key_column, default: 'key'
14
+ config :value_column, default: 'value'
15
+ config :updated_column, default: 'updated_at'
16
+ config :expired_column, default: 'expired'
17
+ config :read_consistency, default: :all
18
+ config :write_consistency, default: :all
19
+
20
+ backend do |keyspace: 'moneta', cluster: nil, create_keyspace: nil, **options|
21
+ cluster ||= ::Cassandra.cluster(options).tap do |own_cluster|
22
+ @own_cluster = own_cluster
23
+ end
24
+
25
+ begin
26
+ cluster.connect(keyspace)
27
+ rescue ::Cassandra::Errors::InvalidError
28
+ backend = cluster.connect
29
+ create_keyspace(backend, keyspace, create_keyspace)
30
+ backend.execute("USE " + keyspace)
31
+ backend
32
+ end
33
+ end
34
+
15
35
  # @param [Hash] options
16
36
  # @option options [String] :keyspace ('moneta') Cassandra keyspace
17
37
  # @option options [String] :table ('moneta') Cassandra table
@@ -35,39 +55,17 @@ module Moneta
35
55
  # keyspace does not already exist.
36
56
  # @option options [::Cassandra::Cluster] :cluster Existing cluster to use
37
57
  # @option options [::Cassandra::Session] :backend Existing session to use
38
- # @option options Other options passed to `Cassandra#new`
58
+ # @option options Other options passed to `Cassandra#cluster`
39
59
  def initialize(options = {})
40
- self.default_expires = options.delete(:expires)
41
- keyspace = options.delete(:keyspace) || 'moneta'
42
-
43
- @table = (options.delete(:column_family) || 'moneta').to_sym
44
- @key_column = options.delete(:key_column) || 'key'
45
- @value_column = options.delete(:value_column) || 'value'
46
- @updated_column = options.delete(:updated_column) || 'updated_at'
47
- @expired_column = options.delete(:expired_column) || 'expired'
48
- @read_consistency = options.delete(:read_consistency) || :all
49
- @write_consistency = options.delete(:write_consistency) || :all
50
- @create_keyspace = options.delete(:create_keyspace)
51
-
52
- unless @backend = options.delete(:backend)
53
- cluster = options.delete(:cluster) || (@own_cluster = ::Cassandra.cluster(options))
54
- begin
55
- @backend = cluster.connect(keyspace)
56
- rescue ::Cassandra::Errors::InvalidError
57
- @backend = cluster.connect
58
- create_keyspace(keyspace)
59
- @backend.execute("USE " + keyspace)
60
- @backend
61
- end
62
- end
63
-
64
- @backend.execute <<-CQL
65
- CREATE TABLE IF NOT EXISTS #{@table} (
66
- #{@key_column} blob,
67
- #{@value_column} blob,
68
- #{@updated_column} timeuuid,
69
- #{@expired_column} boolean,
70
- PRIMARY KEY (#{@key_column}, #{@updated_column})
60
+ super
61
+
62
+ backend.execute <<-CQL
63
+ CREATE TABLE IF NOT EXISTS #{config.table} (
64
+ #{config.key_column} blob,
65
+ #{config.value_column} blob,
66
+ #{config.updated_column} timeuuid,
67
+ #{config.expired_column} boolean,
68
+ PRIMARY KEY (#{config.key_column}, #{config.updated_column})
71
69
  )
72
70
  CQL
73
71
 
@@ -82,18 +80,18 @@ module Moneta
82
80
  # whole column, when we want to update the expiry we load the value
83
81
  # and then re-set it in order to update the TTL.
84
82
  return false unless
85
- row = @backend.execute(@load, options.merge(consistency: rc, arguments: [key])).first and
86
- row[@expired_column] != nil
87
- @backend.execute(@update_expires,
88
- options.merge(consistency: wc,
89
- arguments: [(expires || 0).to_i,
90
- timestamp,
91
- row[@value_column],
92
- key,
93
- row[@updated_column]]))
83
+ row = backend.execute(@load, options.merge(consistency: rc, arguments: [key])).first and
84
+ row[config.expired_column] != nil
85
+ backend.execute(@update_expires,
86
+ options.merge(consistency: wc,
87
+ arguments: [(expires || 0).to_i,
88
+ timestamp,
89
+ row[config.value_column],
90
+ key,
91
+ row[config.updated_column]]))
94
92
  true
95
- elsif row = @backend.execute(@key, options.merge(consistency: rc, arguments: [key])).first
96
- row[@expired_column] != nil
93
+ elsif row = backend.execute(@key, options.merge(consistency: rc, arguments: [key])).first
94
+ row[config.expired_column] != nil
97
95
  else
98
96
  false
99
97
  end
@@ -102,17 +100,17 @@ module Moneta
102
100
  # (see Proxy#load)
103
101
  def load(key, options = {})
104
102
  rc, wc = consistency(options)
105
- if row = @backend.execute(@load, options.merge(consistency: rc, arguments: [key])).first and row[@expired_column] != nil
103
+ if row = backend.execute(@load, options.merge(consistency: rc, arguments: [key])).first and row[config.expired_column] != nil
106
104
  if (expires = expires_value(options, nil)) != nil
107
- @backend.execute(@update_expires,
108
- options.merge(consistency: wc,
109
- arguments: [(expires || 0).to_i,
110
- timestamp,
111
- row[@value_column],
112
- key,
113
- row[@updated_column]]))
105
+ backend.execute(@update_expires,
106
+ options.merge(consistency: wc,
107
+ arguments: [(expires || 0).to_i,
108
+ timestamp,
109
+ row[config.value_column],
110
+ key,
111
+ row[config.updated_column]]))
114
112
  end
115
- row[@value_column]
113
+ row[config.value_column]
116
114
  end
117
115
  end
118
116
 
@@ -121,33 +119,33 @@ module Moneta
121
119
  _, wc = consistency(options)
122
120
  expires = expires_value(options)
123
121
  t = timestamp
124
- batch = @backend.batch do |batch|
122
+ batch = backend.batch do |batch|
125
123
  batch.add(@store_delete, arguments: [t, key])
126
124
  batch.add(@store, arguments: [key, value, (expires || 0).to_i, t + 1])
127
125
  end
128
- @backend.execute(batch, options.merge(consistency: wc))
126
+ backend.execute(batch, options.merge(consistency: wc))
129
127
  value
130
128
  end
131
129
 
132
130
  # (see Proxy#delete)
133
131
  def delete(key, options = {})
134
132
  rc, wc = consistency(options)
135
- result = @backend.execute(@delete_value, options.merge(consistency: rc, arguments: [key]))
136
- if row = result.first and row[@expired_column] != nil
137
- @backend.execute(@delete, options.merge(consistency: wc, arguments: [timestamp, key, row[@updated_column]]))
138
- row[@value_column]
133
+ result = backend.execute(@delete_value, options.merge(consistency: rc, arguments: [key]))
134
+ if row = result.first and row[config.expired_column] != nil
135
+ backend.execute(@delete, options.merge(consistency: wc, arguments: [timestamp, key, row[config.updated_column]]))
136
+ row[config.value_column]
139
137
  end
140
138
  end
141
139
 
142
140
  # (see Proxy#clear)
143
141
  def clear(options = {})
144
- @backend.execute(@clear)
142
+ backend.execute(@clear)
145
143
  self
146
144
  end
147
145
 
148
146
  # (see Proxy#close)
149
147
  def close
150
- @backend.close_async
148
+ backend.close_async
151
149
  @backend = nil
152
150
  if @own_cluster
153
151
  @own_cluster.close_async
@@ -160,11 +158,11 @@ module Moneta
160
158
  def each_key
161
159
  rc, = consistency
162
160
  return enum_for(:each_key) unless block_given?
163
- result = @backend.execute(@each_key, consistency: rc, page_size: 100)
161
+ result = backend.execute(@each_key, consistency: rc, page_size: 100)
164
162
  loop do
165
163
  result.each do |row|
166
- next if row[@expired_column] == nil
167
- yield row[@key_column]
164
+ next if row[config.expired_column] == nil
165
+ yield row[config.key_column]
168
166
  end
169
167
 
170
168
  break if result.last_page?
@@ -176,27 +174,27 @@ module Moneta
176
174
  # (see Proxy#slice)
177
175
  def slice(*keys, **options)
178
176
  rc, wc = consistency(options)
179
- result = @backend.execute(@slice, options.merge(consistency: rc, arguments: [keys]))
177
+ result = backend.execute(@slice, options.merge(consistency: rc, arguments: [keys]))
180
178
  expires = expires_value(options, nil)
181
179
  updated = [] if expires != nil
182
180
  pairs = result.map do |row|
183
- next if row[@expired_column] == nil
181
+ next if row[config.expired_column] == nil
184
182
  if expires != nil
185
- updated << [row[@key_column], row[@value_column], row[@updated_column]]
183
+ updated << [row[config.key_column], row[config.value_column], row[config.updated_column]]
186
184
  end
187
- [row[@key_column], row[@value_column]]
185
+ [row[config.key_column], row[config.value_column]]
188
186
  end.compact
189
187
 
190
188
  if expires != nil && !updated.empty?
191
189
  ttl = (expires || 0).to_i
192
190
  t = timestamp
193
- batch = @backend.batch do |batch|
191
+ batch = backend.batch do |batch|
194
192
  updated.each do |key, value, updated|
195
193
  batch.add(@update_expires, arguments: [ttl, t, value, key, updated])
196
194
  end
197
195
  end
198
196
 
199
- @backend.execute(batch, options.merge(consistency: wc))
197
+ backend.execute(batch, options.merge(consistency: wc))
200
198
  end
201
199
 
202
200
  pairs
@@ -240,13 +238,13 @@ module Moneta
240
238
  _rc, wc = consistency(options)
241
239
  expires = expires_value(options)
242
240
  t = timestamp
243
- batch = @backend.batch do |batch|
241
+ batch = backend.batch do |batch|
244
242
  batch.add(@merge_delete, arguments: [t, keys])
245
243
  pairs.each do |key, value|
246
244
  batch.add(@store, arguments: [key, value, (expires || 0).to_i, t + 1])
247
245
  end
248
246
  end
249
- @backend.execute(batch, options.merge(consistency: wc))
247
+ backend.execute(batch, options.merge(consistency: wc))
250
248
 
251
249
  self
252
250
  end
@@ -257,7 +255,7 @@ module Moneta
257
255
  (Time.now.to_r * 1_000_000).to_i
258
256
  end
259
257
 
260
- def create_keyspace(keyspace)
258
+ def create_keyspace(backend, keyspace, create_keyspace)
261
259
  options = {
262
260
  replication: {
263
261
  class: 'SimpleStrategy',
@@ -265,13 +263,13 @@ module Moneta
265
263
  }
266
264
  }
267
265
 
268
- case @create_keyspace
266
+ case create_keyspace
269
267
  when Proc
270
- return @create_keyspace.call(keyspace)
268
+ return create_keyspace.call(keyspace)
271
269
  when false
272
270
  return
273
271
  when Hash
274
- options.merge!(@create_keyspace)
272
+ options.merge!(create_keyspace)
275
273
  end
276
274
 
277
275
  # This is a bit hacky, but works. Options in Cassandra look like JSON,
@@ -281,7 +279,7 @@ module Moneta
281
279
  key.to_s + ' = ' + MultiJson.dump(value).tr(?", ?')
282
280
  end.join(' AND ')
283
281
 
284
- @backend.execute "CREATE KEYSPACE IF NOT EXISTS %<keyspace>s WITH %<options>s" % {
282
+ backend.execute "CREATE KEYSPACE IF NOT EXISTS %<keyspace>s WITH %<options>s" % {
285
283
  keyspace: keyspace,
286
284
  options: option_str
287
285
  }
@@ -291,65 +289,65 @@ module Moneta
291
289
  end
292
290
 
293
291
  def prepare_statements
294
- @key = @backend.prepare(<<-CQL)
295
- SELECT #{@updated_column}, #{@expired_column}
296
- FROM #{@table} WHERE #{@key_column} = ?
292
+ @key = backend.prepare(<<-CQL)
293
+ SELECT #{config.updated_column}, #{config.expired_column}
294
+ FROM #{config.table} WHERE #{config.key_column} = ?
297
295
  LIMIT 1
298
296
  CQL
299
- @store_delete = @backend.prepare(<<-CQL)
300
- DELETE FROM #{@table}
297
+ @store_delete = backend.prepare(<<-CQL)
298
+ DELETE FROM #{config.table}
301
299
  USING TIMESTAMP ?
302
- WHERE #{@key_column} = ?
300
+ WHERE #{config.key_column} = ?
303
301
  CQL
304
- @store = @backend.prepare(<<-CQL)
305
- INSERT INTO #{@table} (#{@key_column}, #{@value_column}, #{@updated_column}, #{@expired_column})
302
+ @store = backend.prepare(<<-CQL)
303
+ INSERT INTO #{config.table} (#{config.key_column}, #{config.value_column}, #{config.updated_column}, #{config.expired_column})
306
304
  VALUES (?, ?, now(), false)
307
305
  USING TTL ? AND TIMESTAMP ?
308
306
  CQL
309
- @load = @backend.prepare(<<-CQL)
310
- SELECT #{@value_column}, #{@updated_column}, #{@expired_column}
311
- FROM #{@table}
312
- WHERE #{@key_column} = ?
307
+ @load = backend.prepare(<<-CQL)
308
+ SELECT #{config.value_column}, #{config.updated_column}, #{config.expired_column}
309
+ FROM #{config.table}
310
+ WHERE #{config.key_column} = ?
313
311
  LIMIT 1
314
312
  CQL
315
- @update_expires = @backend.prepare(<<-CQL)
316
- UPDATE #{@table}
313
+ @update_expires = backend.prepare(<<-CQL)
314
+ UPDATE #{config.table}
317
315
  USING TTL ? AND TIMESTAMP ?
318
- SET #{@value_column} = ?, #{@expired_column} = false
319
- WHERE #{@key_column} = ? AND #{@updated_column} = ?
316
+ SET #{config.value_column} = ?, #{config.expired_column} = false
317
+ WHERE #{config.key_column} = ? AND #{config.updated_column} = ?
320
318
  CQL
321
- @clear = @backend.prepare("TRUNCATE #{@table}")
322
- @delete_value = @backend.prepare(<<-CQL)
323
- SELECT #{@value_column}, #{@updated_column}, #{@expired_column}
324
- FROM #{@table}
325
- WHERE #{@key_column} = ?
319
+ @clear = backend.prepare("TRUNCATE #{config.table}")
320
+ @delete_value = backend.prepare(<<-CQL)
321
+ SELECT #{config.value_column}, #{config.updated_column}, #{config.expired_column}
322
+ FROM #{config.table}
323
+ WHERE #{config.key_column} = ?
326
324
  LIMIT 1
327
325
  CQL
328
- @delete = @backend.prepare(<<-CQL, idempotent: true)
329
- DELETE FROM #{@table}
326
+ @delete = backend.prepare(<<-CQL, idempotent: true)
327
+ DELETE FROM #{config.table}
330
328
  USING TIMESTAMP ?
331
- WHERE #{@key_column} = ? AND #{@updated_column} = ?
329
+ WHERE #{config.key_column} = ? AND #{config.updated_column} = ?
332
330
  CQL
333
- @each_key = @backend.prepare(<<-CQL)
334
- SELECT #{@key_column}, #{@expired_column}
335
- FROM #{@table}
331
+ @each_key = backend.prepare(<<-CQL)
332
+ SELECT #{config.key_column}, #{config.expired_column}
333
+ FROM #{config.table}
336
334
  CQL
337
- @slice = @backend.prepare(<<-CQL)
338
- SELECT #{@key_column}, #{@value_column}, #{@updated_column}, #{@expired_column}
339
- FROM #{@table}
340
- WHERE #{@key_column} IN ?
335
+ @slice = backend.prepare(<<-CQL)
336
+ SELECT #{config.key_column}, #{config.value_column}, #{config.updated_column}, #{config.expired_column}
337
+ FROM #{config.table}
338
+ WHERE #{config.key_column} IN ?
341
339
  CQL
342
- @merge_delete = @backend.prepare(<<-CQL)
343
- DELETE FROM #{@table}
340
+ @merge_delete = backend.prepare(<<-CQL)
341
+ DELETE FROM #{config.table}
344
342
  USING TIMESTAMP ?
345
- WHERE #{@key_column} IN ?
343
+ WHERE #{config.key_column} IN ?
346
344
  CQL
347
345
  end
348
346
 
349
347
  def consistency(options = {})
350
348
  [
351
- options[:read_consistency] || @read_consistency,
352
- options[:write_consistency] || @write_consistency
349
+ options[:read_consistency] || config.read_consistency,
350
+ options[:write_consistency] || config.write_consistency
353
351
  ]
354
352
  end
355
353
  end
@@ -4,20 +4,19 @@ module Moneta
4
4
  module Adapters
5
5
  # Moneta client backend
6
6
  # @api public
7
- class Client
8
- include Defaults
9
-
10
- # @param [Hash] options
11
- # @option options [Integer] :port (9000) TCP port
12
- # @option options [String] :host ('127.0.0.1') Hostname
13
- # @option options [String] :socket Unix socket file name as alternative to `:port` and `:host`
14
- def initialize(options = {})
15
- @socket =
16
- if options[:socket]
17
- UNIXSocket.open(options[:socket])
18
- else
19
- TCPSocket.open(options[:host] || '127.0.0.1', options[:port] || 9000)
20
- end
7
+ class Client < Adapter
8
+ # @!method initialize(options = {})
9
+ # @param [Hash] options
10
+ # @option options [TCPSocket | UNIXSocket] :backend an open socket to use
11
+ # @option options [Integer] :port (9000) TCP port
12
+ # @option options [String] :host ('127.0.0.1') Hostname
13
+ # @option options [String] :socket Unix socket file name as alternative to `:port` and `:host`
14
+ backend do |socket: nil, host: '127.0.0.1', port: 9000|
15
+ if socket
16
+ UNIXSocket.open(socket)
17
+ else
18
+ TCPSocket.open(host, port)
19
+ end
21
20
  end
22
21
 
23
22
  # (see Proxy#key?)
@@ -66,7 +65,7 @@ module Moneta
66
65
 
67
66
  # (see Proxy#close)
68
67
  def close
69
- @socket.close
68
+ backend.close
70
69
  nil
71
70
  end
72
71
 
@@ -114,19 +113,19 @@ module Moneta
114
113
 
115
114
  def write(*args)
116
115
  s = Marshal.dump(args)
117
- @socket.write([s.bytesize].pack('N') << s)
116
+ backend.write([s.bytesize].pack('N') << s)
118
117
  end
119
118
 
120
119
  # JRuby doesn't support socket#recv with flags
121
120
  if defined?(JRUBY_VERSION)
122
121
  def read(bytes)
123
- received = @socket.read(bytes)
122
+ received = backend.read(bytes)
124
123
  raise EOFError, "Server closed socket" unless received && received.bytesize == bytes
125
124
  received
126
125
  end
127
126
  else
128
127
  def read(bytes)
129
- received = @socket.recv(bytes, Socket::MSG_WAITALL)
128
+ received = backend.recv(bytes, Socket::MSG_WAITALL)
130
129
  raise EOFError, "Server closed socket" unless received && received.bytesize == bytes
131
130
  received
132
131
  end
@@ -12,9 +12,7 @@ module Moneta
12
12
  # db['key'] = {a: 1, b: 2}
13
13
  #
14
14
  # @api public
15
- class Couch
16
- include Defaults
17
-
15
+ class Couch < Adapter
18
16
  # @api private
19
17
  class HTTPError < StandardError
20
18
  attr_reader :status, :request_method, :key
@@ -28,10 +26,21 @@ module Moneta
28
26
  end
29
27
  end
30
28
 
31
- attr_reader :backend
32
-
33
29
  supports :create, :each_key
34
30
 
31
+ config :value_field, default: 'value'
32
+ config :type_field, default: 'type'
33
+ config :login
34
+ config :password
35
+ config :adapter
36
+ config :skip_create_db
37
+
38
+ backend do |scheme: 'http', host: '127.0.0.1', port: 5984, db: 'moneta', adapter: nil, **options|
39
+ ::Faraday.new "#{scheme}://#{host}:#{port}/#{db}", options do |faraday|
40
+ faraday.adapter adapter if adapter
41
+ end
42
+ end
43
+
35
44
  # @param [Hash] options
36
45
  # @option options [String] :host ('127.0.0.1') Couch host
37
46
  # @option options [String] :port (5984) Couch port
@@ -46,26 +55,22 @@ module Moneta
46
55
  # @option options Other options passed to {Faraday::new} (unless
47
56
  # :backend option is provided).
48
57
  def initialize(options = {})
49
- @value_field = options.delete(:value_field) || 'value'
50
- @type_field = options.delete(:type_field) || 'type'
51
- login = options.delete(:login)
52
- password = options.delete(:password)
53
- @backend = options.delete(:backend) || begin
54
- host = options.delete(:host) || '127.0.0.1'
55
- port = options.delete(:port) || 5984
56
- db = options.delete(:db) || 'moneta'
57
- scheme = options.delete(:scheme) || 'http'
58
- block = if faraday_adapter = options.delete(:adapter)
59
- proc { |faraday| faraday.adapter(faraday_adapter) }
60
- end
61
- ::Faraday.new("#{scheme}://#{host}:#{port}/#{db}", options, &block)
58
+ super
59
+
60
+ if config.login && config.password
61
+ # Faraday 1.x had a `basic_auth` function
62
+ if backend.respond_to? :basic_auth
63
+ backend.basic_auth(config.login, config.password)
64
+ else
65
+ backend.request :authorization, :basic, config.login, config.password
66
+ end
62
67
  end
63
- @backend.basic_auth(login, password) if login && password
68
+
64
69
  @rev_cache = Moneta.build do
65
70
  use :Lock
66
71
  adapter :LRUHash
67
72
  end
68
- create_db
73
+ create_db unless config.skip_create_db
69
74
  end
70
75
 
71
76
  # (see Proxy#key?)
@@ -278,15 +283,15 @@ module Moneta
278
283
  end
279
284
 
280
285
  def doc_to_value(doc)
281
- case doc[@type_field]
286
+ case doc[config.type_field]
282
287
  when 'Hash'
283
288
  doc = doc.dup
284
289
  doc.delete('_id')
285
290
  doc.delete('_rev')
286
- doc.delete(@type_field)
291
+ doc.delete(config.type_field)
287
292
  doc
288
293
  else
289
- doc[@value_field]
294
+ doc[config.value_field]
290
295
  end
291
296
  end
292
297
 
@@ -294,11 +299,11 @@ module Moneta
294
299
  doc =
295
300
  case value
296
301
  when Hash
297
- value.merge(@type_field => 'Hash')
302
+ value.merge(config.type_field => 'Hash')
298
303
  when String
299
- { @value_field => value, @type_field => 'String' }
304
+ { config.value_field => value, config.type_field => 'String' }
300
305
  when Float, Integer
301
- { @value_field => value, @type_field => 'Number' }
306
+ { config.value_field => value, config.type_field => 'Number' }
302
307
  else
303
308
  raise ArgumentError, "Invalid value type: #{value.class}"
304
309
  end
@@ -7,6 +7,7 @@ module Moneta
7
7
  # @api public
8
8
  class DataMapper
9
9
  include Defaults
10
+ include Config
10
11
  include NilValues
11
12
 
12
13
  supports :create
@@ -19,15 +20,18 @@ module Moneta
19
20
  self.raise_on_save_failure = true
20
21
  end
21
22
 
23
+ config :setup, required: true
24
+ config :repository, default: :moneta, coerce: :to_sym
25
+ config :table, default: :moneta, coerce: :to_sym
26
+
22
27
  # @param [Hash] options
23
28
  # @option options [String] :setup Datamapper setup string
24
29
  # @option options [String/Symbol] :repository (:moneta) Repository name
25
30
  # @option options [String/Symbol] :table (:moneta) Table name
26
31
  def initialize(options = {})
27
- raise ArgumentError, 'Option :setup is required' unless options[:setup]
28
- @repository = (options.delete(:repository) || :moneta).to_sym
29
- Store.storage_names[@repository] = (options.delete(:table) || :moneta).to_s
30
- ::DataMapper.setup(@repository, options[:setup])
32
+ configure(options)
33
+ Store.storage_names[config.repository] = config.table.to_s
34
+ ::DataMapper.setup(config.repository, config.setup)
31
35
  context { Store.auto_upgrade! }
32
36
  end
33
37
 
@@ -91,7 +95,7 @@ module Moneta
91
95
  private
92
96
 
93
97
  def context
94
- ::DataMapper.repository(@repository) { yield }
98
+ ::DataMapper.repository(config.repository) { yield }
95
99
  end
96
100
  end
97
101
  end
@@ -4,58 +4,52 @@ module Moneta
4
4
  module Adapters
5
5
  # Daybreak backend
6
6
  # @api public
7
- class Daybreak
8
- include Defaults
7
+ class Daybreak < Adapter
9
8
  include DBMAdapter
10
9
  include IncrementSupport
11
10
  include CreateSupport
12
11
  include EachKeySupport
13
12
 
14
- # @param [Hash] options
15
- # @option options [String] :file Database file
16
- # @option options [::Daybreak] :backend Use existing backend instance
17
- def initialize(options = {})
18
- @backend = options[:backend] ||
19
- begin
20
- raise ArgumentError, 'Option :file is required' unless options[:file]
21
- ::Daybreak::DB.new(options[:file], serializer: ::Daybreak::Serializer::None)
22
- end
23
- end
13
+ # @!method initialize(options = {})
14
+ # @param [Hash] options
15
+ # @option options [String] :file Database file
16
+ # @option options [::Daybreak] :backend Use existing backend instance
17
+ backend { |file:| ::Daybreak::DB.new(file, serializer: ::Daybreak::Serializer::None) }
24
18
 
25
19
  # (see Proxy#load)
26
20
  def load(key, options = {})
27
- @backend.load if options[:sync]
28
- @backend[key]
21
+ backend.load if options[:sync]
22
+ backend[key]
29
23
  end
30
24
 
31
25
  # (see Proxy#store)
32
26
  def store(key, value, options = {})
33
- @backend[key] = value
34
- @backend.flush if options[:sync]
27
+ backend[key] = value
28
+ backend.flush if options[:sync]
35
29
  value
36
30
  end
37
31
 
38
32
  # (see Proxy#increment)
39
33
  def increment(key, amount = 1, options = {})
40
- @backend.lock { super }
34
+ backend.lock { super }
41
35
  end
42
36
 
43
37
  # (see Proxy#create)
44
38
  def create(key, value, options = {})
45
- @backend.lock { super }
39
+ backend.lock { super }
46
40
  end
47
41
 
48
42
  # (see Proxy#merge!)
49
43
  def merge!(pairs, options = {})
50
44
  if block_given?
51
- @backend.lock do
52
- @backend.update(pairs.map do |key, new_value|
45
+ backend.lock do
46
+ backend.update(pairs.map do |key, new_value|
53
47
  new_value = yield(key, load(key), new_value) if key?(key)
54
48
  [key, new_value]
55
49
  end)
56
50
  end
57
51
  else
58
- @backend.update(pairs)
52
+ backend.update(pairs)
59
53
  end
60
54
 
61
55
  self