jac 0.0.3 → 0.0.4
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 +5 -5
- data/lib/jac/configuration.rb +97 -41
- data/lib/jac/version.rb +3 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8aaaff9c5e46908f214469f894732bdbd178bdc92e91549180d7f3a45157e2e2
|
4
|
+
data.tar.gz: d6c97e79b6a72e363777af65b5d9e18fb7a2545dd56b3a523ed25d9c1cf33482
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b2244d961c0c82fb75ae3dffc5ce7f42763533f0bc2794062ab2a0766ade890eca579aa7dbf49f28bb2759014b3daaf2f4fa077a5a1d1dde730b8e73226ae635
|
7
|
+
data.tar.gz: 6118f96a703d7a4049b404f6635bf78c878665a2f292cc7c5fc3b6812aa14ec9f2ba62c14118b6cf2f183c31466ea2a6510fda92efdae529586aff56e3c25f30
|
data/lib/jac/configuration.rb
CHANGED
@@ -177,14 +177,28 @@ module Jac
|
|
177
177
|
# If profile name matches multiple generic profiles it not defined
|
178
178
|
# which profile will be used.
|
179
179
|
module Configuration
|
180
|
+
# Name of top level profile. ^top profile is implicit
|
181
|
+
# it automaticly merged on top of resulting configuration
|
182
|
+
TOP_PROFILE_NAME = '^top'.freeze
|
183
|
+
# Name of base level profile. ^base profile is implicit
|
184
|
+
# resulting configuration automaticly merged on top of it.
|
185
|
+
BASE_PROFILE_NAME = '^base'.freeze
|
186
|
+
# Any configuration set always contains `default` profile
|
187
|
+
# which is loaded when no profile requested.
|
188
|
+
DEFAULT_PROFILE_NAME = 'default'.freeze
|
189
|
+
# List of default profiles. Having this list we can easily create default
|
190
|
+
# configuration.
|
191
|
+
BASIC_PROFILES = [
|
192
|
+
TOP_PROFILE_NAME,
|
193
|
+
BASE_PROFILE_NAME,
|
194
|
+
DEFAULT_PROFILE_NAME
|
195
|
+
].freeze
|
196
|
+
# Key where all inherited profiles listed
|
197
|
+
EXTENDS_KEY = 'extends'.freeze
|
198
|
+
|
180
199
|
# Reads and evaluates configuration for given set of streams
|
181
200
|
# and profile
|
182
201
|
class ConfigurationReader
|
183
|
-
# Any configuration set always contains `default` profile
|
184
|
-
# which is loaded when no profile requested.
|
185
|
-
DEFAULT_PROFILE_NAME = 'default'.freeze
|
186
|
-
# Creates "empty" config
|
187
|
-
DEFAULT_CONFIGURATION = -> () { { DEFAULT_PROFILE_NAME => {} } }
|
188
202
|
attr_reader :merger
|
189
203
|
# Creates configuration reader
|
190
204
|
# @param [Array] streams of pairs containing YAML document and provided
|
@@ -200,12 +214,22 @@ module Jac
|
|
200
214
|
def read(*profile)
|
201
215
|
result = @streams
|
202
216
|
.flat_map { |stream, _name| read_stream(stream) }
|
203
|
-
.inject(
|
204
|
-
|
217
|
+
.inject(default_configuration) { |acc, elem| update(acc, elem) }
|
218
|
+
# Keep original profile name
|
219
|
+
original_profile = profile
|
220
|
+
# Add implicit profiles
|
221
|
+
profile =
|
222
|
+
[Configuration::BASE_PROFILE_NAME, profile, Configuration::TOP_PROFILE_NAME].flatten
|
223
|
+
OpenStruct.new(evaluate(resolve(profile, result).merge('profile' => original_profile)))
|
205
224
|
end
|
206
225
|
|
207
226
|
private
|
208
227
|
|
228
|
+
# Creates empty configuration object.
|
229
|
+
def default_configuration
|
230
|
+
Configuration::BASIC_PROFILES.inject({}) { |acc, elem| acc.update(elem => {}) }
|
231
|
+
end
|
232
|
+
|
209
233
|
def read_stream(stream)
|
210
234
|
# Each stream consists of one or more documents
|
211
235
|
YAML.parse_stream(stream).children.flat_map do |document|
|
@@ -256,9 +280,6 @@ module Jac
|
|
256
280
|
|
257
281
|
# Describes profile resolving strategy
|
258
282
|
class ProfileResolver
|
259
|
-
# Key where all inherited profiles listed
|
260
|
-
EXTENDS_KEY = 'extends'.freeze
|
261
|
-
|
262
283
|
attr_reader :config, :merger
|
263
284
|
|
264
285
|
def initialize(config)
|
@@ -273,8 +294,8 @@ module Jac
|
|
273
294
|
raise(ArgumentError, msg)
|
274
295
|
end
|
275
296
|
profile_values = find_profile(elem)
|
276
|
-
# Find all
|
277
|
-
extends =
|
297
|
+
# Find all parent_profiles
|
298
|
+
extends = parent_profiles(profile_values)
|
278
299
|
# We can do not check extends. Empty profile returns {}
|
279
300
|
# Inherited values goes first
|
280
301
|
inherited = merger.merge(acc, resolve(extends, resolved + [elem]))
|
@@ -282,6 +303,17 @@ module Jac
|
|
282
303
|
end
|
283
304
|
end
|
284
305
|
|
306
|
+
# Fetches list of parent profile
|
307
|
+
# @param [Hash] values current profile values
|
308
|
+
# @return [Array] of profile names
|
309
|
+
def parent_profiles(values)
|
310
|
+
extends = *values[Configuration::EXTENDS_KEY] || []
|
311
|
+
[Configuration::TOP_PROFILE_NAME, Configuration::BASE_PROFILE_NAME].each do |implicit|
|
312
|
+
raise(ArgumentError, "`#{implicit}` is not allowed here") if extends.include?(implicit)
|
313
|
+
end
|
314
|
+
extends
|
315
|
+
end
|
316
|
+
|
285
317
|
def find_profile(profile_name)
|
286
318
|
return config[profile_name] if config.key?(profile_name)
|
287
319
|
# First and last chars are '/'
|
@@ -317,8 +349,6 @@ module Jac
|
|
317
349
|
.keys
|
318
350
|
.select { |k| k[0] == '/' && k[-1] == '/' }
|
319
351
|
.map { |k| [k, Regexp.new(k[1..-2])] }
|
320
|
-
|
321
|
-
@generic_profiles
|
322
352
|
end
|
323
353
|
end
|
324
354
|
|
@@ -326,29 +356,27 @@ module Jac
|
|
326
356
|
# when referencing profile inside evaluated
|
327
357
|
# expressions
|
328
358
|
class EvaluationContext
|
329
|
-
def initialize(evaluator)
|
359
|
+
def initialize(hash, evaluator)
|
330
360
|
@evaluator = evaluator
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
return super unless respond_to_missing?(meth, args, &block)
|
340
|
-
@evaluator.evaluate(meth.to_s)
|
361
|
+
hash.each_key do |key|
|
362
|
+
exp = <<-EVAL.strip_indent
|
363
|
+
def #{key}
|
364
|
+
@evaluator.evaluate("#{key}")
|
365
|
+
end
|
366
|
+
EVAL
|
367
|
+
eval(exp, binding)
|
368
|
+
end
|
341
369
|
end
|
342
370
|
end
|
343
371
|
|
344
372
|
# Evaluates all strings inside resolved profile
|
345
373
|
# object
|
346
374
|
class ConfigurationEvaluator
|
347
|
-
def initialize(src_object
|
375
|
+
def initialize(src_object)
|
348
376
|
@object = src_object
|
349
|
-
@evaluated =
|
350
|
-
|
351
|
-
|
377
|
+
@evaluated = {}
|
378
|
+
# Initialize context object with root
|
379
|
+
@context = EvaluationContext.new(@object, self)
|
352
380
|
end
|
353
381
|
|
354
382
|
def evaluate(key)
|
@@ -364,27 +392,32 @@ module Jac
|
|
364
392
|
alias conf c
|
365
393
|
alias cfg c
|
366
394
|
|
367
|
-
|
368
|
-
|
369
|
-
def resolve_object
|
395
|
+
def evaluate_values
|
396
|
+
@ctx_object = @context
|
370
397
|
@object.each_key { |k| evaluate(k) }
|
371
398
|
# Cleanup accidentally created values (when referencing missing values)
|
372
399
|
@evaluated.delete_if { |k, _v| !@object.key?(k) }
|
373
400
|
end
|
374
401
|
|
375
|
-
|
402
|
+
private
|
403
|
+
|
404
|
+
def get_binding(object)
|
376
405
|
binding
|
377
406
|
end
|
378
407
|
|
379
|
-
def evaluate_deep(object)
|
408
|
+
def evaluate_deep(object) # rubocop:disable Metrics/MethodLength
|
380
409
|
case object
|
381
410
|
when String
|
382
411
|
eval_string(object)
|
383
412
|
when Array
|
384
|
-
object
|
413
|
+
contextual(object) do
|
414
|
+
object.map { |e| evaluate_deep(e) }
|
415
|
+
end
|
385
416
|
when Hash
|
386
417
|
# Evaluating values only by convention
|
387
|
-
object
|
418
|
+
contextual(object) do
|
419
|
+
object.inject({}) { |acc, elem| acc.update(elem.first => evaluate_deep(elem.last)) }
|
420
|
+
end
|
388
421
|
else
|
389
422
|
object
|
390
423
|
end
|
@@ -392,17 +425,40 @@ module Jac
|
|
392
425
|
|
393
426
|
def eval_string(o)
|
394
427
|
evaluated = /#\{.+?\}/.match(o) do
|
395
|
-
eval('"' + o + '"', get_binding(
|
428
|
+
eval('"' + o + '"', get_binding(@ctx_object))
|
396
429
|
end
|
397
430
|
|
398
431
|
evaluated || o
|
399
432
|
end
|
400
433
|
|
434
|
+
def respond_to_missing?(meth, args, &block)
|
435
|
+
@ctx_object && @ctx_object.respond_to?(meth, args, &block)
|
436
|
+
end
|
437
|
+
|
438
|
+
def method_missing(meth, *args, &block)
|
439
|
+
# rubocop inspection hack
|
440
|
+
return super unless respond_to_missing?(meth, args, &block)
|
441
|
+
@ctx_object.send(meth, *args, &block)
|
442
|
+
end
|
443
|
+
|
444
|
+
# Keeps track of current context objects
|
445
|
+
# This trick allows us to reference local variables
|
446
|
+
# using `self` calls.
|
447
|
+
# @param ctx [Object] object to use in current evaluation
|
448
|
+
# @param &block [Proc] evaluation logic
|
449
|
+
# @return [Object] result of evaluation
|
450
|
+
def contextual(ctx)
|
451
|
+
memo = @ctx_object
|
452
|
+
@ctx_object = ctx
|
453
|
+
result = yield
|
454
|
+
@ctx_object = memo
|
455
|
+
|
456
|
+
result
|
457
|
+
end
|
458
|
+
|
401
459
|
class << self
|
402
460
|
def evaluate(o)
|
403
|
-
|
404
|
-
ConfigurationEvaluator.new(o, dst)
|
405
|
-
dst
|
461
|
+
ConfigurationEvaluator.new(o).evaluate_values
|
406
462
|
end
|
407
463
|
end
|
408
464
|
end
|
@@ -424,7 +480,7 @@ module Jac
|
|
424
480
|
# names to read
|
425
481
|
# @return [OpenStruct] instance which contains all resolved profile fields
|
426
482
|
def read(profile, *streams)
|
427
|
-
profile = [
|
483
|
+
profile = [Configuration::DEFAULT_PROFILE_NAME] if profile.empty?
|
428
484
|
ConfigurationReader.new(streams).read(*profile)
|
429
485
|
end
|
430
486
|
|
data/lib/jac/version.rb
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jac
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ilya.arkhanhelsky
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-08-06 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Profile based configuration lib
|
14
14
|
email: ilya.arkhanhelsky@vizor-games.com
|
@@ -20,6 +20,7 @@ files:
|
|
20
20
|
- lib/jac/configuration.rb
|
21
21
|
- lib/jac/merger.rb
|
22
22
|
- lib/jac/parser.rb
|
23
|
+
- lib/jac/version.rb
|
23
24
|
homepage: https://github.com/vizor-games/jac
|
24
25
|
licenses:
|
25
26
|
- MIT
|
@@ -40,7 +41,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
40
41
|
version: '0'
|
41
42
|
requirements: []
|
42
43
|
rubyforge_project:
|
43
|
-
rubygems_version: 2.6
|
44
|
+
rubygems_version: 2.7.6
|
44
45
|
signing_key:
|
45
46
|
specification_version: 4
|
46
47
|
summary: Just Another Configuration Lib
|