-
Notifications
You must be signed in to change notification settings - Fork 0
/
defaults_loader.rb
96 lines (78 loc) · 3.04 KB
/
defaults_loader.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# frozen_string_literal: true
require 'frise/parser'
module Frise
# Provides the logic for merging config defaults into pre-loaded configuration objects.
#
# The merge_defaults and merge_defaults_at entrypoint methods provide ways to read files with
# defaults and apply them to configuration objects.
class DefaultsLoader
SYMBOLS = %w[$all $optional].freeze
def initialize(
include_sym: '$include',
content_include_sym: '$content_include',
schema_sym: '$schema',
delete_sym: '$delete'
)
@include_sym = include_sym
@content_include_sym = content_include_sym
@schema_sym = schema_sym
@delete_sym = delete_sym
end
# rubocop:disable Lint/DuplicateBranch
def merge_defaults_obj(config, defaults)
config_class = widened_class(config)
defaults_class = widened_class(defaults)
if defaults.nil?
config
elsif config.nil?
if defaults_class != 'Hash' then defaults
elsif defaults['$optional'] then nil
else
merge_defaults_obj({}, defaults)
end
elsif config == @delete_sym
config
elsif defaults_class == 'Array' && config_class == 'Array'
defaults + config
elsif defaults_class == 'Hash' && defaults['$all'] && config_class == 'Array'
config.map { |elem| merge_defaults_obj(elem, defaults['$all']) }
elsif defaults_class == 'Hash' && config_class == 'Hash'
new_config = {}
(config.keys + defaults.keys).uniq.each do |key|
next if SYMBOLS.include?(key)
new_config[key] = config[key]
new_config[key] = merge_defaults_obj(new_config[key], defaults[key]) if defaults.key?(key)
new_config[key] = merge_defaults_obj(new_config[key], defaults['$all']) unless new_config[key].nil?
new_config.delete(key) if new_config[key].nil?
end
new_config
elsif defaults_class != config_class
raise "Cannot merge config #{config.inspect} (#{widened_class(config)}) " \
"with default #{defaults.inspect} (#{widened_class(defaults)})"
else
config
end
end
# rubocop:enable Lint/DuplicateBranch
def merge_defaults_obj_at(config, at_path, defaults)
at_path.reverse.each { |key| defaults = { key => defaults } }
merge_defaults_obj(config, defaults)
end
def merge_defaults(config, defaults_file, symbol_table = config)
defaults = Parser.parse(defaults_file, symbol_table) || {}
merge_defaults_obj(config, defaults)
end
def merge_defaults_at(config, at_path, defaults_file, symbol_table = config)
defaults = Parser.parse(defaults_file, symbol_table) || {}
merge_defaults_obj_at(config, at_path, defaults)
end
private
def widened_class(obj)
class_name = obj.class.to_s
return 'String' if class_name == 'Hash' && !obj[@content_include_sym].nil?
return 'Boolean' if %w[TrueClass FalseClass].include? class_name
return 'Integer' if %w[Fixnum Bignum].include? class_name
class_name
end
end
end