unifig 0.3.2 → 0.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/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
|