opto 1.8.7 → 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +11 -8
- data/README.md +75 -8
- data/lib/opto/group.rb +55 -20
- data/lib/opto/option.rb +53 -14
- data/lib/opto/resolver.rb +0 -22
- data/lib/opto/resolvers/condition.rb +0 -4
- data/lib/opto/resolvers/evaluate.rb +1 -5
- data/lib/opto/resolvers/interpolate.rb +8 -12
- data/lib/opto/resolvers/yaml.rb +45 -0
- data/lib/opto/types/group.rb +28 -0
- data/lib/opto/version.rb +1 -1
- data/opto.gemspec +2 -2
- metadata +8 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8d5546d31ee73e05adce64402dca900e55ef7159fcb277327fedf8bee0db2d00
|
4
|
+
data.tar.gz: 8dcaaf5040b306b4997f01124f2597a500c230f0a32d2ca5071c9d80e2bb536c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 683dd71495e9ea808933e58416d81fb8ebc815ec0b34834bf14e4d4a7595ce478417287369184928033b6b309ff89797a39a4da0418f5f324a314b09308e7fe0
|
7
|
+
data.tar.gz: b4012a61a1a01b1a0ba7ef545956435939d329cd60400f37966b700a4ccc7e0f10c7223b19dd1a985a6383f5ce1b2d399c9914a411cdeb2d15b22597e4a383c9
|
data/.travis.yml
CHANGED
@@ -1,18 +1,21 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
- 2.
|
4
|
-
- 2.
|
5
|
-
- 2.
|
6
|
-
- 2.4.1
|
3
|
+
- 2.3
|
4
|
+
- 2.4
|
5
|
+
- 2.5
|
7
6
|
env:
|
8
7
|
- secure: "bCu1bVzr6SP+gAbMo88GvcHHbhO3LcnJtWp+YuSZ5qW4EHhdBw+DOQeOlzoKHtYhNhptmb/65pZZctRTE6jOOSZzpOUHaeqaqHZpELldkCMu7rE8bXuCV4OfhG0CKWvURS0x5p5F5onEx1a1sjiu+MVEUqktAPDAcdTBNBW1irRwvnSifgjcZRLzfm1aRs1fqzBJpHaAXyD++2GQaWyXDtQsEsc/Eyhmnkac5Y2cTeQiYlDluqBeB885q9K16ruLp2NWx/rnR8RGMP1LSnrye/GEo2mRWOWy1MyIEwNDcVaA6MVDY2GBIQUoXg4PBrZAleVIsO3LzwR4oorFCaSgWxzqYI67g5Kb2zn8fW9Yu5lDcFEJKIHQAwBrlq3n3Mi5it/IxGQDWXQ/2fjBxCwuilvI0WTzOH0m4g8Uf6jHaQLFC6ahdWDjfs6aCzdPpbJls26/r39NIB5k/6ZO29NZkxGBsQ7E7m4wurr7a9ksLODgPOyPiB8/4Txu35Llp+IuJpbshrlkRIMwEIFVWiLi6MZhRBkxaRzlkJQ0bS3RD9W4z9UJyoBujmgXMrv0eHNTGCOC+/4tvrA+pXzJwmFQJA6TnenoDl9hc6o03gyfH/YvmMgrtJLbJ8rGoLRaY8HsQwHWgimpCl1o043kO8/UkhhS7J4wyQXYwqGnA2PC/j0="
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
bundler_args: --with test development --jobs=3 --retry=3 --path=${BUNDLE_PATH:-vendor/bundle}
|
9
|
+
before_install:
|
10
|
+
- gem update --system
|
11
|
+
- gem install bundler
|
12
|
+
script: bundle exec rspec spec/
|
13
|
+
cache:
|
14
|
+
bundler: true
|
12
15
|
deploy:
|
13
16
|
provider: rubygems
|
14
17
|
api_key: $GEM_TOKEN
|
15
18
|
gem: opto
|
16
19
|
on:
|
17
20
|
tags: true
|
18
|
-
rvm: 2.
|
21
|
+
rvm: 2.5
|
data/README.md
CHANGED
@@ -45,10 +45,12 @@ require 'opto'
|
|
45
45
|
foo_username:
|
46
46
|
type: string
|
47
47
|
required: true
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
validate:
|
49
|
+
min_length: 1
|
50
|
+
max_length: 30
|
51
|
+
transform:
|
52
|
+
- strip # remove leading / trailing whitespace
|
53
|
+
- upcase # make UPCASE
|
52
54
|
from:
|
53
55
|
env: FOO_USER # read value from ENV variable FOO_USER
|
54
56
|
```
|
@@ -72,16 +74,18 @@ require 'opto'
|
|
72
74
|
foo_instances:
|
73
75
|
type: integer
|
74
76
|
default: 1
|
75
|
-
|
76
|
-
|
77
|
+
validate:
|
78
|
+
min: 1
|
79
|
+
max: 30
|
77
80
|
```
|
78
81
|
|
79
82
|
```yaml
|
80
83
|
# Uri validator
|
81
84
|
host_url:
|
82
85
|
type: uri
|
83
|
-
|
84
|
-
|
86
|
+
validate:
|
87
|
+
schemes:
|
88
|
+
- file # only allow file:/// uris
|
85
89
|
```
|
86
90
|
|
87
91
|
## Resolvers
|
@@ -343,6 +347,14 @@ end
|
|
343
347
|
from: prompter
|
344
348
|
```
|
345
349
|
|
350
|
+
You can also use procs:
|
351
|
+
|
352
|
+
```ruby
|
353
|
+
group = Opto::Group.new(
|
354
|
+
resolvers: { prompt: proc { |hint, option| print "Enter #{hint} (default: #{option.default}): "; gets }
|
355
|
+
)
|
356
|
+
```
|
357
|
+
|
346
358
|
## Subclassing a predefined type handler, setter, etc
|
347
359
|
|
348
360
|
```ruby
|
@@ -459,6 +471,23 @@ Global validations:
|
|
459
471
|
}
|
460
472
|
```
|
461
473
|
|
474
|
+
### group
|
475
|
+
|
476
|
+
Allows nesting of Opto::Groups:
|
477
|
+
|
478
|
+
```yaml
|
479
|
+
subgroup:
|
480
|
+
type: group
|
481
|
+
value:
|
482
|
+
subvariable:
|
483
|
+
type: string
|
484
|
+
value: world
|
485
|
+
greeting:
|
486
|
+
type: string
|
487
|
+
from:
|
488
|
+
interpolate: hello, ${subgroup.subvariable} # becomes hello, world
|
489
|
+
```
|
490
|
+
|
462
491
|
## Default resolvers
|
463
492
|
Hint is the value that gets passed to the resolver when doing for example: `env: FOO` (FOO is the hint)
|
464
493
|
|
@@ -598,6 +627,44 @@ When an "else" is not defined and none of the conditions match, a null value wil
|
|
598
627
|
|
599
628
|
The syntax for conditionals and complex conditionals is documented above in the chapter about conditionals.
|
600
629
|
|
630
|
+
### yaml
|
631
|
+
|
632
|
+
Hint is a hash defining filename or variable containing YAML source and optionally a key
|
633
|
+
|
634
|
+
Example:
|
635
|
+
```yaml
|
636
|
+
# Read a string value from a key in YAML file
|
637
|
+
str:
|
638
|
+
type: string
|
639
|
+
from:
|
640
|
+
yaml:
|
641
|
+
file: .env
|
642
|
+
key: STR
|
643
|
+
|
644
|
+
# Read an array from a nested key in a YAML file
|
645
|
+
str2:
|
646
|
+
type: array
|
647
|
+
from:
|
648
|
+
yaml:
|
649
|
+
file: variables.yml
|
650
|
+
key: variables.str2.value # assuming { variables: { str2: { value: ["abcd", "defg"] } } }
|
651
|
+
|
652
|
+
# Read a YAML file into a string
|
653
|
+
yaml_content:
|
654
|
+
type: string
|
655
|
+
from:
|
656
|
+
file: /etc/config.yml
|
657
|
+
|
658
|
+
# Read YAML content from a variable and fetch a key from it
|
659
|
+
str3:
|
660
|
+
type: string
|
661
|
+
from:
|
662
|
+
yaml:
|
663
|
+
variable: yaml_content
|
664
|
+
key: settings.cpu_arch
|
665
|
+
```
|
666
|
+
|
667
|
+
|
601
668
|
## Default setters
|
602
669
|
|
603
670
|
### env
|
data/lib/opto/group.rb
CHANGED
@@ -11,35 +11,52 @@ module Opto
|
|
11
11
|
|
12
12
|
using Opto::Extension::HashStringOrSymbolKey
|
13
13
|
|
14
|
-
attr_reader :options, :defaults
|
15
|
-
|
16
14
|
extend Forwardable
|
17
15
|
|
18
16
|
# Initialize a new Option Group. You can also pass in :defaults.
|
19
17
|
#
|
20
18
|
# @param [Array<Hash,Opto::Option>,Hash,NilClass] opts An array of Option definition hashes or Option objects or a hash like { var_name: { opts } }.
|
21
19
|
# @return [Opto::Group]
|
22
|
-
def initialize(*
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
raise TypeError, "Invalid type #{options.first.class} for Opto::Group.new"
|
20
|
+
def initialize(*opts)
|
21
|
+
case opts.first
|
22
|
+
when NilClass
|
23
|
+
when Hash
|
24
|
+
defaults.merge!(opts.first.delete(:defaults)) if opts.first.key?(:defaults)
|
25
|
+
setters.merge!(opts.first.delete(:setters)) if opts.first.key?(:setters)
|
26
|
+
resolvers.merge!(opts.first.delete(:resolvers)) if opts.first.key?(:resolvers)
|
27
|
+
options.concat(opts.first.map {|k,v| Option.new({name: k.to_s, group: self}.merge(v))})
|
28
|
+
when ::Array
|
29
|
+
if opts.last.is_a?(Hash) && !opts.last.key?(:type)
|
30
|
+
opts.pop.tap do |settings|
|
31
|
+
defaults.merge!(settings[:defaults]) if settings.key?(:defaults)
|
32
|
+
setters.merge!(settings[:setters]) if settings.key?(:setters)
|
33
|
+
resolvers.merge!(settings[:resolvers]) if settings.key?(:resolvers)
|
37
34
|
end
|
35
|
+
end
|
36
|
+
if opts.first.kind_of?(Array)
|
37
|
+
options.concat(opts.first.map { |opt| opt.kind_of?(Opto::Option) ? opt : Option.new(opt.merge(group: self)) })
|
38
|
+
end
|
38
39
|
else
|
39
|
-
|
40
|
+
raise TypeError, "Invalid type #{opts.class} for Opto::Group.new"
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|
44
|
+
def options
|
45
|
+
@options ||= []
|
46
|
+
end
|
47
|
+
|
48
|
+
def setters
|
49
|
+
@setters ||= {}
|
50
|
+
end
|
51
|
+
|
52
|
+
def resolvers
|
53
|
+
@resolvers ||= {}
|
54
|
+
end
|
55
|
+
|
56
|
+
def defaults
|
57
|
+
@defaults ||= {}
|
58
|
+
end
|
59
|
+
|
43
60
|
# Are all options valid? (Option value passes validation)
|
44
61
|
# @return [Boolean]
|
45
62
|
def valid?
|
@@ -91,7 +108,25 @@ module Opto
|
|
91
108
|
# @param [String] option_name
|
92
109
|
# @return [Opto::Option]
|
93
110
|
def option(option_name)
|
94
|
-
|
111
|
+
if option_name.to_s.include?('.')
|
112
|
+
parts = option_name.to_s.split('.')
|
113
|
+
var_name = parts.pop
|
114
|
+
group = parts.inject(self) do |base, part|
|
115
|
+
grp = base.option(part).value
|
116
|
+
if grp.nil?
|
117
|
+
raise NameError, "No such group: #{base.name}.#{part}"
|
118
|
+
elsif grp.kind_of?(Opto::Group)
|
119
|
+
grp
|
120
|
+
else
|
121
|
+
raise TypeError, "Is not a group: #{base.name}.#{part}"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
else
|
125
|
+
group = self
|
126
|
+
var_name = option_name
|
127
|
+
end
|
128
|
+
|
129
|
+
group.options.find { |opt| opt.name == var_name }
|
95
130
|
end
|
96
131
|
|
97
132
|
# Get a value of a member by option name
|
@@ -180,6 +215,6 @@ module Opto
|
|
180
215
|
end
|
181
216
|
end
|
182
217
|
|
183
|
-
def_delegators
|
218
|
+
def_delegators :options, *(::Array.instance_methods - [:__send__, :object_id, :to_h, :to_a, :is_a?, :kind_of?, :instance_of?, :self, :inspect, :nil?])
|
184
219
|
end
|
185
220
|
end
|
data/lib/opto/option.rb
CHANGED
@@ -86,12 +86,27 @@ module Opto
|
|
86
86
|
@only_if = opts.delete(:only_if)
|
87
87
|
@from = normalize_from_to(opts.delete(:from))
|
88
88
|
@to = normalize_from_to(opts.delete(:to))
|
89
|
-
|
89
|
+
validations = opts.delete(:validate).to_h
|
90
|
+
transforms = opts.delete(:transform)
|
91
|
+
transforms = case transforms
|
92
|
+
when NilClass then {}
|
93
|
+
when Hash then transforms
|
94
|
+
when Array then
|
95
|
+
transforms.each_with_object({}) { |t, hash| hash[t] = true }
|
96
|
+
else
|
97
|
+
raise TypeError, 'Transform has to be a hash or an array'
|
98
|
+
end
|
99
|
+
@type_options = opts.merge(validations).merge(transforms)
|
100
|
+
@tried_resolve = false
|
90
101
|
|
91
102
|
set_initial(val) if val
|
92
103
|
deep_merge_defaults
|
93
104
|
end
|
94
105
|
|
106
|
+
def has_group?
|
107
|
+
!group.nil?
|
108
|
+
end
|
109
|
+
|
95
110
|
def deep_merge_defaults
|
96
111
|
return nil unless group && group.defaults
|
97
112
|
if group.defaults[:from]
|
@@ -140,7 +155,7 @@ module Opto
|
|
140
155
|
# Returns true if this field should not be processed because of the conditionals
|
141
156
|
# @return [Boolean]
|
142
157
|
def skip?
|
143
|
-
return false
|
158
|
+
return false unless has_group?
|
144
159
|
return true if group.any_true?(skip_if)
|
145
160
|
return true unless group.all_true?(only_if)
|
146
161
|
false
|
@@ -150,7 +165,8 @@ module Opto
|
|
150
165
|
# @param [String] option_name
|
151
166
|
def value_of(option_name)
|
152
167
|
return value if option_name == self.name
|
153
|
-
|
168
|
+
return nil unless has_group?
|
169
|
+
group.value_of(option_name)
|
154
170
|
end
|
155
171
|
|
156
172
|
# Run validators
|
@@ -181,11 +197,11 @@ module Opto
|
|
181
197
|
# Accessor to defined resolvers for this option.
|
182
198
|
# @return [Array<Opto::Resolver>]
|
183
199
|
def resolvers
|
184
|
-
@resolvers ||= from.merge(default: self).map { |origin, hint| Resolver.for(origin)
|
200
|
+
@resolvers ||= from.merge(default: self).map { |origin, hint| { origin: origin, hint: hint, resolver: ((has_group? && group.resolvers[origin]) || Resolver.for(origin)) } }
|
185
201
|
end
|
186
202
|
|
187
203
|
def setters
|
188
|
-
@setters ||= to.map { |target, hint| Setter.for(target)
|
204
|
+
@setters ||= to.map { |target, hint| { target: target, hint: hint, setter: ((has_group? && group.setters[target]) || Setter.for(target)) } }
|
189
205
|
end
|
190
206
|
|
191
207
|
# True if this field is defined as required: true
|
@@ -194,32 +210,55 @@ module Opto
|
|
194
210
|
handler.required?
|
195
211
|
end
|
196
212
|
|
213
|
+
def tried_resolve?
|
214
|
+
@tried_resolve
|
215
|
+
end
|
216
|
+
|
217
|
+
def set_tried
|
218
|
+
@tried_resolve = true
|
219
|
+
end
|
220
|
+
|
221
|
+
def unset_tried!
|
222
|
+
@tried_resolve = false
|
223
|
+
end
|
224
|
+
|
197
225
|
# Run resolvers
|
198
226
|
# @raise [TypeError, ArgumentError]
|
199
227
|
def resolve
|
200
|
-
|
228
|
+
return nil if tried_resolve?
|
229
|
+
resolvers.each do |resolver_config|
|
201
230
|
begin
|
202
|
-
|
231
|
+
resolver = resolver_config[:resolver]
|
232
|
+
if resolver.respond_to?(:call)
|
233
|
+
result = resolver.call(resolver_config[:hint], self)
|
234
|
+
else
|
235
|
+
result = resolver.new(resolver_config[:hint], self).resolve
|
236
|
+
end
|
203
237
|
rescue StandardError => ex
|
204
|
-
raise ex, "Resolver '#{
|
238
|
+
raise ex, "Resolver '#{resolver_config[:origin]}' for '#{name}' : #{ex.message}"
|
205
239
|
end
|
206
240
|
unless result.nil?
|
207
|
-
@origin =
|
241
|
+
@origin = resolver_config[:origin]
|
208
242
|
return result
|
209
243
|
end
|
210
244
|
end
|
211
245
|
nil
|
246
|
+
ensure
|
247
|
+
set_tried
|
212
248
|
end
|
213
249
|
|
214
250
|
# Run setters
|
215
251
|
def output
|
216
|
-
setters.each do |
|
252
|
+
setters.each do |setter_config|
|
217
253
|
begin
|
218
|
-
setter
|
219
|
-
setter.
|
220
|
-
|
254
|
+
setter = setter_config[:setter]
|
255
|
+
if setter.respond_to?(:call)
|
256
|
+
setter.call(setter_config[:hint], value, self)
|
257
|
+
else
|
258
|
+
setter.new(setter_config[:hint], self).set(value)
|
259
|
+
end
|
221
260
|
rescue StandardError => ex
|
222
|
-
raise ex, "Setter '#{
|
261
|
+
raise ex, "Setter '#{setter_config[:target]}' for '#{name}' : #{ex.message}"
|
223
262
|
end
|
224
263
|
end
|
225
264
|
end
|
data/lib/opto/resolver.rb
CHANGED
@@ -43,28 +43,6 @@ module Opto
|
|
43
43
|
def initialize(hint = nil, option = nil)
|
44
44
|
@hint = hint
|
45
45
|
@option = option
|
46
|
-
@tried = false
|
47
|
-
end
|
48
|
-
|
49
|
-
def tried?
|
50
|
-
!!@tried
|
51
|
-
end
|
52
|
-
|
53
|
-
def set_tried
|
54
|
-
@tried = true
|
55
|
-
end
|
56
|
-
|
57
|
-
def reset_tried
|
58
|
-
@tried = false
|
59
|
-
end
|
60
|
-
|
61
|
-
def try_resolve
|
62
|
-
return nil if tried?
|
63
|
-
set_tried
|
64
|
-
self.respond_to?(:before) && self.before
|
65
|
-
result = resolve
|
66
|
-
self.respond_to?(:after) && self.after
|
67
|
-
result
|
68
46
|
end
|
69
47
|
|
70
48
|
# This is a "base" class, you're supposed to inherit from this in your resolver and define a #resolve method.
|
@@ -10,7 +10,7 @@ module Opto
|
|
10
10
|
|
11
11
|
def resolve
|
12
12
|
raise TypeError, "String required" unless hint.kind_of?(String)
|
13
|
-
interpolated_hint = hint.gsub(/(?<!\$)\$(?!\$)\{
|
13
|
+
interpolated_hint = hint.gsub(/(?<!\$)\$(?!\$)\{?[\w\.]+\}?/) do |v|
|
14
14
|
var = v.tr('${}', '')
|
15
15
|
if option.group.nil? || option.group.option(var).nil?
|
16
16
|
raise RuntimeError, "Variable #{var} not declared"
|
@@ -27,10 +27,6 @@ module Opto
|
|
27
27
|
raise TypeError, "Syntax error: '#{interpolated_hint}' does not look like a number or a calculation"
|
28
28
|
end
|
29
29
|
end
|
30
|
-
|
31
|
-
def after
|
32
|
-
reset_tried
|
33
|
-
end
|
34
30
|
end
|
35
31
|
end
|
36
32
|
end
|
@@ -14,20 +14,16 @@ module Opto
|
|
14
14
|
|
15
15
|
def resolve
|
16
16
|
raise TypeError, "String expected" unless hint.kind_of?(String)
|
17
|
-
hint.gsub(/(?<!\$)\$(?!\$)\{
|
17
|
+
hint.gsub(/(?<!\$)\$(?!\$)\{?[\w\.]+\}?/) do |v|
|
18
18
|
var = v.tr('${}', '')
|
19
|
-
if option.group.nil? || option.group.option(var).nil?
|
20
|
-
raise RuntimeError, "Variable #{var} not declared"
|
21
|
-
end
|
22
|
-
if option.value_of(var).nil?
|
23
|
-
raise RuntimeError, "No value for #{var}, note that the order is meaningful"
|
24
|
-
end
|
25
|
-
option.value_of(var)
|
26
|
-
end
|
27
|
-
end
|
28
19
|
|
29
|
-
|
30
|
-
|
20
|
+
raise RuntimeError, "Variable #{var} not declared" if option.group.nil?
|
21
|
+
opt = option.group.option(var)
|
22
|
+
raise RuntimeError, "Variable #{var} not declared" if opt.nil?
|
23
|
+
value = opt.value
|
24
|
+
raise RuntimeError, "No value for #{var}, note that the order is meaningful" if value.nil?
|
25
|
+
value
|
26
|
+
end
|
31
27
|
end
|
32
28
|
end
|
33
29
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'opto/extensions/snake_case'
|
2
|
+
require 'opto/extensions/hash_string_or_symbol_key'
|
3
|
+
|
4
|
+
module Opto
|
5
|
+
module Resolvers
|
6
|
+
# Loads values from YAML files
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
# from:
|
10
|
+
# yaml:
|
11
|
+
# file: foofoo.yml
|
12
|
+
# key: foo
|
13
|
+
class Yaml < Opto::Resolver
|
14
|
+
|
15
|
+
using Opto::Extension::HashStringOrSymbolKey
|
16
|
+
|
17
|
+
def resolve
|
18
|
+
raise TypeError, "Hash expected" unless hint.kind_of?(Hash)
|
19
|
+
|
20
|
+
require 'yaml' unless Kernel.const_defined?(:YAML)
|
21
|
+
|
22
|
+
if hint[:file]
|
23
|
+
yaml = YAML.safe_load(::File.read(hint[:file]), [], [], true, hint[:file])
|
24
|
+
elsif hint[:variable]
|
25
|
+
raise TypeError, "Option not in a group" unless option.has_group?
|
26
|
+
other_opt = option.group.option(hint[:variable])
|
27
|
+
raise ArgumentError, "No such option: #{hint[:variable]}" if other_opt.nil?
|
28
|
+
yaml = YAML.safe_load(other_opt.value.to_s, [], [], true, hint[:variable])
|
29
|
+
else
|
30
|
+
raise TypeError, "Missing file/variable definition"
|
31
|
+
end
|
32
|
+
if hint[:key]
|
33
|
+
raise TypeError, "Source is not a hash" unless yaml.kind_of?(Hash)
|
34
|
+
if yaml.key?(hint[:key])
|
35
|
+
yaml[hint[:key]]
|
36
|
+
elsif hint[:key].include?('.')
|
37
|
+
yaml.dig(*hint[:key].split('.'))
|
38
|
+
end
|
39
|
+
else
|
40
|
+
yaml
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative '../type'
|
2
|
+
|
3
|
+
module Opto
|
4
|
+
module Types
|
5
|
+
# A subgroup
|
6
|
+
class Group < Opto::Type
|
7
|
+
using Opto::Extension::HashStringOrSymbolKey
|
8
|
+
|
9
|
+
true_when do |value|
|
10
|
+
value.kind_of?(Opto::Group) && !value.empty?
|
11
|
+
end
|
12
|
+
|
13
|
+
sanitizer :init do |value|
|
14
|
+
if options[:variables]
|
15
|
+
Opto::Group.new(options[:variables])
|
16
|
+
elsif value.kind_of?(::Hash) || value.kind_of?(::Array)
|
17
|
+
Opto::Group.new(value)
|
18
|
+
elsif value.kind_of?(Opto::Group)
|
19
|
+
value
|
20
|
+
elsif value.nil?
|
21
|
+
Opto::Group.new
|
22
|
+
else
|
23
|
+
raise TypeError, "Invalid type #{value.class.name} for a group"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/opto/version.rb
CHANGED
data/opto.gemspec
CHANGED
@@ -18,9 +18,9 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.required_ruby_version = ">= 2.
|
21
|
+
spec.required_ruby_version = ">= 2.3.0"
|
22
22
|
|
23
23
|
spec.add_development_dependency "bundler", "~> 1.12"
|
24
|
-
spec.add_development_dependency "rake", "
|
24
|
+
spec.add_development_dependency "rake", ">= 10.0"
|
25
25
|
spec.add_development_dependency "rspec", "~> 3.0"
|
26
26
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: opto
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kimmo Lehto
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-05-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -28,14 +28,14 @@ dependencies:
|
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '10.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '10.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
@@ -83,12 +83,14 @@ files:
|
|
83
83
|
- lib/opto/resolvers/random_string.rb
|
84
84
|
- lib/opto/resolvers/random_uuid.rb
|
85
85
|
- lib/opto/resolvers/variable.rb
|
86
|
+
- lib/opto/resolvers/yaml.rb
|
86
87
|
- lib/opto/setter.rb
|
87
88
|
- lib/opto/setters/environment_variable.rb
|
88
89
|
- lib/opto/type.rb
|
89
90
|
- lib/opto/types/array.rb
|
90
91
|
- lib/opto/types/boolean.rb
|
91
92
|
- lib/opto/types/enum.rb
|
93
|
+
- lib/opto/types/group.rb
|
92
94
|
- lib/opto/types/integer.rb
|
93
95
|
- lib/opto/types/string.rb
|
94
96
|
- lib/opto/types/uri.rb
|
@@ -106,7 +108,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
106
108
|
requirements:
|
107
109
|
- - ">="
|
108
110
|
- !ruby/object:Gem::Version
|
109
|
-
version: 2.
|
111
|
+
version: 2.3.0
|
110
112
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
113
|
requirements:
|
112
114
|
- - ">="
|
@@ -114,7 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
114
116
|
version: '0'
|
115
117
|
requirements: []
|
116
118
|
rubyforge_project:
|
117
|
-
rubygems_version: 2.
|
119
|
+
rubygems_version: 2.7.7
|
118
120
|
signing_key:
|
119
121
|
specification_version: 4
|
120
122
|
summary: Option validator / resolver
|