moneta 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
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