moneta 1.4.2 → 1.5.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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +35 -38
  3. data/CHANGES +9 -0
  4. data/CONTRIBUTORS +2 -0
  5. data/Gemfile +143 -55
  6. data/README.md +5 -4
  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 +53 -52
  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 +1 -1
  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/moneta/adapters/client/client_helper.rb +4 -3
  55. data/spec/moneta/adapters/faraday_helper.rb +3 -2
  56. data/spec/moneta/adapters/lruhash/adapter_lruhash_spec.rb +10 -6
  57. data/spec/moneta/adapters/mongo/adapter_mongo_spec.rb +2 -2
  58. data/spec/moneta/config_spec.rb +219 -0
  59. data/spec/moneta/proxies/transformer/transformer_bson_spec.rb +3 -1
  60. data/spec/moneta/proxies/transformer/transformer_marshal_escape_spec.rb +2 -0
  61. data/spec/rack/session_moneta_spec.rb +44 -25
  62. data/spec/restserver.rb +3 -14
  63. metadata +24 -6
@@ -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