moneta 1.3.0 → 1.4.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +26 -8
- data/CHANGES +6 -0
- data/CONTRIBUTORS +2 -1
- data/Gemfile +7 -5
- data/README.md +2 -6
- data/feature_matrix.yaml +0 -10
- data/lib/moneta.rb +9 -9
- data/lib/moneta/adapters/mongo.rb +256 -7
- data/lib/moneta/adapters/redis.rb +5 -1
- data/lib/moneta/adapters/sequel.rb +45 -464
- data/lib/moneta/adapters/sequel/mysql.rb +66 -0
- data/lib/moneta/adapters/sequel/postgres.rb +80 -0
- data/lib/moneta/adapters/sequel/postgres_hstore.rb +240 -0
- data/lib/moneta/adapters/sequel/sqlite.rb +57 -0
- data/lib/moneta/adapters/sqlite.rb +7 -7
- data/lib/moneta/create_support.rb +21 -0
- data/lib/moneta/dbm_adapter.rb +31 -0
- data/lib/moneta/{mixins.rb → defaults.rb} +1 -302
- data/lib/moneta/each_key_support.rb +27 -0
- data/lib/moneta/expires_support.rb +60 -0
- data/lib/moneta/hash_adapter.rb +68 -0
- data/lib/moneta/increment_support.rb +16 -0
- data/lib/moneta/nil_values.rb +35 -0
- data/lib/moneta/option_support.rb +51 -0
- data/lib/moneta/transformer/helper/bson.rb +5 -15
- data/lib/moneta/version.rb +1 -1
- data/lib/rack/cache/moneta.rb +14 -15
- data/moneta.gemspec +7 -9
- data/script/benchmarks +1 -2
- data/script/contributors +11 -6
- data/spec/active_support/cache_moneta_store_spec.rb +27 -29
- data/spec/features/concurrent_increment.rb +2 -3
- data/spec/features/create_expires.rb +15 -15
- data/spec/features/default_expires.rb +11 -12
- data/spec/features/expires.rb +215 -210
- data/spec/helper.rb +16 -33
- data/spec/moneta/adapters/mongo/adapter_mongo_spec.rb +16 -1
- data/spec/moneta/adapters/mongo/adapter_mongo_with_default_expires_spec.rb +1 -1
- data/spec/moneta/adapters/mongo/standard_mongo_spec.rb +1 -1
- data/spec/moneta/adapters/sequel/adapter_sequel_spec.rb +7 -34
- data/spec/moneta/adapters/sequel/helper.rb +37 -0
- data/spec/moneta/adapters/sequel/standard_sequel_spec.rb +4 -10
- data/spec/moneta/adapters/sequel/standard_sequel_with_expires_spec.rb +7 -8
- data/spec/moneta/proxies/shared/shared_unix_spec.rb +10 -0
- data/spec/restserver.rb +15 -0
- metadata +39 -58
- data/lib/moneta/adapters/mongo/base.rb +0 -103
- data/lib/moneta/adapters/mongo/moped.rb +0 -166
- data/lib/moneta/adapters/mongo/official.rb +0 -156
- data/spec/moneta/adapters/mongo/adapter_mongo_moped_spec.rb +0 -26
- data/spec/moneta/adapters/mongo/adapter_mongo_moped_with_default_expires_spec.rb +0 -14
- data/spec/moneta/adapters/mongo/adapter_mongo_official_spec.rb +0 -27
- data/spec/moneta/adapters/mongo/adapter_mongo_official_with_default_expires_spec.rb +0 -14
- data/spec/moneta/adapters/mongo/standard_mongo_moped_spec.rb +0 -7
- data/spec/moneta/adapters/mongo/standard_mongo_official_spec.rb +0 -7
- data/spec/quality_spec.rb +0 -51
@@ -0,0 +1,21 @@
|
|
1
|
+
module Moneta
|
2
|
+
# Implements simple create using key? and store.
|
3
|
+
#
|
4
|
+
# This is sufficient for non-shared stores or if atomicity is not required.
|
5
|
+
# @api private
|
6
|
+
module CreateSupport
|
7
|
+
# (see Defaults#create)
|
8
|
+
def create(key, value, options = {})
|
9
|
+
if key? key
|
10
|
+
false
|
11
|
+
else
|
12
|
+
store(key, value, options)
|
13
|
+
true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.included(base)
|
18
|
+
base.supports(:create) if base.respond_to?(:supports)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Moneta
|
2
|
+
# This is for adapters that conform to the DBM interface
|
3
|
+
# @api private
|
4
|
+
module DBMAdapter
|
5
|
+
include HashAdapter
|
6
|
+
|
7
|
+
# (see Proxy#close)
|
8
|
+
def close
|
9
|
+
@backend.close
|
10
|
+
nil
|
11
|
+
end
|
12
|
+
|
13
|
+
# (see Proxy#merge!)
|
14
|
+
def merge!(pairs, options = {})
|
15
|
+
hash =
|
16
|
+
if block_given?
|
17
|
+
keys = pairs.map { |k, _| k }
|
18
|
+
old_pairs = Hash[slice(*keys)]
|
19
|
+
Hash[pairs.map do |key, new_value|
|
20
|
+
new_value = yield(key, old_pairs[key], new_value) if old_pairs.key?(key)
|
21
|
+
[key, new_value]
|
22
|
+
end.to_a]
|
23
|
+
else
|
24
|
+
Hash === pairs ? pairs : Hash[pairs.to_a]
|
25
|
+
end
|
26
|
+
|
27
|
+
@backend.update(hash)
|
28
|
+
self
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -1,58 +1,8 @@
|
|
1
1
|
module Moneta
|
2
|
-
# @api private
|
3
|
-
module OptionSupport
|
4
|
-
# Return Moneta store with default options or additional proxies
|
5
|
-
#
|
6
|
-
# @param [Hash] options Options to merge
|
7
|
-
# @return [Moneta store]
|
8
|
-
#
|
9
|
-
# @api public
|
10
|
-
def with(options = nil, &block)
|
11
|
-
adapter = self
|
12
|
-
if block
|
13
|
-
builder = Builder.new(&block)
|
14
|
-
builder.adapter(adapter)
|
15
|
-
adapter = builder.build.last
|
16
|
-
end
|
17
|
-
options ? OptionMerger.new(adapter, options) : adapter
|
18
|
-
end
|
19
|
-
|
20
|
-
# Return Moneta store with default option raw: true
|
21
|
-
#
|
22
|
-
# @return [OptionMerger]
|
23
|
-
# @api public
|
24
|
-
def raw
|
25
|
-
@raw ||=
|
26
|
-
begin
|
27
|
-
store = with(raw: true, only: [:load, :store, :create, :delete])
|
28
|
-
store.instance_variable_set(:@raw, store)
|
29
|
-
store
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
# Return Moneta store with default prefix option
|
34
|
-
#
|
35
|
-
# @param [String] prefix Key prefix
|
36
|
-
# @return [OptionMerger]
|
37
|
-
# @api public
|
38
|
-
def prefix(prefix)
|
39
|
-
with(prefix: prefix, except: :clear)
|
40
|
-
end
|
41
|
-
|
42
|
-
# Return Moneta store with default expiration time
|
43
|
-
#
|
44
|
-
# @param [Integer] expires Default expiration time
|
45
|
-
# @return [OptionMerger]
|
46
|
-
# @api public
|
47
|
-
def expires(expires)
|
48
|
-
with(expires: expires, only: [:store, :create, :increment])
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
2
|
# Simple interface to key/value stores with Hash-like interface.
|
53
3
|
# @api public
|
54
4
|
module Defaults
|
55
|
-
include OptionSupport
|
5
|
+
include ::Moneta::OptionSupport
|
56
6
|
|
57
7
|
# @api private
|
58
8
|
module ClassMethods
|
@@ -367,255 +317,4 @@ module Moneta
|
|
367
317
|
features.include?(feature)
|
368
318
|
end
|
369
319
|
end
|
370
|
-
|
371
|
-
# This contains overrides of methods in Defaults where additional nil
|
372
|
-
# checks are required, because nil values are possible in the store.
|
373
|
-
# @api private
|
374
|
-
module NilValues
|
375
|
-
def fetch_values(*keys, **options)
|
376
|
-
values = values_at(*keys, **options)
|
377
|
-
return values unless block_given?
|
378
|
-
keys.zip(values).map do |key, value|
|
379
|
-
if value == nil && !key?(key)
|
380
|
-
yield key
|
381
|
-
else
|
382
|
-
value
|
383
|
-
end
|
384
|
-
end
|
385
|
-
end
|
386
|
-
|
387
|
-
def slice(*keys, **options)
|
388
|
-
keys.zip(values_at(*keys, **options)).reject do |key, value|
|
389
|
-
value == nil && !key?(key)
|
390
|
-
end
|
391
|
-
end
|
392
|
-
|
393
|
-
def merge!(pairs, options = {})
|
394
|
-
pairs.each do |key, value|
|
395
|
-
if block_given? && key?(key, options)
|
396
|
-
existing = load(key, options)
|
397
|
-
value = yield(key, existing, value)
|
398
|
-
end
|
399
|
-
store(key, value, options)
|
400
|
-
end
|
401
|
-
self
|
402
|
-
end
|
403
|
-
end
|
404
|
-
|
405
|
-
# @api private
|
406
|
-
module IncrementSupport
|
407
|
-
# (see Defaults#increment)
|
408
|
-
def increment(key, amount = 1, options = {})
|
409
|
-
existing = load(key, options)
|
410
|
-
value = (existing == nil ? 0 : Integer(existing)) + amount
|
411
|
-
store(key, value.to_s, options)
|
412
|
-
value
|
413
|
-
end
|
414
|
-
|
415
|
-
def self.included(base)
|
416
|
-
base.supports(:increment) if base.respond_to?(:supports)
|
417
|
-
end
|
418
|
-
end
|
419
|
-
|
420
|
-
# This provides an each_key implementation that works in most cases.
|
421
|
-
# @api private
|
422
|
-
module EachKeySupport
|
423
|
-
def each_key
|
424
|
-
return enum_for(:each_key) unless block_given?
|
425
|
-
|
426
|
-
if @backend.respond_to?(:each_key)
|
427
|
-
@backend.each_key { |key| yield key }
|
428
|
-
elsif @backend.respond_to?(:keys)
|
429
|
-
if keys = @backend.keys
|
430
|
-
keys.each { |key| yield key }
|
431
|
-
end
|
432
|
-
elsif @backend.respond_to?(:each)
|
433
|
-
@backend.each { |key, _| yield key }
|
434
|
-
else
|
435
|
-
raise ::NotImplementedError, "No enumerable found on backend"
|
436
|
-
end
|
437
|
-
|
438
|
-
self
|
439
|
-
end
|
440
|
-
|
441
|
-
def self.included(base)
|
442
|
-
base.supports(:each_key) if base.respond_to?(:supports)
|
443
|
-
end
|
444
|
-
end
|
445
|
-
|
446
|
-
# Implements simple create using key? and store.
|
447
|
-
#
|
448
|
-
# This is sufficient for non-shared stores or if atomicity is not required.
|
449
|
-
# @api private
|
450
|
-
module CreateSupport
|
451
|
-
# (see Defaults#create)
|
452
|
-
def create(key, value, options = {})
|
453
|
-
if key? key
|
454
|
-
false
|
455
|
-
else
|
456
|
-
store(key, value, options)
|
457
|
-
true
|
458
|
-
end
|
459
|
-
end
|
460
|
-
|
461
|
-
def self.included(base)
|
462
|
-
base.supports(:create) if base.respond_to?(:supports)
|
463
|
-
end
|
464
|
-
end
|
465
|
-
|
466
|
-
# @api private
|
467
|
-
module HashAdapter
|
468
|
-
attr_reader :backend
|
469
|
-
|
470
|
-
# (see Proxy#key?)
|
471
|
-
def key?(key, options = {})
|
472
|
-
@backend.has_key?(key)
|
473
|
-
end
|
474
|
-
|
475
|
-
# (see Proxy#load)
|
476
|
-
def load(key, options = {})
|
477
|
-
@backend[key]
|
478
|
-
end
|
479
|
-
|
480
|
-
# (see Proxy#store)
|
481
|
-
def store(key, value, options = {})
|
482
|
-
@backend[key] = value
|
483
|
-
end
|
484
|
-
|
485
|
-
# (see Proxy#delete)
|
486
|
-
def delete(key, options = {})
|
487
|
-
@backend.delete(key)
|
488
|
-
end
|
489
|
-
|
490
|
-
# (see Proxy#clear)
|
491
|
-
def clear(options = {})
|
492
|
-
@backend.clear
|
493
|
-
self
|
494
|
-
end
|
495
|
-
|
496
|
-
# (see Defaults#values_at)
|
497
|
-
def values_at(*keys, **options)
|
498
|
-
return super unless @backend.respond_to? :values_at
|
499
|
-
@backend.values_at(*keys)
|
500
|
-
end
|
501
|
-
|
502
|
-
# (see Defaults#fetch_values)
|
503
|
-
def fetch_values(*keys, **options, &defaults)
|
504
|
-
return super unless @backend.respond_to? :fetch_values
|
505
|
-
defaults ||= {} # prevents KeyError
|
506
|
-
@backend.fetch_values(*keys, &defaults)
|
507
|
-
end
|
508
|
-
|
509
|
-
# (see Defaults#slice)
|
510
|
-
def slice(*keys, **options)
|
511
|
-
return super unless @backend.respond_to? :slice
|
512
|
-
@backend.slice(*keys)
|
513
|
-
end
|
514
|
-
|
515
|
-
# (see Defaults#merge!)
|
516
|
-
def merge!(pairs, options = {}, &block)
|
517
|
-
return super unless method = [:merge!, :update].find do |method|
|
518
|
-
@backend.respond_to? method
|
519
|
-
end
|
520
|
-
|
521
|
-
hash = Hash === pairs ? pairs : Hash[pairs.to_a]
|
522
|
-
case method
|
523
|
-
when :merge!
|
524
|
-
@backend.merge!(hash, &block)
|
525
|
-
when :update
|
526
|
-
@backend.update(hash, &block)
|
527
|
-
end
|
528
|
-
|
529
|
-
self
|
530
|
-
end
|
531
|
-
end
|
532
|
-
|
533
|
-
# This is for adapters that conform to the DBM interface
|
534
|
-
# @api private
|
535
|
-
module DBMAdapter
|
536
|
-
include HashAdapter
|
537
|
-
|
538
|
-
# (see Proxy#close)
|
539
|
-
def close
|
540
|
-
@backend.close
|
541
|
-
nil
|
542
|
-
end
|
543
|
-
|
544
|
-
# (see Proxy#merge!)
|
545
|
-
def merge!(pairs, options = {})
|
546
|
-
hash =
|
547
|
-
if block_given?
|
548
|
-
keys = pairs.map { |k, _| k }
|
549
|
-
old_pairs = Hash[slice(*keys)]
|
550
|
-
Hash[pairs.map do |key, new_value|
|
551
|
-
new_value = yield(key, old_pairs[key], new_value) if old_pairs.key?(key)
|
552
|
-
[key, new_value]
|
553
|
-
end.to_a]
|
554
|
-
else
|
555
|
-
Hash === pairs ? pairs : Hash[pairs.to_a]
|
556
|
-
end
|
557
|
-
|
558
|
-
@backend.update(hash)
|
559
|
-
self
|
560
|
-
end
|
561
|
-
end
|
562
|
-
|
563
|
-
# This mixin handles the calculation of expiration times.
|
564
|
-
#
|
565
|
-
#
|
566
|
-
module ExpiresSupport
|
567
|
-
attr_accessor :default_expires
|
568
|
-
|
569
|
-
protected
|
570
|
-
|
571
|
-
# Calculates the time when something will expire.
|
572
|
-
#
|
573
|
-
# This method considers false and 0 as "no-expire" and every positive
|
574
|
-
# number as a time to live in seconds.
|
575
|
-
#
|
576
|
-
# @param [Hash] options Options hash
|
577
|
-
# @option options [0,false,nil,Numeric] :expires expires value given by user
|
578
|
-
# @param [0,false,nil,Numeric] default default expiration time
|
579
|
-
#
|
580
|
-
# @return [false] if it should not expire
|
581
|
-
# @return [Time] the time when something should expire
|
582
|
-
# @return [nil] if it is not known
|
583
|
-
def expires_at(options, default = @default_expires)
|
584
|
-
value = expires_value(options, default)
|
585
|
-
Numeric === value ? Time.now + value : value
|
586
|
-
end
|
587
|
-
|
588
|
-
# Calculates the number of seconds something should last.
|
589
|
-
#
|
590
|
-
# This method considers false and 0 as "no-expire" and every positive
|
591
|
-
# number as a time to live in seconds.
|
592
|
-
#
|
593
|
-
# @param [Hash] options Options hash
|
594
|
-
# @option options [0,false,nil,Numeric] :expires expires value given by user
|
595
|
-
# @param [0,false,nil,Numeric] default default expiration time
|
596
|
-
#
|
597
|
-
# @return [false] if it should not expire
|
598
|
-
# @return [Numeric] seconds until expiration
|
599
|
-
# @return [nil] if it is not known
|
600
|
-
def expires_value(options, default = @default_expires)
|
601
|
-
case value = options[:expires]
|
602
|
-
when 0, false
|
603
|
-
false
|
604
|
-
when nil
|
605
|
-
default ? default.to_r : nil
|
606
|
-
when Numeric
|
607
|
-
value = value.to_r
|
608
|
-
raise ArgumentError, ":expires must be a positive value, got #{value}" if value < 0
|
609
|
-
value
|
610
|
-
else
|
611
|
-
raise ArgumentError, ":expires must be Numeric or false, got #{value.inspect}"
|
612
|
-
end
|
613
|
-
end
|
614
|
-
|
615
|
-
class << self
|
616
|
-
def included(base)
|
617
|
-
base.supports(:expires) if base.respond_to?(:supports)
|
618
|
-
end
|
619
|
-
end
|
620
|
-
end
|
621
320
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Moneta
|
2
|
+
# This provides an each_key implementation that works in most cases.
|
3
|
+
# @api private
|
4
|
+
module EachKeySupport
|
5
|
+
def each_key
|
6
|
+
return enum_for(:each_key) unless block_given?
|
7
|
+
|
8
|
+
if @backend.respond_to?(:each_key)
|
9
|
+
@backend.each_key { |key| yield key }
|
10
|
+
elsif @backend.respond_to?(:keys)
|
11
|
+
if keys = @backend.keys
|
12
|
+
keys.each { |key| yield key }
|
13
|
+
end
|
14
|
+
elsif @backend.respond_to?(:each)
|
15
|
+
@backend.each { |key, _| yield key }
|
16
|
+
else
|
17
|
+
raise ::NotImplementedError, "No enumerable found on backend"
|
18
|
+
end
|
19
|
+
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.included(base)
|
24
|
+
base.supports(:each_key) if base.respond_to?(:supports)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Moneta
|
2
|
+
# This mixin handles the calculation of expiration times.
|
3
|
+
#
|
4
|
+
#
|
5
|
+
module ExpiresSupport
|
6
|
+
attr_accessor :default_expires
|
7
|
+
|
8
|
+
protected
|
9
|
+
|
10
|
+
# Calculates the time when something will expire.
|
11
|
+
#
|
12
|
+
# This method considers false and 0 as "no-expire" and every positive
|
13
|
+
# number as a time to live in seconds.
|
14
|
+
#
|
15
|
+
# @param [Hash] options Options hash
|
16
|
+
# @option options [0,false,nil,Numeric] :expires expires value given by user
|
17
|
+
# @param [0,false,nil,Numeric] default default expiration time
|
18
|
+
#
|
19
|
+
# @return [false] if it should not expire
|
20
|
+
# @return [Time] the time when something should expire
|
21
|
+
# @return [nil] if it is not known
|
22
|
+
def expires_at(options, default = @default_expires)
|
23
|
+
value = expires_value(options, default)
|
24
|
+
Numeric === value ? Time.now + value : value
|
25
|
+
end
|
26
|
+
|
27
|
+
# Calculates the number of seconds something should last.
|
28
|
+
#
|
29
|
+
# This method considers false and 0 as "no-expire" and every positive
|
30
|
+
# number as a time to live in seconds.
|
31
|
+
#
|
32
|
+
# @param [Hash] options Options hash
|
33
|
+
# @option options [0,false,nil,Numeric] :expires expires value given by user
|
34
|
+
# @param [0,false,nil,Numeric] default default expiration time
|
35
|
+
#
|
36
|
+
# @return [false] if it should not expire
|
37
|
+
# @return [Numeric] seconds until expiration
|
38
|
+
# @return [nil] if it is not known
|
39
|
+
def expires_value(options, default = @default_expires)
|
40
|
+
case value = options[:expires]
|
41
|
+
when 0, false
|
42
|
+
false
|
43
|
+
when nil
|
44
|
+
default ? default.to_r : nil
|
45
|
+
when Numeric
|
46
|
+
value = value.to_r
|
47
|
+
raise ArgumentError, ":expires must be a positive value, got #{value}" if value < 0
|
48
|
+
value
|
49
|
+
else
|
50
|
+
raise ArgumentError, ":expires must be Numeric or false, got #{value.inspect}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class << self
|
55
|
+
def included(base)
|
56
|
+
base.supports(:expires) if base.respond_to?(:supports)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|