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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +26 -8
  3. data/CHANGES +6 -0
  4. data/CONTRIBUTORS +2 -1
  5. data/Gemfile +7 -5
  6. data/README.md +2 -6
  7. data/feature_matrix.yaml +0 -10
  8. data/lib/moneta.rb +9 -9
  9. data/lib/moneta/adapters/mongo.rb +256 -7
  10. data/lib/moneta/adapters/redis.rb +5 -1
  11. data/lib/moneta/adapters/sequel.rb +45 -464
  12. data/lib/moneta/adapters/sequel/mysql.rb +66 -0
  13. data/lib/moneta/adapters/sequel/postgres.rb +80 -0
  14. data/lib/moneta/adapters/sequel/postgres_hstore.rb +240 -0
  15. data/lib/moneta/adapters/sequel/sqlite.rb +57 -0
  16. data/lib/moneta/adapters/sqlite.rb +7 -7
  17. data/lib/moneta/create_support.rb +21 -0
  18. data/lib/moneta/dbm_adapter.rb +31 -0
  19. data/lib/moneta/{mixins.rb → defaults.rb} +1 -302
  20. data/lib/moneta/each_key_support.rb +27 -0
  21. data/lib/moneta/expires_support.rb +60 -0
  22. data/lib/moneta/hash_adapter.rb +68 -0
  23. data/lib/moneta/increment_support.rb +16 -0
  24. data/lib/moneta/nil_values.rb +35 -0
  25. data/lib/moneta/option_support.rb +51 -0
  26. data/lib/moneta/transformer/helper/bson.rb +5 -15
  27. data/lib/moneta/version.rb +1 -1
  28. data/lib/rack/cache/moneta.rb +14 -15
  29. data/moneta.gemspec +7 -9
  30. data/script/benchmarks +1 -2
  31. data/script/contributors +11 -6
  32. data/spec/active_support/cache_moneta_store_spec.rb +27 -29
  33. data/spec/features/concurrent_increment.rb +2 -3
  34. data/spec/features/create_expires.rb +15 -15
  35. data/spec/features/default_expires.rb +11 -12
  36. data/spec/features/expires.rb +215 -210
  37. data/spec/helper.rb +16 -33
  38. data/spec/moneta/adapters/mongo/adapter_mongo_spec.rb +16 -1
  39. data/spec/moneta/adapters/mongo/adapter_mongo_with_default_expires_spec.rb +1 -1
  40. data/spec/moneta/adapters/mongo/standard_mongo_spec.rb +1 -1
  41. data/spec/moneta/adapters/sequel/adapter_sequel_spec.rb +7 -34
  42. data/spec/moneta/adapters/sequel/helper.rb +37 -0
  43. data/spec/moneta/adapters/sequel/standard_sequel_spec.rb +4 -10
  44. data/spec/moneta/adapters/sequel/standard_sequel_with_expires_spec.rb +7 -8
  45. data/spec/moneta/proxies/shared/shared_unix_spec.rb +10 -0
  46. data/spec/restserver.rb +15 -0
  47. metadata +39 -58
  48. data/lib/moneta/adapters/mongo/base.rb +0 -103
  49. data/lib/moneta/adapters/mongo/moped.rb +0 -166
  50. data/lib/moneta/adapters/mongo/official.rb +0 -156
  51. data/spec/moneta/adapters/mongo/adapter_mongo_moped_spec.rb +0 -26
  52. data/spec/moneta/adapters/mongo/adapter_mongo_moped_with_default_expires_spec.rb +0 -14
  53. data/spec/moneta/adapters/mongo/adapter_mongo_official_spec.rb +0 -27
  54. data/spec/moneta/adapters/mongo/adapter_mongo_official_with_default_expires_spec.rb +0 -14
  55. data/spec/moneta/adapters/mongo/standard_mongo_moped_spec.rb +0 -7
  56. data/spec/moneta/adapters/mongo/standard_mongo_official_spec.rb +0 -7
  57. 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