collapsium-config 0.4.3 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/Gemfile.lock +10 -10
- data/collapsium-config.gemspec +2 -2
- data/lib/collapsium-config.rb +19 -1
- data/lib/collapsium-config/configuration.rb +42 -15
- data/lib/collapsium-config/version.rb +1 -1
- data/spec/configuration_spec.rb +45 -8
- data/spec/data/global.yml +2 -0
- data/spec/module_spec.rb +9 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 31e518d37d4cdaa12f8a8718c3ca5816939b6ab2
|
4
|
+
data.tar.gz: 3d466b1b37734a90beafa962991fd9735734ea39
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7052b7b696d6b7cb5422fa2e6236656de330ffc28ecf08fdb0db52593b36a5fab2d219333ef8ea0c55b3ae83c7a18704d0c7fb998c77caece40e8ebac69fd94a
|
7
|
+
data.tar.gz: 85bddfd097bce75d0285c01e1f1da0dfc612f127be4bfc769481669e75df7425a6e67ecd9b11f551378da7edef29cd944a8ca38928a49cfd2da4305023145fc1
|
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,23 +1,23 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
collapsium-config (0.
|
5
|
-
collapsium (~> 0.
|
4
|
+
collapsium-config (0.5.0)
|
5
|
+
collapsium (~> 0.8)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
10
|
ast (2.3.0)
|
11
|
-
codeclimate-test-reporter (1.0.
|
11
|
+
codeclimate-test-reporter (1.0.4)
|
12
12
|
simplecov
|
13
|
-
collapsium (0.
|
13
|
+
collapsium (0.8.2)
|
14
14
|
diff-lcs (1.2.5)
|
15
15
|
docile (1.1.5)
|
16
16
|
json (2.0.2)
|
17
|
-
parser (2.3.
|
17
|
+
parser (2.3.3.1)
|
18
18
|
ast (~> 2.2)
|
19
19
|
powerpack (0.1.1)
|
20
|
-
rainbow (2.1
|
20
|
+
rainbow (2.2.1)
|
21
21
|
rake (11.3.0)
|
22
22
|
rspec (3.5.0)
|
23
23
|
rspec-core (~> 3.5.0)
|
@@ -32,7 +32,7 @@ GEM
|
|
32
32
|
diff-lcs (>= 1.2.0, < 2.0)
|
33
33
|
rspec-support (~> 3.5.0)
|
34
34
|
rspec-support (3.5.0)
|
35
|
-
rubocop (0.
|
35
|
+
rubocop (0.46.0)
|
36
36
|
parser (>= 2.3.1.1, < 3.0)
|
37
37
|
powerpack (~> 0.1)
|
38
38
|
rainbow (>= 1.99.1, < 3.0)
|
@@ -44,8 +44,8 @@ GEM
|
|
44
44
|
json (>= 1.8, < 3)
|
45
45
|
simplecov-html (~> 0.10.0)
|
46
46
|
simplecov-html (0.10.0)
|
47
|
-
unicode-display_width (1.1.
|
48
|
-
yard (0.9.
|
47
|
+
unicode-display_width (1.1.2)
|
48
|
+
yard (0.9.6)
|
49
49
|
|
50
50
|
PLATFORMS
|
51
51
|
ruby
|
@@ -56,7 +56,7 @@ DEPENDENCIES
|
|
56
56
|
collapsium-config!
|
57
57
|
rake (~> 11.3)
|
58
58
|
rspec (~> 3.5)
|
59
|
-
rubocop (~> 0.
|
59
|
+
rubocop (~> 0.46)
|
60
60
|
simplecov (~> 0.12)
|
61
61
|
yard (~> 0.9)
|
62
62
|
|
data/collapsium-config.gemspec
CHANGED
@@ -38,13 +38,13 @@ Gem::Specification.new do |spec|
|
|
38
38
|
spec.required_ruby_version = '>= 2.0'
|
39
39
|
|
40
40
|
spec.add_development_dependency "bundler", "~> 1.12"
|
41
|
-
spec.add_development_dependency "rubocop", "~> 0.
|
41
|
+
spec.add_development_dependency "rubocop", "~> 0.46"
|
42
42
|
spec.add_development_dependency "rake", "~> 11.3"
|
43
43
|
spec.add_development_dependency "rspec", "~> 3.5"
|
44
44
|
spec.add_development_dependency "simplecov", "~> 0.12"
|
45
45
|
spec.add_development_dependency "yard", "~> 0.9"
|
46
46
|
|
47
|
-
spec.add_dependency 'collapsium', '~> 0.
|
47
|
+
spec.add_dependency 'collapsium', '~> 0.8'
|
48
48
|
end
|
49
49
|
# rubocop:enable Metrics/BlockLength
|
50
50
|
# rubocop:enable Style/SpaceAroundOperators
|
data/lib/collapsium-config.rb
CHANGED
@@ -18,6 +18,13 @@ module Collapsium
|
|
18
18
|
# The default configuration file path
|
19
19
|
DEFAULT_CONFIG_PATH = 'config.yml'.freeze
|
20
20
|
|
21
|
+
# Default options for configuration loading
|
22
|
+
DEFAULT_CONFIG_OPTIONS = {
|
23
|
+
resolve_extensions: true,
|
24
|
+
nonexistent_base: :ignore,
|
25
|
+
data: nil,
|
26
|
+
}.freeze
|
27
|
+
|
21
28
|
##
|
22
29
|
# Modules can have class methods, too, but it's a little more verbose to
|
23
30
|
# provide them.
|
@@ -32,6 +39,16 @@ module Collapsium
|
|
32
39
|
return @config_file || DEFAULT_CONFIG_PATH
|
33
40
|
end
|
34
41
|
|
42
|
+
# Set configuration loading options
|
43
|
+
def config_options=(opts)
|
44
|
+
@config_options = opts
|
45
|
+
end
|
46
|
+
|
47
|
+
# @return [Hash] configuration loading options
|
48
|
+
def config_options
|
49
|
+
return @config_options || DEFAULT_CONFIG_OPTIONS
|
50
|
+
end
|
51
|
+
|
35
52
|
# @api private
|
36
53
|
attr_accessor :config
|
37
54
|
end # module ClassMethods
|
@@ -42,7 +59,8 @@ module Collapsium
|
|
42
59
|
def config
|
43
60
|
if Config.config.nil? or Config.config.empty?
|
44
61
|
begin
|
45
|
-
Config.config = Configuration.load_config(Config.config_file
|
62
|
+
Config.config = Configuration.load_config(Config.config_file,
|
63
|
+
Config.config_options)
|
46
64
|
rescue Errno::ENOENT
|
47
65
|
Config.config = {}
|
48
66
|
end
|
@@ -98,13 +98,31 @@ module Collapsium
|
|
98
98
|
# @param options [Hash] options hash with the following keys:
|
99
99
|
# - resolve_extensions [Boolean] flag whether to resolve configuration
|
100
100
|
# hash extensions. (see `#resolve_extensions`)
|
101
|
+
# - nonexistent_base [Symbol] either of :extend or :ignore; flag that
|
102
|
+
# determines how a nonexistent base should be treated:
|
103
|
+
# - :extend behaves as if it does exist, but refers to an empty Hash
|
104
|
+
# - :ignore does not modify the `.base` or `.extends` properties,
|
105
|
+
# and simply ignores the reference.
|
101
106
|
# - data [Hash] data Hash to pass on to the templating mechanism.
|
102
107
|
def load_config(path, options = {})
|
103
108
|
# Option defaults
|
109
|
+
options = options.dup
|
104
110
|
if options[:resolve_extensions].nil?
|
105
111
|
options[:resolve_extensions] = true
|
106
112
|
end
|
113
|
+
if not [true, false].include?(options[:resolve_extensions])
|
114
|
+
raise "The :resolve_extensions option must be a boolean value!"
|
115
|
+
end
|
116
|
+
if options[:nonexistent_base].nil?
|
117
|
+
options[:nonexistent_base] = :ignore
|
118
|
+
end
|
119
|
+
if not [:extend, :ignore].include?(options[:nonexistent_base])
|
120
|
+
raise "The :nonexistent_base option must be one of :ignore or :extend!"
|
121
|
+
end
|
107
122
|
options[:data] ||= {}
|
123
|
+
if not options[:data].is_a? Hash
|
124
|
+
raise "The :data option must be a Hash!"
|
125
|
+
end
|
108
126
|
|
109
127
|
# Load base and local configuration files
|
110
128
|
base, config = load_base_config(path, options[:data])
|
@@ -121,7 +139,7 @@ module Collapsium
|
|
121
139
|
|
122
140
|
# Now resolve config hashes that extend other hashes.
|
123
141
|
if options[:resolve_extensions]
|
124
|
-
cfg.resolve_extensions!
|
142
|
+
cfg.resolve_extensions!(options)
|
125
143
|
end
|
126
144
|
|
127
145
|
return cfg
|
@@ -251,35 +269,35 @@ module Collapsium
|
|
251
269
|
# Also note that all of this means that :extends and :base are reserved
|
252
270
|
# keywords that cannot be used in configuration files other than for this
|
253
271
|
# purpose!
|
254
|
-
def resolve_extensions!
|
272
|
+
def resolve_extensions!(options)
|
255
273
|
# The root object is always a Hash, so has keys, which can be processed
|
256
274
|
# recursively.
|
257
|
-
recursive_resolve(self)
|
275
|
+
recursive_resolve(self, "", options)
|
258
276
|
end
|
259
277
|
|
260
|
-
def recursive_resolve(root, prefix = "")
|
278
|
+
def recursive_resolve(root, prefix = "", options = {})
|
261
279
|
# The self object is a Hash or an Array. Let's iterate over its children
|
262
280
|
# one by one. Defaulting to a Hash here is just convenience, it could
|
263
281
|
# equally be an Array.
|
264
282
|
children = root.fetch(prefix, {})
|
265
283
|
|
266
|
-
merge_base(root, prefix, children)
|
284
|
+
merge_base(root, prefix, children, options)
|
267
285
|
|
268
286
|
if children.is_a? Hash
|
269
287
|
children.each do |key, _|
|
270
288
|
full_key = normalize_path("#{prefix}#{separator}#{key}")
|
271
|
-
recursive_resolve(root, full_key)
|
289
|
+
recursive_resolve(root, full_key, options)
|
272
290
|
end
|
273
291
|
elsif children.is_a? Array
|
274
292
|
children.each_with_index do |_, idx|
|
275
293
|
key = idx.to_s
|
276
294
|
full_key = normalize_path("#{prefix}#{separator}#{key}")
|
277
|
-
recursive_resolve(root, full_key)
|
295
|
+
recursive_resolve(root, full_key, options)
|
278
296
|
end
|
279
297
|
end
|
280
298
|
end
|
281
299
|
|
282
|
-
def merge_base(root, path, value)
|
300
|
+
def merge_base(root, path, value, options)
|
283
301
|
# If the value is not a Hash, we can't do anything here.
|
284
302
|
if not value.is_a? Hash
|
285
303
|
return
|
@@ -292,18 +310,19 @@ module Collapsium
|
|
292
310
|
end
|
293
311
|
|
294
312
|
# Now to resolve the path to the base and remove the "extends" keyword.
|
295
|
-
bases = fetch_base_values(root, parent_path(path), value)
|
313
|
+
bases = fetch_base_values(root, parent_path(path), value, options)
|
296
314
|
|
297
315
|
# Merge the bases
|
298
|
-
merge_base_values(root, value, bases)
|
316
|
+
merge_base_values(root, value, bases, options)
|
299
317
|
|
300
318
|
# And we're done, set the value to what was being merged.
|
301
319
|
root[path] = value
|
302
320
|
end
|
303
321
|
|
304
|
-
def fetch_base_values(root, parent, value)
|
322
|
+
def fetch_base_values(root, parent, value, options)
|
305
323
|
base_paths = array_value(value["extends"])
|
306
324
|
bases = []
|
325
|
+
base_count = 0
|
307
326
|
base_paths.each do |base_path|
|
308
327
|
if not base_path.start_with?(separator)
|
309
328
|
base_path = "#{parent}#{separator}#{base_path}"
|
@@ -315,30 +334,38 @@ module Collapsium
|
|
315
334
|
# We default to nil. Only Hash base values can be processed.
|
316
335
|
base_value = root.fetch(base_path, nil)
|
317
336
|
if not base_value.is_a? Hash
|
337
|
+
bases << [base_path, nil]
|
318
338
|
next
|
319
339
|
end
|
320
340
|
|
321
341
|
bases << [base_path, base_value]
|
342
|
+
base_count += 1
|
322
343
|
end
|
323
344
|
|
324
345
|
# Only delete the "extends" keyword if we found all base.
|
325
|
-
if
|
346
|
+
if options[:nonexistent_base] == :extend or \
|
347
|
+
base_count == base_paths.length
|
326
348
|
value.delete("extends")
|
327
349
|
end
|
328
350
|
|
329
351
|
return bases
|
330
352
|
end
|
331
353
|
|
332
|
-
def merge_base_values(root, value, bases)
|
354
|
+
def merge_base_values(root, value, bases, options)
|
333
355
|
# We need to recursively resolve the base values before merging them into
|
334
356
|
# value. To preserve the override order, we need to overwrite values when
|
335
357
|
# merging bases...
|
336
358
|
merged_base = Configuration.new
|
337
359
|
bases.each do |base_path, base_value|
|
338
|
-
base_value.
|
339
|
-
|
360
|
+
if not base_value.nil?
|
361
|
+
base_value.recursive_resolve(root, base_path)
|
362
|
+
merged_base.recursive_merge!(base_value, true)
|
363
|
+
end
|
340
364
|
|
341
365
|
# Modify bases for this path: we go depth first into the hierarchy
|
366
|
+
if options[:nonexistent_base] == :ignore and base_value.nil?
|
367
|
+
next
|
368
|
+
end
|
342
369
|
base_val = merged_base.fetch("base", []).dup
|
343
370
|
base_val << base_path
|
344
371
|
base_val.uniq!
|
data/spec/configuration_spec.rb
CHANGED
@@ -49,6 +49,25 @@ describe Collapsium::Config::Configuration do
|
|
49
49
|
cfg = Collapsium::Config::Configuration.load_config(config)
|
50
50
|
expect(cfg).to be_empty
|
51
51
|
end
|
52
|
+
|
53
|
+
it "validates options" do
|
54
|
+
config = File.join(@data_path, 'hash.yml')
|
55
|
+
|
56
|
+
# :resolve_extensions must be a boolean
|
57
|
+
opts = { resolve_extensions: 42 }
|
58
|
+
expect { Collapsium::Config::Configuration.load_config(config, opts) }.to \
|
59
|
+
raise_error RuntimeError
|
60
|
+
|
61
|
+
# :data must be a Hash
|
62
|
+
opts = { data: 42 }
|
63
|
+
expect { Collapsium::Config::Configuration.load_config(config, opts) }.to \
|
64
|
+
raise_error RuntimeError
|
65
|
+
|
66
|
+
# :nonexistent_base must be one of :ignore, :extend
|
67
|
+
opts = { nonexistent_base: :foo }
|
68
|
+
expect { Collapsium::Config::Configuration.load_config(config, opts) }.to \
|
69
|
+
raise_error RuntimeError
|
70
|
+
end
|
52
71
|
end
|
53
72
|
|
54
73
|
describe "merge behaviour" do
|
@@ -175,16 +194,34 @@ describe Collapsium::Config::Configuration do
|
|
175
194
|
.drivers.branch2)
|
176
195
|
end
|
177
196
|
|
178
|
-
|
179
|
-
|
180
|
-
|
197
|
+
context "Extension" do
|
198
|
+
it "ignores nonexistent bases by default" do
|
199
|
+
# Ensure the hash contains its own value
|
200
|
+
expect(@config["drivers.base_does_not_exist.some"]).to eql "value"
|
201
|
+
|
202
|
+
# Also ensure the "base" is _not_ set properly
|
203
|
+
expect(@config["drivers.base_does_not_exist.base"]).to be_nil
|
204
|
+
|
205
|
+
# On the other hand, "extends" should stay.
|
206
|
+
expect(@config["drivers.base_does_not_exist.extends"]).to eql \
|
207
|
+
"nonexistent_base"
|
208
|
+
end
|
209
|
+
|
210
|
+
it "can pretend nonexistent bases are empty" do
|
211
|
+
opts = { nonexistent_base: :extend }
|
212
|
+
config = Collapsium::Config::Configuration.load_config(@config_path,
|
213
|
+
opts)
|
214
|
+
|
215
|
+
# Ensure the hash contains its own value
|
216
|
+
expect(config["drivers.base_does_not_exist.some"]).to eql "value"
|
181
217
|
|
182
|
-
|
183
|
-
|
218
|
+
# Here, the base must be set!
|
219
|
+
expect(config["drivers.base_does_not_exist.base"]).to eql \
|
220
|
+
%w(.drivers.nonexistent_base)
|
184
221
|
|
185
|
-
|
186
|
-
|
187
|
-
|
222
|
+
# Then "extends" needs to vanish.
|
223
|
+
expect(config["drivers.base_does_not_exist.extends"]).to be_nil
|
224
|
+
end
|
188
225
|
end
|
189
226
|
end
|
190
227
|
|
data/spec/data/global.yml
CHANGED
data/spec/module_spec.rb
CHANGED
@@ -4,11 +4,12 @@ require_relative '../lib/collapsium-config'
|
|
4
4
|
include Collapsium::Config
|
5
5
|
|
6
6
|
describe Collapsium::Config do
|
7
|
-
before do
|
7
|
+
before :each do
|
8
8
|
@data_path = File.join(File.dirname(__FILE__), 'data')
|
9
9
|
ENV.delete("SOME_PATH")
|
10
10
|
ENV.delete("SOME")
|
11
11
|
ENV.delete("PATH")
|
12
|
+
Collapsium::Config.config = nil
|
12
13
|
end
|
13
14
|
|
14
15
|
it "fails to load configuration from the default path (it does not exist)" do
|
@@ -55,5 +56,12 @@ describe Collapsium::Config do
|
|
55
56
|
expect(config["some.path"]).to eql "override"
|
56
57
|
expect(config["some"]["path"]).to eql "override"
|
57
58
|
end
|
59
|
+
|
60
|
+
it "accepts non-default options" do
|
61
|
+
Collapsium::Config.config_file = File.join(@data_path, 'global.yml')
|
62
|
+
Collapsium::Config.config_options = { resolve_extensions: false }
|
63
|
+
|
64
|
+
expect(config["foo.base"]).to be_nil
|
65
|
+
end
|
58
66
|
end
|
59
67
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: collapsium-config
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jens Finkhaeuser
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-01-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '0.
|
33
|
+
version: '0.46'
|
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
|
-
version: '0.
|
40
|
+
version: '0.46'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -100,14 +100,14 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '0.
|
103
|
+
version: '0.8'
|
104
104
|
type: :runtime
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '0.
|
110
|
+
version: '0.8'
|
111
111
|
description: "\n Using collapsium's UberHash class for easy access to configuration
|
112
112
|
values,\n this gem reads and merges various configuration sources into one\n
|
113
113
|
\ configuration object.\n "
|