unifig 0.3.2 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +165 -79
- data/lib/unifig/config.rb +16 -1
- data/lib/unifig/errors.rb +3 -0
- data/lib/unifig/init.rb +6 -5
- data/lib/unifig/providers/local.rb +1 -1
- data/lib/unifig/var.rb +87 -6
- data/lib/unifig/version.rb +1 -1
- data/spec/spec_helper.rb +4 -2
- data/spec/unifig/config_spec.rb +43 -1
- data/spec/unifig/init_spec.rb +41 -17
- data/spec/unifig/var_spec.rb +259 -0
- data/spec/unifig/vars_spec.rb +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a663a7911df321fea42c56973ea1d194c678e3fa54c7856decaec28df550619
|
4
|
+
data.tar.gz: ada57aa2f5292246c16498218e869be155532dcbd9ab72544abbd06b5d9692b4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1dd696cd7f734a3fc9e041d61291f2d70796e00ceb069ed5697dca7d1f8f29856ebb6b0c17722e04b2a198fd89aa3e6b7edca635c0e3abb04f256195cc684fc1
|
7
|
+
data.tar.gz: c9f9728f4ebca40748944c096a87f2e2f2bf0fe4aad4ca5706757cbedb45bd24c2dc571124460893b96d4ecee9d3b2238c56fe2cddb0536f73be516e7759f99c
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
# [0.4.0][] (2022-09-01)
|
2
|
+
|
3
|
+
## Changed
|
4
|
+
|
5
|
+
- All values are strings by default regardless of how they arrived.
|
6
|
+
- The `config` key is now `unifig`.
|
7
|
+
|
8
|
+
## Added
|
9
|
+
|
10
|
+
- Values can now be converted to built-in or custom types.
|
11
|
+
- Providers can now be configured.
|
12
|
+
|
1
13
|
# [0.3.2][] (2022-08-01)
|
2
14
|
|
3
15
|
## Fixed
|
@@ -34,6 +46,7 @@
|
|
34
46
|
|
35
47
|
Initial release.
|
36
48
|
|
49
|
+
[0.4.0]: https://github.com/AaronLasseigne/unifig/compare/v0.3.2...v0.4.0
|
37
50
|
[0.3.2]: https://github.com/AaronLasseigne/unifig/compare/v0.3.1...v0.3.2
|
38
51
|
[0.3.1]: https://github.com/AaronLasseigne/unifig/compare/v0.3.0...v0.3.1
|
39
52
|
[0.3.0]: https://github.com/AaronLasseigne/unifig/compare/v0.2.0...v0.3.0
|
data/README.md
CHANGED
@@ -18,13 +18,13 @@ If you want to use Unifig outside of a framework listed above you can manually a
|
|
18
18
|
Add it to your Gemfile:
|
19
19
|
|
20
20
|
``` rb
|
21
|
-
gem 'unifig', '~> 0.
|
21
|
+
gem 'unifig', '~> 0.4.0'
|
22
22
|
```
|
23
23
|
|
24
24
|
Or install it manually:
|
25
25
|
|
26
26
|
``` sh
|
27
|
-
$ gem install unifig --version '~> 0.
|
27
|
+
$ gem install unifig --version '~> 0.4.0'
|
28
28
|
```
|
29
29
|
|
30
30
|
This project uses [Semantic Versioning][].
|
@@ -32,44 +32,146 @@ Check out [GitHub releases][] for a detailed list of changes.
|
|
32
32
|
|
33
33
|
## Usage
|
34
34
|
|
35
|
-
###
|
35
|
+
### Basic
|
36
36
|
|
37
|
-
Unifig
|
38
|
-
|
37
|
+
Unifig works by loading a YAML configuration that instructs it on how to retrieve and treat external variables.
|
38
|
+
Variable values are retrieved from an ordered list of providers.
|
39
|
+
|
40
|
+
A provider is any source where you would retrieve variable values.
|
39
41
|
Unifig comes with a `local` provider which reads values straight from the configuration file.
|
40
|
-
Additional providers may be installed
|
42
|
+
Additional providers may be installed:
|
43
|
+
|
44
|
+
| Provider | Gem |
|
45
|
+
| -------- | -------------- |
|
46
|
+
| local | Built-in |
|
47
|
+
| env | [unifig-env][] |
|
48
|
+
|
49
|
+
Providers are checked in order to find the variable values.
|
50
|
+
If a variable is not found in the first provider, it will be requested from the second provider and so on until it is found.
|
51
|
+
|
52
|
+
The YAML configuration should begin with a `unifig` key which lists the providers in the order you would like them checked:
|
53
|
+
|
54
|
+
```yml
|
55
|
+
unifig:
|
56
|
+
providers: [local, env]
|
57
|
+
```
|
41
58
|
|
42
|
-
|
59
|
+
You can list a single provider or an ordered array to check.
|
60
|
+
|
61
|
+
Variables should be listed after the `unifig` key as their own keys.
|
62
|
+
Here's a mininal example YAML:
|
43
63
|
|
44
64
|
```yml
|
45
|
-
|
65
|
+
unifig:
|
46
66
|
providers: local
|
47
67
|
|
68
|
+
HELLO: "world"
|
69
|
+
```
|
70
|
+
|
71
|
+
When this YAML is loaded, Unifig will add two methods to it's core `Unifig` class.
|
72
|
+
The first, `Unifig.hello` will return `"hello"` as the value it found from the `local` provider.
|
73
|
+
The second method, `Unifig.hello?` allow you to check to see if the value was able to be retrived at all.
|
74
|
+
|
75
|
+
```yml
|
76
|
+
> Unifig.hello?
|
77
|
+
# true
|
78
|
+
> Unifig.hello
|
79
|
+
# => "world"
|
80
|
+
```
|
81
|
+
|
82
|
+
Each variable listed in the YAML configuration will receive its own pair of methods on `Unifig`.
|
83
|
+
|
84
|
+
Variables can be listed with the `local` value immediately following as seen above.
|
85
|
+
They can also be defined with no `local` value:
|
86
|
+
|
87
|
+
```yml
|
88
|
+
HELLO:
|
89
|
+
```
|
90
|
+
|
91
|
+
Or they can be declared with the verbose syntax:
|
92
|
+
|
93
|
+
```yaml
|
48
94
|
HELLO:
|
49
95
|
value: "world"
|
50
96
|
```
|
51
97
|
|
52
|
-
|
53
|
-
|
98
|
+
The verbose syntax is useful when additional configration is need as seen in the [Advanced](#advanced) section.
|
99
|
+
|
100
|
+
Loading a YAML configuration can be accomplished using the `Unifig::Init` class.
|
101
|
+
From `Unifig::Init` you can load the YAML as a string with `.load` or as a file with `.load_file`.
|
102
|
+
|
103
|
+
*NOTE: If you're using one of the framework gems, loading may be handled for you.*
|
104
|
+
|
105
|
+
Loading from a string:
|
106
|
+
|
107
|
+
```rb
|
108
|
+
Unifig::Init.load(<<~YML)
|
109
|
+
unifig:
|
110
|
+
providers: local
|
111
|
+
|
112
|
+
HELLO: "world"
|
113
|
+
YML
|
114
|
+
```
|
115
|
+
|
116
|
+
Loading from a file:
|
117
|
+
|
118
|
+
```rb
|
119
|
+
Unifig::Init.load_file('unifig.yml')
|
120
|
+
```
|
121
|
+
|
122
|
+
### Advanced
|
123
|
+
|
124
|
+
#### Environments
|
125
|
+
|
126
|
+
Different working environments may require different setups.
|
127
|
+
This can be accomplished in the `unifig` key or within variable keys with the `envs` key.
|
54
128
|
|
55
|
-
|
56
|
-
|
129
|
+
Assuming two environments, `developement` and `production`, let's say we want to use different providers for each.
|
130
|
+
Whatever we set at the top level will operate as the default.
|
131
|
+
From there we can use the `envs` key to override that behavior:
|
57
132
|
|
58
133
|
```yml
|
59
|
-
|
60
|
-
providers:
|
134
|
+
unifig:
|
135
|
+
providers: local
|
136
|
+
envs:
|
137
|
+
production:
|
138
|
+
providers: env
|
139
|
+
|
140
|
+
HELLO: "world"
|
141
|
+
```
|
142
|
+
|
143
|
+
In the `development` environment we'll check the `local` provider but in `production` we'll use `env`.
|
144
|
+
This will result with `Unifig.hello` returning `"world"` in `development` and whatever the value of the `HELLO` environment variable is in `production`.
|
145
|
+
To select an environment, add it to `Unifig::Init.load` or `Unifig::Init.load_file`:
|
146
|
+
|
147
|
+
```rb
|
148
|
+
Unifig::Init.load(<<~YML, env: :development)
|
149
|
+
unifig:
|
150
|
+
providers: local
|
61
151
|
envs:
|
62
152
|
production:
|
63
153
|
providers: env
|
64
154
|
|
155
|
+
HELLO: "world"
|
156
|
+
YML
|
157
|
+
```
|
158
|
+
|
159
|
+
*NOTE: If you're using one of the framework gems, environments may be loaded automatically depending on the framework.*
|
160
|
+
|
161
|
+
In addition to changing `unifig`, `envs` may be used inside variables.
|
162
|
+
Any variable configuration may be overridden using `envs`:
|
163
|
+
|
164
|
+
```yml
|
65
165
|
HELLO:
|
66
166
|
value: "world"
|
67
167
|
envs:
|
68
|
-
|
69
|
-
value: "
|
168
|
+
production:
|
169
|
+
value: "universe"
|
70
170
|
```
|
71
171
|
|
72
|
-
|
172
|
+
Here we've set the `local` provider value to `"world"` for all environments with an override setting it to `"universe"` in the `production` environment.
|
173
|
+
|
174
|
+
#### Variable Substitutions
|
73
175
|
|
74
176
|
Variables can be used in other variables with `${VAR}`.
|
75
177
|
|
@@ -80,86 +182,71 @@ SERVICE_USERNAME: "${USER}_at_service"
|
|
80
182
|
|
81
183
|
Order of the variables does not matter but cyclical dependencies will throw an error.
|
82
184
|
|
83
|
-
|
185
|
+
#### Type Conversion
|
84
186
|
|
85
|
-
|
86
|
-
|
187
|
+
By default, all values are converted to strings.
|
188
|
+
If you want the value to be something other than a string you can assign a specific conversion.
|
189
|
+
Unifig comes with some basic built-in conversions or you can convert to any class available.
|
87
190
|
|
88
|
-
|
89
|
-
Variables can be made optional by using the `:optional` setting.
|
90
|
-
If there is a required variable without a value, Unifig will throw an error when loading.
|
91
|
-
|
92
|
-
```rb
|
93
|
-
Unifig::Init.load(<<~YAML, env: :production)
|
94
|
-
config:
|
95
|
-
providers: local
|
96
|
-
|
97
|
-
HOST:
|
98
|
-
value: github.com
|
99
|
-
envs:
|
100
|
-
development:
|
101
|
-
value: localhost
|
102
|
-
PORT:
|
103
|
-
optional: true
|
104
|
-
envs:
|
105
|
-
development:
|
106
|
-
value: 8080
|
107
|
-
YAML
|
191
|
+
In order to convert a value you can provide a type to `convert`:
|
108
192
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
> Unifig.port?
|
114
|
-
# true
|
115
|
-
> Unifig.port
|
116
|
-
# => 8080
|
193
|
+
```yml
|
194
|
+
THREADS:
|
195
|
+
value: 5
|
196
|
+
convert: integer
|
117
197
|
```
|
118
198
|
|
119
|
-
|
199
|
+
Conversion works regardless of the provider of the value.
|
120
200
|
|
121
|
-
|
122
|
-
> Unifig.host?
|
123
|
-
# true
|
124
|
-
> Unifig.host
|
125
|
-
# => "github.com"
|
126
|
-
> Unifig.port?
|
127
|
-
# false
|
128
|
-
> Unifig.port
|
129
|
-
# => nil
|
130
|
-
```
|
201
|
+
##### Built-in
|
131
202
|
|
132
|
-
|
203
|
+
There are a number of built-in types available.
|
204
|
+
Basic types that have no additional options include `string` (the default), `symbol`, `float`, and `decimal` (i.e. `BigDecimal`).
|
133
205
|
|
134
|
-
|
135
|
-
|
136
|
-
```
|
206
|
+
The `integer` type assumes base 10.
|
207
|
+
This can be overridden by providing a `base` option:
|
137
208
|
|
138
|
-
|
209
|
+
```yml
|
210
|
+
BINARY_INPUT:
|
211
|
+
convert:
|
212
|
+
type: integer
|
213
|
+
base: 2
|
214
|
+
```
|
139
215
|
|
140
|
-
|
216
|
+
Unifig also provides `date`, `date_time`, and `time` all of which use `parse` by default.
|
217
|
+
Any of them can be provided with a `format` option if you want to specify the format of the input.
|
218
|
+
The `format` option uses `strptime` for the conversion.
|
219
|
+
You can find all valid formats by looking at the standard Ruby documentation.
|
141
220
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
221
|
+
```yml
|
222
|
+
STARTS_ON:
|
223
|
+
convert:
|
224
|
+
type: date
|
225
|
+
format: %Y-%m-%d
|
226
|
+
```
|
146
227
|
|
147
|
-
|
148
|
-
These can be overridden by setting the `envs` key and a key with the name of then environment and then redefining any settings.
|
149
|
-
This is the case for the overall configuration as well as any variable configurations.
|
228
|
+
##### Custom
|
150
229
|
|
151
|
-
|
230
|
+
Any available class can be used as a converter by providing the class name as the `converter`.
|
231
|
+
By default, `new` will be called on the class with the value passed in.
|
232
|
+
To use a different method provide it via the `method` option.
|
152
233
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
234
|
+
```yml
|
235
|
+
IP_ADDRESS:
|
236
|
+
convert: IPAddr
|
237
|
+
ENCODING:
|
238
|
+
convert:
|
239
|
+
type: Encoding
|
240
|
+
method: find
|
241
|
+
```
|
157
242
|
|
158
|
-
|
243
|
+
#### Unifig::Vars
|
159
244
|
|
160
245
|
After loading the configuration you can use `Unifig::Vars` to check on what happened.
|
161
246
|
It will return a list of `Unifig::Var`s with information such as which provider supplied the value.
|
162
247
|
|
248
|
+
[API Documentation][]
|
249
|
+
|
163
250
|
## Contributing
|
164
251
|
|
165
252
|
If you want to contribute to Unifig, please read [our contribution guidelines][].
|
@@ -173,7 +260,6 @@ Unifig is licensed under [the MIT License][].
|
|
173
260
|
[unifig-rails]: https://github.com/AaronLasseigne/unifig-rails
|
174
261
|
[Semantic Versioning]: http://semver.org/spec/v2.0.0.html
|
175
262
|
[GitHub releases]: https://github.com/AaronLasseigne/unifig/releases
|
176
|
-
[YAML configuration]: #yaml-configuration
|
177
263
|
[API Documentation]: http://rubydoc.info/github/AaronLasseigne/unifig
|
178
264
|
[our contribution guidelines]: CONTRIBUTING.md
|
179
265
|
[unifig-env]: https://github.com/AaronLasseigne/unifig-env
|
data/lib/unifig/config.rb
CHANGED
@@ -14,7 +14,22 @@ module Unifig
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def providers
|
17
|
-
@providers
|
17
|
+
return @providers if defined?(@providers)
|
18
|
+
|
19
|
+
providers =
|
20
|
+
if @env_config[:providers].is_a?(Hash)
|
21
|
+
@env_config.dig(:providers, :list)
|
22
|
+
else
|
23
|
+
@env_config[:providers]
|
24
|
+
end
|
25
|
+
|
26
|
+
@providers = Array(providers).map(&:to_sym).freeze
|
27
|
+
end
|
28
|
+
|
29
|
+
def provider_config(name)
|
30
|
+
return {} unless @env_config[:providers].is_a?(Hash)
|
31
|
+
|
32
|
+
@env_config.dig(:providers, :config, name) || {}
|
18
33
|
end
|
19
34
|
end
|
20
35
|
end
|
data/lib/unifig/errors.rb
CHANGED
data/lib/unifig/init.rb
CHANGED
@@ -10,7 +10,7 @@ module Unifig
|
|
10
10
|
#
|
11
11
|
# @example
|
12
12
|
# Unifig::Init.load(<<~YML, env: :development)
|
13
|
-
#
|
13
|
+
# unifig:
|
14
14
|
# envs:
|
15
15
|
# development:
|
16
16
|
# providers: local
|
@@ -54,14 +54,14 @@ module Unifig
|
|
54
54
|
# @raise (see Unifig::Var.load!)
|
55
55
|
# @raise (see .complete_substitutions!)
|
56
56
|
def exec!(yml, env: nil)
|
57
|
-
config = Config.new(yml.delete(:
|
57
|
+
config = Config.new(yml.delete(:unifig), env: env)
|
58
58
|
|
59
59
|
providers = Providers.list(config.providers)
|
60
60
|
return if providers.empty?
|
61
61
|
|
62
62
|
Vars.load!(yml, env)
|
63
63
|
|
64
|
-
fetch_from_providers!(providers)
|
64
|
+
fetch_from_providers!(providers, config)
|
65
65
|
|
66
66
|
check_required_vars
|
67
67
|
|
@@ -72,10 +72,10 @@ module Unifig
|
|
72
72
|
attach_missing_optional_methods!(missing_vars)
|
73
73
|
end
|
74
74
|
|
75
|
-
def fetch_from_providers!(providers)
|
75
|
+
def fetch_from_providers!(providers, config)
|
76
76
|
providers.each do |provider|
|
77
77
|
remaining_vars = Vars.list.filter_map { |var| var.name if var.value.nil? }
|
78
|
-
result = provider.retrieve(remaining_vars)
|
78
|
+
result = provider.retrieve(remaining_vars, config.provider_config(provider.name))
|
79
79
|
|
80
80
|
Vars.write_results!(result, provider.name)
|
81
81
|
end
|
@@ -92,6 +92,7 @@ module Unifig
|
|
92
92
|
|
93
93
|
# @raise [CyclicalSubstitutionError] - Subtitutions resulted in a cyclical dependency.
|
94
94
|
# @raise [MissingSubstitutionError] - A substitution does not exist.
|
95
|
+
# @raise (see Unifig::Var#value=)
|
95
96
|
def complete_substitutions!
|
96
97
|
Vars.tsort.each do |name|
|
97
98
|
var = Vars[name]
|
data/lib/unifig/var.rb
CHANGED
@@ -1,8 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'bigdecimal'
|
4
|
+
require 'date'
|
5
|
+
require 'time'
|
6
|
+
|
3
7
|
module Unifig
|
4
8
|
# A variable created after loading a configuration.
|
5
9
|
class Var
|
10
|
+
DEFAULT_INTEGER_BASE = 10
|
11
|
+
private_constant :DEFAULT_INTEGER_BASE
|
12
|
+
|
6
13
|
# @private
|
7
14
|
def initialize(name, config, env)
|
8
15
|
@name = name
|
@@ -31,9 +38,10 @@ module Unifig
|
|
31
38
|
attr_reader :value
|
32
39
|
|
33
40
|
# @private
|
41
|
+
# @raise (see #convert)
|
34
42
|
def value=(obj)
|
35
|
-
value = blank?(obj) ? nil : obj
|
36
|
-
value = value.
|
43
|
+
value = blank?(obj) ? nil : obj.dup
|
44
|
+
value = convert(value).freeze unless value.nil?
|
37
45
|
@value = value
|
38
46
|
end
|
39
47
|
|
@@ -46,7 +54,7 @@ module Unifig
|
|
46
54
|
|
47
55
|
# @private
|
48
56
|
def local_value
|
49
|
-
@local_value ||=
|
57
|
+
@local_value ||= config(:value)
|
50
58
|
end
|
51
59
|
|
52
60
|
# Returns whether or not this is a required variable.
|
@@ -55,7 +63,7 @@ module Unifig
|
|
55
63
|
def required?
|
56
64
|
return @required if defined?(@required)
|
57
65
|
|
58
|
-
optional =
|
66
|
+
optional = config(:optional)
|
59
67
|
optional = @config[:optional] if optional.nil?
|
60
68
|
optional = false if optional.nil?
|
61
69
|
@required = !optional
|
@@ -63,8 +71,81 @@ module Unifig
|
|
63
71
|
|
64
72
|
private
|
65
73
|
|
66
|
-
|
67
|
-
|
74
|
+
# @raise [InvalidTypeError] - A type does not exist.
|
75
|
+
def convert(value)
|
76
|
+
convert = config(:convert)
|
77
|
+
type, options =
|
78
|
+
if convert.is_a?(Hash)
|
79
|
+
[convert[:type], convert.slice(*(convert.keys - [:type]))]
|
80
|
+
else
|
81
|
+
[convert, nil]
|
82
|
+
end
|
83
|
+
type = 'string' if type.nil?
|
84
|
+
options = {} if options.nil?
|
85
|
+
|
86
|
+
if built_in?(type)
|
87
|
+
convert_built_in(type, options, value)
|
88
|
+
else
|
89
|
+
convert_custom_type(type, options, value)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def convert_built_in(type, options, value) # rubocop:disable Metrics
|
94
|
+
case type
|
95
|
+
when 'date'
|
96
|
+
time_convert(Date, options, value)
|
97
|
+
when 'date_time'
|
98
|
+
time_convert(DateTime, options, value)
|
99
|
+
when 'decimal'
|
100
|
+
BigDecimal(value)
|
101
|
+
when 'integer'
|
102
|
+
base = options.fetch(:base, DEFAULT_INTEGER_BASE)
|
103
|
+
Integer(value, base)
|
104
|
+
when 'float'
|
105
|
+
Float(value)
|
106
|
+
when 'string'
|
107
|
+
String(value)
|
108
|
+
when 'symbol'
|
109
|
+
String(value).to_sym
|
110
|
+
when 'time'
|
111
|
+
time_convert(Time, options, value)
|
112
|
+
else
|
113
|
+
raise InvalidTypeError, %(unknown built-in type "#{type}")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def convert_custom_type(type, options, value)
|
118
|
+
klass =
|
119
|
+
begin
|
120
|
+
Kernel.const_get(type)
|
121
|
+
rescue NameError
|
122
|
+
raise InvalidTypeError, %(unknown custom type "#{type}")
|
123
|
+
end
|
124
|
+
|
125
|
+
klass.public_send(options.fetch(:method, :new), value)
|
126
|
+
end
|
127
|
+
|
128
|
+
def integer(value)
|
129
|
+
Integer(value, DEFAULT_INTEGER_BASE)
|
130
|
+
rescue ArgumentError
|
131
|
+
nil
|
132
|
+
end
|
133
|
+
|
134
|
+
def built_in?(type)
|
135
|
+
/\A\p{Ll}/.match?(type) # \p{Ll} = unicode lowercase
|
136
|
+
end
|
137
|
+
|
138
|
+
def time_convert(klass, options, value)
|
139
|
+
return klass.strptime(value, options[:format]) if options[:format]
|
140
|
+
|
141
|
+
klass.parse(value)
|
142
|
+
end
|
143
|
+
|
144
|
+
def config(key)
|
145
|
+
env_conf = @config.dig(:envs, @env, key)
|
146
|
+
return env_conf unless env_conf.nil?
|
147
|
+
|
148
|
+
@config[key]
|
68
149
|
end
|
69
150
|
|
70
151
|
def blank?(value)
|
data/lib/unifig/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -41,9 +41,11 @@ RSpec.configure do |config|
|
|
41
41
|
:forty_two
|
42
42
|
end
|
43
43
|
|
44
|
-
def self.retrieve(var_names)
|
44
|
+
def self.retrieve(var_names, config)
|
45
|
+
num = config.fetch(:num, 42).to_s.freeze
|
46
|
+
|
45
47
|
var_names.to_h do |var_name|
|
46
|
-
[var_name,
|
48
|
+
[var_name, num]
|
47
49
|
end
|
48
50
|
end
|
49
51
|
end
|
data/spec/unifig/config_spec.rb
CHANGED
@@ -24,7 +24,7 @@ RSpec.describe Unifig::Config do
|
|
24
24
|
end
|
25
25
|
|
26
26
|
describe '#providers' do
|
27
|
-
it 'returns a list of providers
|
27
|
+
it 'returns a list of providers' do
|
28
28
|
expect(config.providers).to eql %i[local]
|
29
29
|
end
|
30
30
|
|
@@ -35,5 +35,47 @@ RSpec.describe Unifig::Config do
|
|
35
35
|
expect(config.providers).to eql %i[local forty_two]
|
36
36
|
end
|
37
37
|
end
|
38
|
+
|
39
|
+
context 'with a :list' do
|
40
|
+
let(:config_hash) do
|
41
|
+
{
|
42
|
+
providers: {
|
43
|
+
list: 'local'
|
44
|
+
}
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'returns a list of providers' do
|
49
|
+
expect(config.providers).to eql %i[local]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#provider_config' do
|
55
|
+
it 'returns an empty config if none is provided' do
|
56
|
+
expect(config.provider_config(:local)).to eql({})
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'with a configuration' do
|
60
|
+
let(:local_config) do
|
61
|
+
{
|
62
|
+
here: true
|
63
|
+
}
|
64
|
+
end
|
65
|
+
let(:config_hash) do
|
66
|
+
{
|
67
|
+
providers: {
|
68
|
+
list: 'local',
|
69
|
+
config: {
|
70
|
+
local: local_config
|
71
|
+
}
|
72
|
+
}
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'returns the config info' do
|
77
|
+
expect(config.provider_config(:local)).to eql(local_config)
|
78
|
+
end
|
79
|
+
end
|
38
80
|
end
|
39
81
|
end
|
data/spec/unifig/init_spec.rb
CHANGED
@@ -20,7 +20,7 @@ RSpec.shared_examples 'basic load tests' do
|
|
20
20
|
context 'with a valid config' do
|
21
21
|
let(:str) do
|
22
22
|
<<~YML
|
23
|
-
|
23
|
+
unifig:
|
24
24
|
providers: local
|
25
25
|
|
26
26
|
ONE:
|
@@ -32,7 +32,7 @@ RSpec.shared_examples 'basic load tests' do
|
|
32
32
|
subject
|
33
33
|
|
34
34
|
expect(Unifig).to respond_to(:one)
|
35
|
-
expect(Unifig.one).to
|
35
|
+
expect(Unifig.one).to eql '1'
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
@@ -48,7 +48,7 @@ RSpec.describe Unifig::Init do
|
|
48
48
|
context 'from multiple providers' do
|
49
49
|
let(:str) do
|
50
50
|
<<~YML
|
51
|
-
|
51
|
+
unifig:
|
52
52
|
providers: [local, forty_two]
|
53
53
|
|
54
54
|
ONE:
|
@@ -61,7 +61,31 @@ RSpec.describe Unifig::Init do
|
|
61
61
|
load
|
62
62
|
|
63
63
|
expect(Unifig.one).to eql '42'
|
64
|
-
expect(Unifig.two).to
|
64
|
+
expect(Unifig.two).to eql '2'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'with provider configuration' do
|
69
|
+
let(:str) do
|
70
|
+
<<~YML
|
71
|
+
unifig:
|
72
|
+
providers:
|
73
|
+
list: [local, forty_two]
|
74
|
+
config:
|
75
|
+
forty_two:
|
76
|
+
num: 24
|
77
|
+
|
78
|
+
ONE:
|
79
|
+
TWO:
|
80
|
+
value: 2
|
81
|
+
YML
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'returns the values from the providers in order' do
|
85
|
+
load
|
86
|
+
|
87
|
+
expect(Unifig.one).to eql '24'
|
88
|
+
expect(Unifig.two).to eql '2'
|
65
89
|
end
|
66
90
|
end
|
67
91
|
|
@@ -71,7 +95,7 @@ RSpec.describe Unifig::Init do
|
|
71
95
|
context 'that is available' do
|
72
96
|
let(:str) do
|
73
97
|
<<~YML
|
74
|
-
|
98
|
+
unifig:
|
75
99
|
providers: local
|
76
100
|
|
77
101
|
ONE:
|
@@ -81,7 +105,7 @@ RSpec.describe Unifig::Init do
|
|
81
105
|
end
|
82
106
|
|
83
107
|
it 'loads the var' do
|
84
|
-
expect(Unifig.one).to
|
108
|
+
expect(Unifig.one).to eql '1'
|
85
109
|
end
|
86
110
|
|
87
111
|
it 'sets the predicate to true' do
|
@@ -92,7 +116,7 @@ RSpec.describe Unifig::Init do
|
|
92
116
|
context 'that is not available' do
|
93
117
|
let(:str) do
|
94
118
|
<<~YML
|
95
|
-
|
119
|
+
unifig:
|
96
120
|
providers: local
|
97
121
|
|
98
122
|
ONE:
|
@@ -112,7 +136,7 @@ RSpec.describe Unifig::Init do
|
|
112
136
|
context 'that is not blank' do
|
113
137
|
let(:str) do
|
114
138
|
<<~YML
|
115
|
-
|
139
|
+
unifig:
|
116
140
|
providers: local
|
117
141
|
|
118
142
|
ONE:
|
@@ -137,7 +161,7 @@ RSpec.describe Unifig::Init do
|
|
137
161
|
|
138
162
|
let(:str) do
|
139
163
|
<<~YML
|
140
|
-
|
164
|
+
unifig:
|
141
165
|
providers: local
|
142
166
|
|
143
167
|
ONE:
|
@@ -146,7 +170,7 @@ RSpec.describe Unifig::Init do
|
|
146
170
|
end
|
147
171
|
|
148
172
|
it 'loads the var' do
|
149
|
-
expect(Unifig.one).to
|
173
|
+
expect(Unifig.one).to eql '1'
|
150
174
|
end
|
151
175
|
|
152
176
|
it 'sets the predicate to true' do
|
@@ -157,7 +181,7 @@ RSpec.describe Unifig::Init do
|
|
157
181
|
context 'that is not available' do
|
158
182
|
let(:str) do
|
159
183
|
<<~YML
|
160
|
-
|
184
|
+
unifig:
|
161
185
|
providers: local
|
162
186
|
|
163
187
|
ONE:
|
@@ -173,7 +197,7 @@ RSpec.describe Unifig::Init do
|
|
173
197
|
context 'that is blank' do
|
174
198
|
let(:str) do
|
175
199
|
<<~YML
|
176
|
-
|
200
|
+
unifig:
|
177
201
|
providers: local
|
178
202
|
|
179
203
|
ONE:
|
@@ -190,7 +214,7 @@ RSpec.describe Unifig::Init do
|
|
190
214
|
context 'with substitutions' do
|
191
215
|
let(:str) do
|
192
216
|
<<~YML
|
193
|
-
|
217
|
+
unifig:
|
194
218
|
providers: local
|
195
219
|
|
196
220
|
NAME:
|
@@ -209,7 +233,7 @@ RSpec.describe Unifig::Init do
|
|
209
233
|
context 'when they are out of order' do
|
210
234
|
let(:str) do
|
211
235
|
<<~YML
|
212
|
-
|
236
|
+
unifig:
|
213
237
|
providers: local
|
214
238
|
|
215
239
|
GREETING:
|
@@ -229,7 +253,7 @@ RSpec.describe Unifig::Init do
|
|
229
253
|
context 'when they chain' do
|
230
254
|
let(:str) do
|
231
255
|
<<~YML
|
232
|
-
|
256
|
+
unifig:
|
233
257
|
providers: local
|
234
258
|
|
235
259
|
INTRO:
|
@@ -251,7 +275,7 @@ RSpec.describe Unifig::Init do
|
|
251
275
|
context 'when they cause a cycle' do
|
252
276
|
let(:str) do
|
253
277
|
<<~YML
|
254
|
-
|
278
|
+
unifig:
|
255
279
|
providers: local
|
256
280
|
|
257
281
|
A:
|
@@ -271,7 +295,7 @@ RSpec.describe Unifig::Init do
|
|
271
295
|
context 'when they do not exist' do
|
272
296
|
let(:str) do
|
273
297
|
<<~YML
|
274
|
-
|
298
|
+
unifig:
|
275
299
|
providers: local
|
276
300
|
|
277
301
|
A:
|
data/spec/unifig/var_spec.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
|
1
3
|
RSpec.describe Unifig::Var do
|
2
4
|
subject(:var) { described_class.new(name, config, env) }
|
3
5
|
|
@@ -32,6 +34,263 @@ RSpec.describe Unifig::Var do
|
|
32
34
|
expect(var.value).to eql 'a'
|
33
35
|
expect(var.value).to be_frozen
|
34
36
|
end
|
37
|
+
|
38
|
+
context 'without a type' do
|
39
|
+
it 'defaults to string' do
|
40
|
+
var.value = 1
|
41
|
+
|
42
|
+
expect(var.value).to eql '1'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'with a type of' do
|
47
|
+
context 'string' do
|
48
|
+
before do
|
49
|
+
config.merge!(convert: 'string')
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'converts to a String' do
|
53
|
+
var.value = 1
|
54
|
+
|
55
|
+
expect(var.value).to eql '1'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'integer' do
|
60
|
+
before do
|
61
|
+
config.merge!(convert: 'integer')
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'converts to an Integer' do
|
65
|
+
var.value = '01'
|
66
|
+
|
67
|
+
expect(var.value).to be 1
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'with option' do
|
71
|
+
context 'base' do
|
72
|
+
before do
|
73
|
+
config.merge!(convert: { type: 'integer', base: 2 })
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'converts it using the specified base' do
|
77
|
+
var.value = '11'
|
78
|
+
|
79
|
+
expect(var.value).to be 3
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'float' do
|
86
|
+
before do
|
87
|
+
config.merge!(convert: 'float')
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'converts to a Float' do
|
91
|
+
var.value = '01.1'
|
92
|
+
|
93
|
+
expect(var.value).to be 1.1
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'decimal' do
|
98
|
+
before do
|
99
|
+
config.merge!(convert: 'decimal')
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'converts to a BigDecimal' do
|
103
|
+
var.value = '01.1'
|
104
|
+
|
105
|
+
expect(var.value).to eql BigDecimal('01.1')
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'symbol' do
|
110
|
+
before do
|
111
|
+
config.merge!(convert: 'symbol')
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'converts to a Symbol' do
|
115
|
+
var.value = 'one'
|
116
|
+
|
117
|
+
expect(var.value).to be :one
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'date' do
|
122
|
+
before do
|
123
|
+
config.merge!(convert: 'date')
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'converts to a Date' do
|
127
|
+
var.value = '2022-01-02'
|
128
|
+
|
129
|
+
value = var.value
|
130
|
+
expect(value).to be_an_instance_of Date
|
131
|
+
expect(value.year).to be 2022
|
132
|
+
expect(value.month).to be 1
|
133
|
+
expect(value.day).to be 2
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'with option' do
|
137
|
+
context 'format' do
|
138
|
+
before do
|
139
|
+
config.merge!(convert: { type: 'date', format: '%Y-%m-%d' })
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'converts it using the specified format' do
|
143
|
+
var.value = '2022-01-02'
|
144
|
+
|
145
|
+
value = var.value
|
146
|
+
expect(value).to be_an_instance_of Date
|
147
|
+
expect(value.year).to be 2022
|
148
|
+
expect(value.month).to be 1
|
149
|
+
expect(value.day).to be 2
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'throws an error on the wrong input' do
|
153
|
+
expect { var.value = '2022-01' }.to raise_error Date::Error
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context 'date_time' do
|
160
|
+
before do
|
161
|
+
config.merge!(convert: 'date_time')
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'converts to a DateTime' do
|
165
|
+
var.value = '2022-01-02T03:04:05'
|
166
|
+
|
167
|
+
value = var.value
|
168
|
+
expect(value).to be_an_instance_of DateTime
|
169
|
+
expect(value.year).to be 2022
|
170
|
+
expect(value.month).to be 1
|
171
|
+
expect(value.day).to be 2
|
172
|
+
expect(value.hour).to be 3
|
173
|
+
expect(value.minute).to be 4
|
174
|
+
expect(value.second).to be 5
|
175
|
+
end
|
176
|
+
|
177
|
+
context 'with option' do
|
178
|
+
context 'format' do
|
179
|
+
before do
|
180
|
+
config.merge!(convert: { type: 'date_time', format: '%Y-%m-%dT%H:%M:%S' })
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'converts it using the specified format' do
|
184
|
+
var.value = '2022-01-02T03:04:05'
|
185
|
+
|
186
|
+
value = var.value
|
187
|
+
expect(value).to be_an_instance_of DateTime
|
188
|
+
expect(value.year).to be 2022
|
189
|
+
expect(value.month).to be 1
|
190
|
+
expect(value.day).to be 2
|
191
|
+
expect(value.hour).to be 3
|
192
|
+
expect(value.minute).to be 4
|
193
|
+
expect(value.second).to be 5
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'throws an error on the wrong input' do
|
197
|
+
expect { var.value = '2022-01' }.to raise_error DateTime::Error
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
context 'time' do
|
204
|
+
before do
|
205
|
+
config.merge!(convert: 'time')
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'converts to a Time' do
|
209
|
+
var.value = '2022-01-02T03:04:05'
|
210
|
+
|
211
|
+
value = var.value
|
212
|
+
expect(value).to be_an_instance_of Time
|
213
|
+
expect(value.year).to be 2022
|
214
|
+
expect(value.month).to be 1
|
215
|
+
expect(value.day).to be 2
|
216
|
+
expect(value.hour).to be 3
|
217
|
+
expect(value.min).to be 4
|
218
|
+
expect(value.sec).to be 5
|
219
|
+
end
|
220
|
+
|
221
|
+
context 'with option' do
|
222
|
+
context 'format' do
|
223
|
+
before do
|
224
|
+
config.merge!(convert: { type: 'time', format: '%Y-%m-%dT%H:%M:%S' })
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'converts it using the specified format' do
|
228
|
+
var.value = '2022-01-02T03:04:05'
|
229
|
+
|
230
|
+
value = var.value
|
231
|
+
expect(value).to be_an_instance_of Time
|
232
|
+
expect(value.year).to be 2022
|
233
|
+
expect(value.month).to be 1
|
234
|
+
expect(value.day).to be 2
|
235
|
+
expect(value.hour).to be 3
|
236
|
+
expect(value.min).to be 4
|
237
|
+
expect(value.sec).to be 5
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'throws an error on the wrong input' do
|
241
|
+
expect { var.value = '2022-01' }.to raise_error ArgumentError
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
context 'invalid' do
|
248
|
+
before do
|
249
|
+
config.merge!(convert: 'invalid')
|
250
|
+
end
|
251
|
+
|
252
|
+
it 'throws an error' do
|
253
|
+
expect { var.value = 1 }.to raise_error Unifig::InvalidTypeError
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
context 'custom' do
|
258
|
+
before do
|
259
|
+
config.merge!(convert: 'IPAddr')
|
260
|
+
end
|
261
|
+
|
262
|
+
it 'converts to the class provided using .new' do
|
263
|
+
var.value = '127.0.0.1'
|
264
|
+
|
265
|
+
value = var.value
|
266
|
+
expect(value).to be_an_instance_of IPAddr
|
267
|
+
expect(value).to be_ipv4
|
268
|
+
expect(value.to_s).to eql '127.0.0.1'
|
269
|
+
end
|
270
|
+
|
271
|
+
context 'with a custom method' do
|
272
|
+
before do
|
273
|
+
config.merge!(convert: { type: 'Encoding', method: 'find' })
|
274
|
+
end
|
275
|
+
|
276
|
+
it 'uses the method provided' do
|
277
|
+
var.value = 'ascii'
|
278
|
+
|
279
|
+
expect(var.value).to be Encoding::US_ASCII
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
context 'with an invalid class' do
|
284
|
+
before do
|
285
|
+
config.merge!(convert: 'Invalid')
|
286
|
+
end
|
287
|
+
|
288
|
+
it 'throws an error' do
|
289
|
+
expect { var.value = 'invalid' }.to raise_error Unifig::InvalidTypeError
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
35
294
|
end
|
36
295
|
|
37
296
|
describe '#local_value' do
|
data/spec/unifig/vars_spec.rb
CHANGED
@@ -24,7 +24,7 @@ RSpec.describe Unifig::Vars do
|
|
24
24
|
expect(vars.size).to be 2
|
25
25
|
vars.each.with_index(1) do |var, value|
|
26
26
|
expect(var).to be_an_instance_of Unifig::Var
|
27
|
-
expect(var.value).to
|
27
|
+
expect(var.value).to eql String(value)
|
28
28
|
expect(var.provider).to be :local
|
29
29
|
end
|
30
30
|
end
|
@@ -35,7 +35,7 @@ RSpec.describe Unifig::Vars do
|
|
35
35
|
var = described_class[:one]
|
36
36
|
|
37
37
|
expect(var).to be_an_instance_of Unifig::Var
|
38
|
-
expect(var.value).to
|
38
|
+
expect(var.value).to eql '1'
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unifig
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Lasseigne
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-09-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: tsort
|