hocon 0.0.7 → 0.1.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 +7 -0
- data/README.md +4 -2
- data/lib/hocon.rb +2 -0
- data/lib/hocon/config.rb +1010 -0
- data/lib/hocon/config_error.rb +32 -2
- data/lib/hocon/config_factory.rb +46 -0
- data/lib/hocon/config_include_context.rb +49 -0
- data/lib/hocon/config_includer_file.rb +27 -0
- data/lib/hocon/config_list.rb +49 -0
- data/lib/hocon/config_mergeable.rb +74 -0
- data/lib/hocon/config_object.rb +144 -1
- data/lib/hocon/config_parse_options.rb +33 -9
- data/lib/hocon/config_parseable.rb +51 -0
- data/lib/hocon/config_render_options.rb +4 -2
- data/lib/hocon/config_resolve_options.rb +31 -0
- data/lib/hocon/config_syntax.rb +5 -2
- data/lib/hocon/config_util.rb +73 -0
- data/lib/hocon/config_value.rb +122 -0
- data/lib/hocon/config_value_factory.rb +66 -2
- data/lib/hocon/config_value_type.rb +5 -2
- data/lib/hocon/impl.rb +2 -0
- data/lib/hocon/impl/abstract_config_node.rb +29 -0
- data/lib/hocon/impl/abstract_config_node_value.rb +11 -0
- data/lib/hocon/impl/abstract_config_object.rb +148 -42
- data/lib/hocon/impl/abstract_config_value.rb +251 -11
- data/lib/hocon/impl/array_iterator.rb +19 -0
- data/lib/hocon/impl/config_boolean.rb +7 -1
- data/lib/hocon/impl/config_concatenation.rb +177 -28
- data/lib/hocon/impl/config_delayed_merge.rb +329 -0
- data/lib/hocon/impl/config_delayed_merge_object.rb +274 -0
- data/lib/hocon/impl/config_document_parser.rb +647 -0
- data/lib/hocon/impl/config_double.rb +44 -0
- data/lib/hocon/impl/config_impl.rb +143 -19
- data/lib/hocon/impl/config_impl_util.rb +18 -0
- data/lib/hocon/impl/config_include_kind.rb +10 -0
- data/lib/hocon/impl/config_int.rb +13 -1
- data/lib/hocon/impl/config_node_array.rb +11 -0
- data/lib/hocon/impl/config_node_comment.rb +19 -0
- data/lib/hocon/impl/config_node_complex_value.rb +54 -0
- data/lib/hocon/impl/config_node_concatenation.rb +11 -0
- data/lib/hocon/impl/config_node_field.rb +81 -0
- data/lib/hocon/impl/config_node_include.rb +33 -0
- data/lib/hocon/impl/config_node_object.rb +276 -0
- data/lib/hocon/impl/config_node_path.rb +48 -0
- data/lib/hocon/impl/config_node_root.rb +60 -0
- data/lib/hocon/impl/config_node_simple_value.rb +42 -0
- data/lib/hocon/impl/config_node_single_token.rb +17 -0
- data/lib/hocon/impl/config_null.rb +15 -7
- data/lib/hocon/impl/config_number.rb +43 -4
- data/lib/hocon/impl/config_parser.rb +403 -0
- data/lib/hocon/impl/config_reference.rb +142 -0
- data/lib/hocon/impl/config_string.rb +55 -7
- data/lib/hocon/impl/container.rb +29 -0
- data/lib/hocon/impl/default_transformer.rb +24 -15
- data/lib/hocon/impl/from_map_mode.rb +3 -1
- data/lib/hocon/impl/full_includer.rb +2 -0
- data/lib/hocon/impl/memo_key.rb +42 -0
- data/lib/hocon/impl/mergeable_value.rb +8 -0
- data/lib/hocon/impl/origin_type.rb +8 -2
- data/lib/hocon/impl/parseable.rb +455 -91
- data/lib/hocon/impl/path.rb +181 -59
- data/lib/hocon/impl/path_builder.rb +24 -3
- data/lib/hocon/impl/path_parser.rb +280 -0
- data/lib/hocon/impl/replaceable_merge_stack.rb +22 -0
- data/lib/hocon/impl/resolve_context.rb +254 -0
- data/lib/hocon/impl/resolve_memos.rb +21 -0
- data/lib/hocon/impl/resolve_result.rb +39 -0
- data/lib/hocon/impl/resolve_source.rb +354 -0
- data/lib/hocon/impl/resolve_status.rb +3 -1
- data/lib/hocon/impl/simple_config.rb +264 -10
- data/lib/hocon/impl/simple_config_document.rb +48 -0
- data/lib/hocon/impl/simple_config_list.rb +282 -8
- data/lib/hocon/impl/simple_config_object.rb +424 -88
- data/lib/hocon/impl/simple_config_origin.rb +263 -71
- data/lib/hocon/impl/simple_include_context.rb +31 -1
- data/lib/hocon/impl/simple_includer.rb +196 -1
- data/lib/hocon/impl/substitution_expression.rb +38 -0
- data/lib/hocon/impl/token.rb +17 -4
- data/lib/hocon/impl/token_type.rb +6 -2
- data/lib/hocon/impl/tokenizer.rb +339 -109
- data/lib/hocon/impl/tokens.rb +330 -79
- data/lib/hocon/impl/unmergeable.rb +14 -1
- data/lib/hocon/impl/unsupported_operation_error.rb +6 -0
- data/lib/hocon/impl/url.rb +37 -0
- data/lib/hocon/parser.rb +7 -0
- data/lib/hocon/parser/config_document.rb +92 -0
- data/lib/hocon/parser/config_document_factory.rb +36 -0
- data/lib/hocon/parser/config_node.rb +30 -0
- metadata +67 -43
- data/lib/hocon/impl/config_float.rb +0 -13
- data/lib/hocon/impl/parser.rb +0 -977
- data/lib/hocon/impl/properties_parser.rb +0 -83
@@ -1,12 +1,18 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require 'hocon/impl'
|
2
4
|
require 'hocon/impl/abstract_config_value'
|
3
5
|
|
4
|
-
class Hocon::Impl::ConfigBoolean
|
6
|
+
class Hocon::Impl::ConfigBoolean
|
7
|
+
include Hocon::Impl::AbstractConfigValue
|
8
|
+
|
5
9
|
def initialize(origin, value)
|
6
10
|
super(origin)
|
7
11
|
@value = value
|
8
12
|
end
|
9
13
|
|
14
|
+
attr_reader :value
|
15
|
+
|
10
16
|
def value_type
|
11
17
|
Hocon::ConfigValueType::BOOLEAN
|
12
18
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require 'hocon/impl'
|
2
4
|
require 'hocon/impl/abstract_config_value'
|
3
5
|
require 'hocon/impl/abstract_config_object'
|
@@ -6,14 +8,70 @@ require 'hocon/config_object'
|
|
6
8
|
require 'hocon/impl/unmergeable'
|
7
9
|
require 'hocon/impl/simple_config_origin'
|
8
10
|
require 'hocon/impl/config_string'
|
11
|
+
require 'hocon/impl/container'
|
9
12
|
|
10
|
-
class Hocon::Impl::ConfigConcatenation
|
13
|
+
class Hocon::Impl::ConfigConcatenation
|
11
14
|
include Hocon::Impl::Unmergeable
|
15
|
+
include Hocon::Impl::Container
|
16
|
+
include Hocon::Impl::AbstractConfigValue
|
12
17
|
|
13
18
|
SimpleConfigList = Hocon::Impl::SimpleConfigList
|
14
19
|
ConfigObject = Hocon::ConfigObject
|
20
|
+
ConfigString = Hocon::Impl::ConfigString
|
21
|
+
ResolveStatus = Hocon::Impl::ResolveStatus
|
15
22
|
Unmergeable = Hocon::Impl::Unmergeable
|
16
23
|
SimpleConfigOrigin = Hocon::Impl::SimpleConfigOrigin
|
24
|
+
ConfigBugOrBrokenError = Hocon::ConfigError::ConfigBugOrBrokenError
|
25
|
+
ConfigNotResolvedError = Hocon::ConfigError::ConfigNotResolvedError
|
26
|
+
ConfigWrongTypeError = Hocon::ConfigError::ConfigWrongTypeError
|
27
|
+
|
28
|
+
attr_reader :pieces
|
29
|
+
|
30
|
+
def initialize(origin, pieces)
|
31
|
+
super(origin)
|
32
|
+
@pieces = pieces
|
33
|
+
|
34
|
+
if pieces.size < 2
|
35
|
+
raise ConfigBugOrBrokenError, "Created concatenation with less than 2 items: #{self}"
|
36
|
+
end
|
37
|
+
|
38
|
+
had_unmergeable = false
|
39
|
+
pieces.each do |p|
|
40
|
+
if p.is_a?(Hocon::Impl::ConfigConcatenation)
|
41
|
+
raise ConfigBugOrBrokenError, "ConfigConcatenation should never be nested: #{self}"
|
42
|
+
end
|
43
|
+
if p.is_a?(Unmergeable)
|
44
|
+
had_unmergeable = true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
unless had_unmergeable
|
49
|
+
raise ConfigBugOrBrokenError, "Created concatenation without an unmergeable in it: #{self}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def value_type
|
54
|
+
raise not_resolved
|
55
|
+
end
|
56
|
+
|
57
|
+
def unwrapped
|
58
|
+
raise not_resolved
|
59
|
+
end
|
60
|
+
|
61
|
+
def new_copy(new_origin)
|
62
|
+
self.class.new(new_origin, @pieces)
|
63
|
+
end
|
64
|
+
|
65
|
+
def ignores_fallbacks?
|
66
|
+
# we can never ignore fallbacks because if a child ConfigReference
|
67
|
+
# is self-referential we have to look lower in the merge stack
|
68
|
+
# for its value.
|
69
|
+
false
|
70
|
+
end
|
71
|
+
|
72
|
+
def unmerged_values
|
73
|
+
[self]
|
74
|
+
end
|
17
75
|
|
18
76
|
#
|
19
77
|
# Add left and right, or their merger, to builder
|
@@ -25,9 +83,9 @@ class Hocon::Impl::ConfigConcatenation < Hocon::Impl::AbstractConfigValue
|
|
25
83
|
# check for an object which can be converted to a list
|
26
84
|
# (this will be an object with numeric keys, like foo.0, foo.1)
|
27
85
|
if (left.is_a?(ConfigObject)) && (right.is_a?(SimpleConfigList))
|
28
|
-
left = DefaultTransformer.transform(left, ConfigValueType::LIST)
|
86
|
+
left = Hocon::Impl::DefaultTransformer.transform(left, Hocon::ConfigValueType::LIST)
|
29
87
|
elsif (left.is_a?(SimpleConfigList)) && (right.is_a?(ConfigObject))
|
30
|
-
right = DefaultTransformer.transform(right, ConfigValueType::LIST)
|
88
|
+
right = Hocon::Impl::DefaultTransformer.transform(right, Hocon::ConfigValueType::LIST)
|
31
89
|
end
|
32
90
|
|
33
91
|
# Since this depends on the type of two instances, I couldn't think
|
@@ -38,9 +96,13 @@ class Hocon::Impl::ConfigConcatenation < Hocon::Impl::AbstractConfigValue
|
|
38
96
|
joined = right.with_fallback(left)
|
39
97
|
elsif (left.is_a?(SimpleConfigList)) && (right.is_a?(SimpleConfigList))
|
40
98
|
joined = left.concatenate(right)
|
99
|
+
elsif (left.is_a?(SimpleConfigList) || left.is_a?(ConfigObject)) &&
|
100
|
+
is_ignored_whitespace(right)
|
101
|
+
joined = left
|
102
|
+
# it should be impossible that left is whitespace and right is a list or object
|
41
103
|
elsif (left.is_a?(Hocon::Impl::ConfigConcatenation)) ||
|
42
104
|
(right.is_a?(Hocon::Impl::ConfigConcatenation))
|
43
|
-
raise
|
105
|
+
raise ConfigBugOrBrokenError, "unflattened ConfigConcatenation"
|
44
106
|
elsif (left.is_a?(Unmergeable)) || (right.is_a?(Unmergeable))
|
45
107
|
# leave joined=null, cannot join
|
46
108
|
else
|
@@ -50,10 +112,10 @@ class Hocon::Impl::ConfigConcatenation < Hocon::Impl::AbstractConfigValue
|
|
50
112
|
if s1.nil? || s2.nil?
|
51
113
|
raise ConfigWrongTypeError.new(left.origin,
|
52
114
|
"Cannot concatenate object or list with a non-object-or-list, #{left} " +
|
53
|
-
"and #{right} are not compatible")
|
115
|
+
"and #{right} are not compatible", nil)
|
54
116
|
else
|
55
117
|
joined_origin = SimpleConfigOrigin.merge_origins([left.origin, right.origin])
|
56
|
-
joined = Hocon::Impl::ConfigString.new(joined_origin, s1 + s2)
|
118
|
+
joined = Hocon::Impl::ConfigString::Quoted.new(joined_origin, s1 + s2)
|
57
119
|
end
|
58
120
|
end
|
59
121
|
|
@@ -98,39 +160,126 @@ class Hocon::Impl::ConfigConcatenation < Hocon::Impl::AbstractConfigValue
|
|
98
160
|
elsif consolidated.length == 1
|
99
161
|
consolidated[0]
|
100
162
|
else
|
101
|
-
merged_origin = SimpleConfigOrigin.
|
163
|
+
merged_origin = SimpleConfigOrigin.merge_value_origins(consolidated)
|
102
164
|
Hocon::Impl::ConfigConcatenation.new(merged_origin, consolidated)
|
103
165
|
end
|
104
166
|
end
|
105
167
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
168
|
+
def resolve_substitutions(context, source)
|
169
|
+
if Hocon::Impl::ConfigImpl.trace_substitution_enabled
|
170
|
+
indent = context.depth + 2
|
171
|
+
Hocon::Impl::ConfigImpl.trace("concatenation has #{@pieces.size} pieces",
|
172
|
+
indent - 1)
|
173
|
+
count = 0
|
174
|
+
@pieces.each { |v|
|
175
|
+
Hocon::Impl::ConfigImpl.trace("#{count}: #{v}", count)
|
176
|
+
count += 1
|
177
|
+
}
|
113
178
|
end
|
114
179
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
180
|
+
# Right now there's no reason to pushParent here because the
|
181
|
+
# content of ConfigConcatenation should not need to replaceChild,
|
182
|
+
# but if it did we'd have to do this.
|
183
|
+
source_with_parent = source
|
184
|
+
new_context = context
|
185
|
+
|
186
|
+
resolved = []
|
187
|
+
@pieces.each { |p|
|
188
|
+
# to concat into a string we have to do a full resolve,
|
189
|
+
# so unrestrict the context, then put restriction back afterward
|
190
|
+
restriction = new_context.restrict_to_child
|
191
|
+
result = new_context.unrestricted
|
192
|
+
.resolve(p, source_with_parent)
|
193
|
+
r = result.value
|
194
|
+
new_context = result.context.restrict(restriction)
|
195
|
+
if Hocon::Impl::ConfigImpl.trace_substitution_enabled
|
196
|
+
Hocon::Impl::ConfigImpl.trace("resolved concat piece to #{r}",
|
197
|
+
context.depth)
|
119
198
|
end
|
120
|
-
|
121
|
-
|
199
|
+
|
200
|
+
if r
|
201
|
+
resolved << r
|
122
202
|
end
|
203
|
+
# otherwise, it was optional ... omit
|
204
|
+
}
|
205
|
+
|
206
|
+
# now need to concat everything
|
207
|
+
joined = self.class.consolidate(resolved)
|
208
|
+
# if unresolved is allowed we can just become another
|
209
|
+
# ConfigConcatenation
|
210
|
+
if joined.size > 1 and context.options.allow_unresolved
|
211
|
+
Hocon::Impl::ResolveResult.make(new_context, Hocon::Impl::ConfigConcatenation.new(origin, joined))
|
212
|
+
elsif joined.empty?
|
213
|
+
# we had just a list of optional references using ${?}
|
214
|
+
Hocon::Impl::ResolveResult.make(new_context, nil)
|
215
|
+
elsif joined.size == 1
|
216
|
+
Hocon::Impl::ResolveResult.make(new_context, joined[0])
|
217
|
+
else
|
218
|
+
raise ConfigBugOrBrokenError.new(
|
219
|
+
"Bug in the library; resolved list was joined to too many values: #{joined}")
|
123
220
|
end
|
221
|
+
end
|
124
222
|
|
125
|
-
|
126
|
-
|
223
|
+
def resolve_status
|
224
|
+
ResolveStatus::UNRESOLVED
|
225
|
+
end
|
226
|
+
|
227
|
+
def replace_child(child, replacement)
|
228
|
+
new_pieces = replace_child_in_list(@pieces, child, replacement)
|
229
|
+
if new_pieces == nil
|
230
|
+
nil
|
231
|
+
else
|
232
|
+
self.class.new(origin, new_pieces)
|
127
233
|
end
|
128
234
|
end
|
129
235
|
|
130
|
-
def
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
236
|
+
def has_descendant?(descendant)
|
237
|
+
has_descendant_in_list?(@pieces, descendant)
|
238
|
+
end
|
239
|
+
|
240
|
+
# when you graft a substitution into another object,
|
241
|
+
# you have to prefix it with the location in that object
|
242
|
+
# where you grafted it; but save prefixLength so
|
243
|
+
# system property and env variable lookups don 't get
|
244
|
+
# broken.
|
245
|
+
def relativized(prefix)
|
246
|
+
new_pieces = []
|
247
|
+
@pieces.each { |p|
|
248
|
+
new_pieces << p.relativized(prefix)
|
249
|
+
}
|
250
|
+
self.class.new(origin, new_pieces)
|
251
|
+
end
|
252
|
+
|
253
|
+
def can_equal(other)
|
254
|
+
other.is_a? Hocon::Impl::ConfigConcatenation
|
255
|
+
end
|
256
|
+
|
257
|
+
def ==(other)
|
258
|
+
if other.is_a? Hocon::Impl::ConfigConcatenation
|
259
|
+
can_equal(other) && @pieces == other.pieces
|
260
|
+
else
|
261
|
+
false
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
def hash
|
266
|
+
# note that "origin" is deliberately NOT part of equality
|
267
|
+
@pieces.hash
|
268
|
+
end
|
269
|
+
|
270
|
+
def render_value_to_sb(sb, indent, at_root, options)
|
271
|
+
@pieces.each do |piece|
|
272
|
+
piece.render_value_to_sb(sb, indent, at_root, options)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
private
|
277
|
+
|
278
|
+
def not_resolved
|
279
|
+
ConfigNotResolvedError.new("need to Config#resolve(), see the API docs for Config#resolve(); substitution not resolved: #{self}")
|
280
|
+
end
|
281
|
+
|
282
|
+
def self.is_ignored_whitespace(value)
|
283
|
+
return value.is_a?(ConfigString) && !value.was_quoted?
|
135
284
|
end
|
136
|
-
end
|
285
|
+
end
|
@@ -0,0 +1,329 @@
|
|
1
|
+
require 'hocon/impl'
|
2
|
+
require 'hocon/impl/replaceable_merge_stack'
|
3
|
+
require 'hocon/impl/config_delayed_merge_object'
|
4
|
+
require 'hocon/impl/config_impl'
|
5
|
+
require 'hocon/impl/resolve_result'
|
6
|
+
require 'hocon/impl/abstract_config_value'
|
7
|
+
|
8
|
+
#
|
9
|
+
# The issue here is that we want to first merge our stack of config files, and
|
10
|
+
# then we want to evaluate substitutions. But if two substitutions both expand
|
11
|
+
# to an object, we might need to merge those two objects. Thus, we can't ever
|
12
|
+
# "override" a substitution when we do a merge; instead we have to save the
|
13
|
+
# stack of values that should be merged, and resolve the merge when we evaluate
|
14
|
+
# substitutions.
|
15
|
+
#
|
16
|
+
class Hocon::Impl::ConfigDelayedMerge
|
17
|
+
include Hocon::Impl::Unmergeable
|
18
|
+
include Hocon::Impl::ReplaceableMergeStack
|
19
|
+
include Hocon::Impl::AbstractConfigValue
|
20
|
+
|
21
|
+
ConfigImpl = Hocon::Impl::ConfigImpl
|
22
|
+
ResolveResult = Hocon::Impl::ResolveResult
|
23
|
+
|
24
|
+
def initialize(origin, stack)
|
25
|
+
super(origin)
|
26
|
+
@stack = stack
|
27
|
+
|
28
|
+
if stack.empty?
|
29
|
+
raise Hocon::ConfigError::ConfigBugOrBrokenError.new("creating empty delayed merge value", nil)
|
30
|
+
end
|
31
|
+
|
32
|
+
stack.each do |v|
|
33
|
+
if v.is_a?(Hocon::Impl::ConfigDelayedMerge) || v.is_a?(Hocon::Impl::ConfigDelayedMergeObject)
|
34
|
+
error_message = "placed nested DelayedMerge in a ConfigDelayedMerge, should have consolidated stack"
|
35
|
+
raise Hocon::ConfigError::ConfigBugOrBrokenError.new(error_message, nil)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
attr_reader :stack
|
41
|
+
|
42
|
+
|
43
|
+
def value_type
|
44
|
+
error_message = "called value_type() on value with unresolved substitutions, need to Config#resolve() first, see API docs"
|
45
|
+
raise Hocon::ConfigError::ConfigNotResolvedError.new(error_message, nil)
|
46
|
+
end
|
47
|
+
|
48
|
+
def unwrapped
|
49
|
+
error_message = "called unwrapped() on value with unresolved substitutions, need to Config#resolve() first, see API docs"
|
50
|
+
raise Hocon::ConfigError::ConfigNotResolvedError.new(error_message, nil)
|
51
|
+
end
|
52
|
+
|
53
|
+
def resolve_substitutions(context, source)
|
54
|
+
self.class.resolve_substitutions(self, stack, context, source)
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.resolve_substitutions(replaceable, stack, context, source)
|
58
|
+
if ConfigImpl.trace_substitution_enabled
|
59
|
+
ConfigImpl.trace("delayed merge stack has #{stack.size} items:", context.depth)
|
60
|
+
count = 0
|
61
|
+
stack.each do |v|
|
62
|
+
ConfigImpl.trace("#{count}: #{v}", context.depth)
|
63
|
+
count += 1
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# to resolve substitutions, we need to recursively resolve
|
68
|
+
# the stack of stuff to merge, and merge the stack so
|
69
|
+
# we won't be a delayed merge anymore. If restrictToChildOrNull
|
70
|
+
# is non-null, or resolve options allow partial resolves,
|
71
|
+
# we may remain a delayed merge though.
|
72
|
+
|
73
|
+
new_context = context
|
74
|
+
count = 0
|
75
|
+
merged = nil
|
76
|
+
stack.each do |stack_end|
|
77
|
+
# the end value may or may not be resolved already
|
78
|
+
|
79
|
+
if stack_end.is_a?(Hocon::Impl::ReplaceableMergeStack)
|
80
|
+
raise ConfigBugOrBrokenError, "A delayed merge should not contain another one: #{replaceable}"
|
81
|
+
elsif stack_end.is_a?(Hocon::Impl::Unmergeable)
|
82
|
+
# the remainder could be any kind of value, including another
|
83
|
+
# ConfigDelayedMerge
|
84
|
+
remainder = replaceable.make_replacement(context, count + 1)
|
85
|
+
|
86
|
+
if ConfigImpl.trace_substitution_enabled
|
87
|
+
ConfigImpl.trace("remainder portion: #{remainder}", new_context.depth)
|
88
|
+
end
|
89
|
+
|
90
|
+
# If, while resolving 'end' we come back to the same
|
91
|
+
# merge stack, we only want to look _below_ 'end'
|
92
|
+
# in the stack. So we arrange to replace the
|
93
|
+
# ConfigDelayedMerge with a value that is only
|
94
|
+
# the remainder of the stack below this one.
|
95
|
+
|
96
|
+
if ConfigImpl.trace_substitution_enabled
|
97
|
+
ConfigImpl.trace("building sourceForEnd", new_context.depth)
|
98
|
+
end
|
99
|
+
|
100
|
+
# we resetParents() here because we'll be resolving "end"
|
101
|
+
# against a root which does NOT contain "end"
|
102
|
+
source_for_end = source.replace_within_current_parent(replaceable, remainder)
|
103
|
+
|
104
|
+
if ConfigImpl.trace_substitution_enabled
|
105
|
+
ConfigImpl.trace(" sourceForEnd before reset parents but after replace: #{source_for_end}", new_context.depth)
|
106
|
+
end
|
107
|
+
|
108
|
+
source_for_end = source_for_end.reset_parents
|
109
|
+
else
|
110
|
+
if ConfigImpl.trace_substitution_enabled
|
111
|
+
ConfigImpl.trace("will resolve end against the original source with parent pushed",
|
112
|
+
new_context.depth)
|
113
|
+
end
|
114
|
+
|
115
|
+
source_for_end = source.push_parent(replaceable)
|
116
|
+
end
|
117
|
+
|
118
|
+
if ConfigImpl.trace_substitution_enabled
|
119
|
+
ConfigImpl.trace("sourceForEnd =#{source_for_end}", new_context.depth)
|
120
|
+
end
|
121
|
+
|
122
|
+
if ConfigImpl.trace_substitution_enabled
|
123
|
+
ConfigImpl.trace("Resolving highest-priority item in delayed merge #{stack_end}" +
|
124
|
+
" against #{source_for_end} endWasRemoved=#{(source != source_for_end)}")
|
125
|
+
end
|
126
|
+
|
127
|
+
result = new_context.resolve(stack_end, source_for_end)
|
128
|
+
resolved_end = result.value
|
129
|
+
new_context = result.context
|
130
|
+
|
131
|
+
if ! resolved_end.nil?
|
132
|
+
if merged.nil?
|
133
|
+
merged = resolved_end
|
134
|
+
else
|
135
|
+
if ConfigImpl.trace_substitution_enabled
|
136
|
+
ConfigImpl.trace("merging #{merged} with fallback #{resolved_end}",
|
137
|
+
new_context.depth + 1)
|
138
|
+
end
|
139
|
+
merged = merged.with_fallback(resolved_end)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
count += 1
|
144
|
+
|
145
|
+
if ConfigImpl.trace_substitution_enabled
|
146
|
+
ConfigImpl.trace("stack merged, yielding: #{merged}",
|
147
|
+
new_context.depth)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
ResolveResult.make(new_context, merged)
|
152
|
+
end
|
153
|
+
|
154
|
+
def make_replacement(context, skipping)
|
155
|
+
self.class.make_replacement(context, @stack, skipping)
|
156
|
+
end
|
157
|
+
|
158
|
+
# static method also used by ConfigDelayedMergeObject; end may be null
|
159
|
+
def self.make_replacement(context, stack, skipping)
|
160
|
+
sub_stack = stack.slice(skipping..stack.size)
|
161
|
+
|
162
|
+
if sub_stack.empty?
|
163
|
+
if ConfigImpl.trace_substitution_enabled
|
164
|
+
ConfigImpl.trace("Nothing else in the merge stack, replacing with null", context.depth)
|
165
|
+
return nil
|
166
|
+
end
|
167
|
+
else
|
168
|
+
# generate a new merge stack from only the remaining items
|
169
|
+
merged = nil
|
170
|
+
sub_stack.each do |v|
|
171
|
+
if merged.nil?
|
172
|
+
merged = v
|
173
|
+
else
|
174
|
+
merged = merged.with_fallback(v)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
merged
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def resolve_status
|
182
|
+
Hocon::Impl::ResolveStatus::UNRESOLVED
|
183
|
+
end
|
184
|
+
|
185
|
+
def replace_child(child, replacement)
|
186
|
+
new_stack = replace_child_in_list(stack, child, replacement)
|
187
|
+
if new_stack.nil?
|
188
|
+
nil
|
189
|
+
else
|
190
|
+
self.class.new(origin, new_stack)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def has_descendant?(descendant)
|
195
|
+
Hocon::Impl::AbstractConfigValue.has_descendant_in_list?(stack, descendant)
|
196
|
+
end
|
197
|
+
|
198
|
+
def relativized(prefix)
|
199
|
+
new_stack = stack.map { |o| o.relativized(prefix) }
|
200
|
+
self.class.new(origin, new_stack)
|
201
|
+
end
|
202
|
+
|
203
|
+
# static utility shared with ConfigDelayedMergeObject
|
204
|
+
def self.stack_ignores_fallbacks?(stack)
|
205
|
+
last = stack[-1]
|
206
|
+
last.ignores_fallbacks?
|
207
|
+
end
|
208
|
+
|
209
|
+
def ignores_fallbacks?
|
210
|
+
self.class.stack_ignores_fallbacks?(stack)
|
211
|
+
end
|
212
|
+
|
213
|
+
def new_copy(new_origin)
|
214
|
+
self.class.new(new_origin, stack)
|
215
|
+
end
|
216
|
+
|
217
|
+
def merged_with_the_unmergeable(fallback)
|
218
|
+
merged_stack_with_the_unmergeable(stack, fallback)
|
219
|
+
end
|
220
|
+
|
221
|
+
def merged_with_object(fallback)
|
222
|
+
merged_stack_with_object(stack, fallback)
|
223
|
+
end
|
224
|
+
|
225
|
+
def merged_with_non_object(fallback)
|
226
|
+
merged_stack_with_non_object(stack, fallback)
|
227
|
+
end
|
228
|
+
|
229
|
+
def unmerged_values
|
230
|
+
stack
|
231
|
+
end
|
232
|
+
|
233
|
+
def can_equal(other)
|
234
|
+
other.is_a? Hocon::Impl::ConfigDelayedMerge
|
235
|
+
end
|
236
|
+
|
237
|
+
def ==(other)
|
238
|
+
# note that "origin" is deliberately NOT part of equality
|
239
|
+
if other.is_a? Hocon::Impl::ConfigDelayedMerge
|
240
|
+
can_equal(other) && (@stack == other.stack || @stack.equal?(other.stack))
|
241
|
+
else
|
242
|
+
false
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def hash
|
247
|
+
# note that "origin" is deliberately NOT part of equality
|
248
|
+
@stack.hash
|
249
|
+
end
|
250
|
+
|
251
|
+
def render_to_sb(sb, indent, at_root, at_key, options)
|
252
|
+
self.class.render_value_to_sb_from_stack(stack, sb, indent, at_root, at_key, options)
|
253
|
+
end
|
254
|
+
|
255
|
+
# static method also used by ConfigDelayedMergeObject.
|
256
|
+
def self.render_value_to_sb_from_stack(stack, sb, indent, at_root, at_key, options)
|
257
|
+
comment_merge = options.comments
|
258
|
+
|
259
|
+
if comment_merge
|
260
|
+
sb << "# unresolved merge of #{stack.size} values follows (\n"
|
261
|
+
if at_key.nil?
|
262
|
+
self.indent(sb, indent, options)
|
263
|
+
sb << "# this unresolved merge will not be parseable because it's at the root of the object\n"
|
264
|
+
self.indent(sb, indent, options)
|
265
|
+
sb << "# the HOCON format has no way to list multiple root objects in a single file\n"
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
reversed = stack.reverse
|
270
|
+
|
271
|
+
i = 0
|
272
|
+
|
273
|
+
reversed.each do |v|
|
274
|
+
if comment_merge
|
275
|
+
self.indent(sb, indent, options)
|
276
|
+
if !at_key.nil?
|
277
|
+
rendered_key = Hocon::Impl::ConfigImplUtil.render_json_string(at_key)
|
278
|
+
sb << "# unmerged value #{i} for key #{rendered_key}"
|
279
|
+
else
|
280
|
+
sb << "# unmerged value #{i} from "
|
281
|
+
end
|
282
|
+
i += 1
|
283
|
+
|
284
|
+
sb << v.origin.description
|
285
|
+
sb << "\n"
|
286
|
+
|
287
|
+
v.origin.comments.each do |comment|
|
288
|
+
self.indent(sb, indent, options)
|
289
|
+
sb << "# "
|
290
|
+
sb << comment
|
291
|
+
sb << "\n"
|
292
|
+
end
|
293
|
+
end
|
294
|
+
Hocon::Impl::AbstractConfigValue.indent(sb, indent, options)
|
295
|
+
|
296
|
+
if !at_key.nil?
|
297
|
+
sb << Hocon::Impl::ConfigImplUtil.render_json_string(at_key)
|
298
|
+
if options.formatted
|
299
|
+
sb << " : "
|
300
|
+
else
|
301
|
+
sb << ":"
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
v.render_value_to_sb(sb, indent, at_root, options)
|
306
|
+
sb << ","
|
307
|
+
|
308
|
+
if options.formatted
|
309
|
+
sb.append "\n"
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
# chop comma or newline
|
314
|
+
# couldn't figure out a better way to chop characters off of the end of
|
315
|
+
# the StringIO. This relies on making sure that, prior to returning the
|
316
|
+
# final string, we take a substring that ends at sb.pos.
|
317
|
+
sb.pos = sb.pos - 1
|
318
|
+
if options.formatted
|
319
|
+
sb.pos = sb.pos - 1
|
320
|
+
sb << "\n"
|
321
|
+
end
|
322
|
+
|
323
|
+
if comment_merge
|
324
|
+
self.indent(sb, indent, options)
|
325
|
+
sb << "# ) end of unresolved merge\n"
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
end
|