plumbum 0.1.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.
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sleeping_king_studios/tools'
4
+
5
+ require 'plumbum'
6
+ require 'plumbum/errors/immutable_error'
7
+ require 'plumbum/errors/invalid_key_error'
8
+
9
+ module Plumbum
10
+ # Abstract module defining the Provider interface.
11
+ #
12
+ # A Plumbum::Provider is responsible for making one or more values available
13
+ # to a consumer object. How those values are stored or generated is up to the
14
+ # provider implementation.
15
+ #
16
+ # Each provider implementation is responsible for defining the #get_value(key)
17
+ # and #has_value(key) methods:
18
+ #
19
+ # - #get_value(key) must accept a single non-empty String argument and return
20
+ # the provided value matching the key, or nil if there is no matching value.
21
+ # - #has_value?(key) must accept a single non-empty String argument and return
22
+ # true if the provider has a value matching the key, or false if there is
23
+ # no matching value.
24
+ #
25
+ # @see Plumbum::Consumer
26
+ # @see Plumbum::Providers::Plural
27
+ # @see Plumbum::Providers::Singular
28
+ module Provider
29
+ # Retrieves the provided value for the given key.
30
+ #
31
+ # @param key [String, Symbol] the key for the requested value.
32
+ #
33
+ # @return [Object, nil] the requested object, or nil if the provider does
34
+ # not have a value for the requested key.
35
+ def get(key)
36
+ key
37
+ .then { |obj| normalize_key(obj) }
38
+ .then { |str| get_value(str) }
39
+ end
40
+
41
+ # Checks if the provider has a value for the given key.
42
+ #
43
+ # @param key [String, Symbol] the key for the requested value.
44
+ # @param allow_undefined [true, false] if true, returns true even if the key
45
+ # exists but the value is undefined.
46
+ #
47
+ # @return [true, false] true if the provider has a value for the requested
48
+ # key, otherwise false.
49
+ def has?(key, allow_undefined: false)
50
+ key
51
+ .then { |obj| normalize_key(obj) }
52
+ .then { |str| has_value?(str, allow_undefined:) }
53
+ end
54
+
55
+ # Sets the value for the given key.
56
+ #
57
+ # @param key [String, Symbol] the key for the assigned value.
58
+ # @param value [Object] the value to assign.
59
+ #
60
+ # @return [Object] the assigned value.
61
+ #
62
+ # @raise [Plumbum::Errors::ImmutableError] when attempting to assign a value
63
+ # to an immutable provider.
64
+ def set(key, value)
65
+ if frozen?
66
+ raise FrozenError, "can't modify frozen #{self.class}: #{inspect}"
67
+ end
68
+
69
+ key
70
+ .then { |obj| normalize_key(obj) }
71
+ .tap { |key| validate_key(key) }
72
+ .tap { |key| require_mutable(key) }
73
+ .then { |key| set_value(key, value) }
74
+ end
75
+
76
+ # @return [Hash{Symbol => Object}] the options used to configure the
77
+ # provider.
78
+ def options
79
+ @options ||= {}
80
+ end
81
+
82
+ # @return [true, false] if true, indicates the provider is read only, and an
83
+ # exception will be raised when attempting to set or change its value(s).
84
+ def read_only?
85
+ options.fetch(:read_only, true)
86
+ end
87
+
88
+ # @return [true, false] if true, indicates the provider permits overwriting
89
+ # undefined values, and an exception will be raised when attemption to
90
+ # set or change any other values.
91
+ def write_once?
92
+ options.fetch(:write_once, false)
93
+ end
94
+
95
+ private
96
+
97
+ def get_value(key) = raw_value(key)
98
+
99
+ def has_value?(_key, **) = false # rubocop:disable Naming/PredicatePrefix
100
+
101
+ def mutable?(key)
102
+ return true if write_once? && raw_value(key) == Plumbum::UNDEFINED
103
+
104
+ !read_only?
105
+ end
106
+
107
+ def normalize_key(key)
108
+ tools.assertions.validate_name(key, as: :key)
109
+
110
+ key.to_s
111
+ end
112
+
113
+ def provider_name = respond_to?(:name) ? name : self.class.name
114
+
115
+ def raw_value(_key) = nil
116
+
117
+ def require_mutable(key)
118
+ return if mutable?(key)
119
+
120
+ raise Plumbum::Errors::ImmutableError,
121
+ "unable to change immutable value for #{provider_name} with key " \
122
+ "#{key.inspect}"
123
+ end
124
+
125
+ def set_value(_key, _value) = nil
126
+
127
+ def tools = SleepingKingStudios::Tools::Toolbelt.instance
128
+
129
+ def valid_key?(key) = has_value?(key) # rubocop:disable Style/PreferredHashMethods
130
+
131
+ def validate_key(key)
132
+ return if valid_key?(key)
133
+
134
+ return if raw_value(key) == Plumbum::UNDEFINED
135
+
136
+ raise Plumbum::Errors::InvalidKeyError,
137
+ "invalid key #{key.inspect} for #{provider_name}"
138
+ end
139
+
140
+ def validate_options(options)
141
+ if options.key?(:read_only) && options.key?(:write_once)
142
+ raise ArgumentError, 'incompatible options :read_only and :write_once'
143
+ end
144
+
145
+ options
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'plumbum/providers'
4
+
5
+ module Plumbum::Providers
6
+ # Provider that calls proc values and returns the result.
7
+ #
8
+ # Add Plumbum::Providers::Lazy for values that have a consistent definition
9
+ # but changing value, such as class definitions under code reloading.
10
+ module Lazy
11
+ # Retrieves the provided value for the given key.
12
+ #
13
+ # If the value is a Proc, the Proc is called and the value returned by the
14
+ # Proc is returned by #get. Otherwise, #get returns the value directly.
15
+ #
16
+ # @param key [String, Symbol] the key for the requested value.
17
+ #
18
+ # @return [Object, nil] the requested object, or nil if the provider does
19
+ # not have a value for the requested key.
20
+ def get(key)
21
+ value = super
22
+
23
+ value.is_a?(Proc) ? value.call : value
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'plumbum/providers'
4
+
5
+ module Plumbum::Providers
6
+ # Provider implementation that wraps a multiple key-value pairs.
7
+ module Plural
8
+ include Plumbum::Provider
9
+
10
+ # @return [Hash] the key-value pairs returned by the provider.
11
+ attr_reader :values
12
+
13
+ private
14
+
15
+ def get_value(key) = values[key]
16
+
17
+ def has_value?(key, **) = values.key?(key) # rubocop:disable Naming/PredicatePrefix
18
+
19
+ def mutable?(key)
20
+ return true if write_once? && @values == Plumbum::UNDEFINED
21
+
22
+ super
23
+ end
24
+
25
+ def raw_value(key) = values[key]
26
+
27
+ def set_value(key, value)
28
+ @values[key.to_s] = value
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'plumbum/providers'
4
+
5
+ module Plumbum::Providers
6
+ # Provider implementation that wraps a single key-value pair.
7
+ module Singular
8
+ include Plumbum::Provider
9
+
10
+ # @return [String] the key matched by the provider.
11
+ attr_reader :key
12
+
13
+ # @return [Object] the value returned by the provider.
14
+ attr_reader :value
15
+
16
+ private
17
+
18
+ def has_value?(key, **) = key == self.key # rubocop:disable Naming/PredicatePrefix
19
+
20
+ def raw_value(key) = key == self.key ? @value : nil
21
+
22
+ def set_value(key, value) = key == self.key ? @value = value : nil
23
+
24
+ def valid_key?(key) = key == self.key
25
+ end
26
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'plumbum'
4
+
5
+ module Plumbum
6
+ # Namespace for Provider implementations.
7
+ module Providers
8
+ autoload :Lazy, 'plumbum/providers/lazy'
9
+ autoload :Plural, 'plumbum/providers/plural'
10
+ autoload :Singular, 'plumbum/providers/singular'
11
+ end
12
+ end