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,4 +1,7 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require 'hocon'
|
4
|
+
require 'hocon/config_error'
|
2
5
|
|
3
6
|
#
|
4
7
|
# The type of a configuration value (following the <a
|
@@ -20,7 +23,7 @@ module Hocon::ConfigValueType
|
|
20
23
|
when BOOLEAN then "BOOLEAN"
|
21
24
|
when NULL then "NULL"
|
22
25
|
when STRING then "STRING"
|
23
|
-
else raise
|
26
|
+
else raise Hocon::ConfigError::ConfigBugOrBrokenError, "Unrecognized value type '#{config_value_type}'"
|
24
27
|
end
|
25
28
|
end
|
26
|
-
end
|
29
|
+
end
|
data/lib/hocon/impl.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'hocon/impl'
|
4
|
+
require 'hocon/parser/config_node'
|
5
|
+
require 'hocon/config_error'
|
6
|
+
|
7
|
+
module Hocon::Impl::AbstractConfigNode
|
8
|
+
include Hocon::Parser::ConfigNode
|
9
|
+
def tokens
|
10
|
+
raise Hocon::ConfigError::ConfigBugOrBrokenError, "subclasses of AbstractConfigNode should override `tokens` (#{self.class})"
|
11
|
+
end
|
12
|
+
|
13
|
+
def render
|
14
|
+
orig_text = StringIO.new
|
15
|
+
tokens.each do |t|
|
16
|
+
orig_text << t.token_text
|
17
|
+
end
|
18
|
+
orig_text.string
|
19
|
+
end
|
20
|
+
|
21
|
+
def ==(other)
|
22
|
+
other.is_a?(Hocon::Impl::AbstractConfigNode) &&
|
23
|
+
(render == other.render)
|
24
|
+
end
|
25
|
+
|
26
|
+
def hash
|
27
|
+
render.hash
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'hocon/impl'
|
4
|
+
require 'hocon/impl/abstract_config_node'
|
5
|
+
|
6
|
+
# This essentially exists in the upstream so we can ensure only certain types of
|
7
|
+
# config nodes can be passed into some methods. That's not a problem in Ruby, so this is
|
8
|
+
# unnecessary, but it seems best to keep it around for consistency
|
9
|
+
module Hocon::Impl::AbstractConfigNodeValue
|
10
|
+
include Hocon::Impl::AbstractConfigNode
|
11
|
+
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/simple_config'
|
@@ -7,9 +9,13 @@ require 'hocon/impl/resolve_status'
|
|
7
9
|
require 'hocon/impl/simple_config_origin'
|
8
10
|
require 'hocon/config_error'
|
9
11
|
require 'hocon/impl/config_impl'
|
12
|
+
require 'hocon/impl/unsupported_operation_error'
|
13
|
+
require 'hocon/impl/container'
|
10
14
|
|
11
|
-
|
15
|
+
module Hocon::Impl::AbstractConfigObject
|
12
16
|
include Hocon::ConfigObject
|
17
|
+
include Hocon::Impl::Container
|
18
|
+
include Hocon::Impl::AbstractConfigValue
|
13
19
|
|
14
20
|
ConfigBugOrBrokenError = Hocon::ConfigError::ConfigBugOrBrokenError
|
15
21
|
ConfigNotResolvedError = Hocon::ConfigError::ConfigNotResolvedError
|
@@ -27,17 +33,117 @@ class Hocon::Impl::AbstractConfigObject < Hocon::Impl::AbstractConfigValue
|
|
27
33
|
self
|
28
34
|
end
|
29
35
|
|
36
|
+
def with_only_key(key)
|
37
|
+
raise ConfigBugOrBrokenError, "subclasses of AbstractConfigObject should override `with_only_key`"
|
38
|
+
end
|
39
|
+
|
40
|
+
def without_key(key)
|
41
|
+
raise ConfigBugOrBrokenError, "subclasses of AbstractConfigObject should override `without_key`"
|
42
|
+
end
|
43
|
+
|
44
|
+
def with_value(key, value)
|
45
|
+
raise ConfigBugOrBrokenError, "subclasses of AbstractConfigObject should override `with_value`"
|
46
|
+
end
|
47
|
+
|
48
|
+
def with_only_path_or_nil(path)
|
49
|
+
raise ConfigBugOrBrokenError, "subclasses of AbstractConfigObject should override `with_only_path_or_nil`"
|
50
|
+
end
|
51
|
+
|
52
|
+
def with_only_path(path)
|
53
|
+
raise ConfigBugOrBrokenError, "subclasses of AbstractConfigObject should override `with_only_path`"
|
54
|
+
end
|
55
|
+
|
56
|
+
def without_path(path)
|
57
|
+
raise ConfigBugOrBrokenError, "subclasses of AbstractConfigObject should override `without_path`"
|
58
|
+
end
|
59
|
+
|
60
|
+
def with_path_value(path, value)
|
61
|
+
raise ConfigBugOrBrokenError, "subclasses of AbstractConfigObject should override `with_path_value`"
|
62
|
+
end
|
63
|
+
|
64
|
+
# This looks up the key with no transformation or type conversion of any
|
65
|
+
# kind, and returns null if the key is not present. The object must be
|
66
|
+
# resolved along the nodes needed to get the key or
|
67
|
+
# ConfigNotResolvedError will be thrown.
|
68
|
+
#
|
69
|
+
# @param key
|
70
|
+
# @return the unmodified raw value or null
|
71
|
+
def peek_assuming_resolved(key, original_path)
|
72
|
+
begin
|
73
|
+
attempt_peek_with_partial_resolve(key)
|
74
|
+
rescue ConfigNotResolvedError => e
|
75
|
+
raise Hocon::Impl::ConfigImpl.improve_not_resolved(original_path, e)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Look up the key on an only-partially-resolved object, with no
|
80
|
+
# transformation or type conversion of any kind; if 'this' is not resolved
|
81
|
+
# then try to look up the key anyway if possible.
|
82
|
+
#
|
83
|
+
# @param key
|
84
|
+
# key to look up
|
85
|
+
# @return the value of the key, or null if known not to exist
|
86
|
+
# @throws ConfigNotResolvedError
|
87
|
+
# if can't figure out key's value (or existence) without more
|
88
|
+
# resolving
|
89
|
+
def attempt_peek_with_partial_resolve(key)
|
90
|
+
raise ConfigBugOrBrokenError, "subclasses of AbstractConfigObject should override `attempt_peek_with_partial_resolve`"
|
91
|
+
end
|
92
|
+
|
93
|
+
# Looks up the path with no transformation or type conversion. Returns null
|
94
|
+
# if the path is not found; throws ConfigException.NotResolved if we need
|
95
|
+
# to go through an unresolved node to look up the path.
|
96
|
+
def peek_path(path)
|
97
|
+
peek_path_from_obj(self, path)
|
98
|
+
end
|
99
|
+
|
100
|
+
def peek_path_from_obj(obj, path)
|
101
|
+
begin
|
102
|
+
# we'll fail if anything along the path can't be looked at without resolving
|
103
|
+
path_next = path.remainder
|
104
|
+
v = obj.attempt_peek_with_partial_resolve(path.first)
|
105
|
+
|
106
|
+
if path_next.nil?
|
107
|
+
v
|
108
|
+
else
|
109
|
+
if v.is_a?(Hocon::Impl::AbstractConfigObject)
|
110
|
+
peek_path_from_obj(v, path_next)
|
111
|
+
else
|
112
|
+
nil
|
113
|
+
end
|
114
|
+
end
|
115
|
+
rescue ConfigNotResolvedError => e
|
116
|
+
raise Hocon::Impl::ConfigImpl.improve_not_resolved(path, e)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
30
120
|
def value_type
|
31
121
|
Hocon::ConfigValueType::OBJECT
|
32
122
|
end
|
33
123
|
|
124
|
+
def new_copy_with_status(status, origin)
|
125
|
+
raise ConfigBugOrBrokenError, "subclasses of AbstractConfigObject should override `new_copy_with_status`"
|
126
|
+
end
|
127
|
+
|
34
128
|
def new_copy(origin)
|
35
129
|
new_copy_with_status(resolve_status, origin)
|
36
130
|
end
|
37
131
|
|
38
|
-
def
|
132
|
+
def construct_delayed_merge(origin, stack)
|
133
|
+
Hocon::Impl::ConfigDelayedMergeObject.new(origin, stack)
|
134
|
+
end
|
135
|
+
|
136
|
+
def merged_with_object(fallback)
|
137
|
+
raise ConfigBugOrBrokenError, "subclasses of AbstractConfigObject should override `merged_with_object`"
|
138
|
+
end
|
139
|
+
|
140
|
+
def with_fallback(mergeable)
|
141
|
+
super(mergeable)
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.merge_origins(stack)
|
39
145
|
if stack.empty?
|
40
|
-
raise
|
146
|
+
raise ConfigBugOrBrokenError, "can't merge origins on empty list"
|
41
147
|
end
|
42
148
|
origins = []
|
43
149
|
first_origin = nil
|
@@ -67,47 +173,47 @@ class Hocon::Impl::AbstractConfigObject < Hocon::Impl::AbstractConfigValue
|
|
67
173
|
Hocon::Impl::SimpleConfigOrigin.merge_origins(origins)
|
68
174
|
end
|
69
175
|
|
70
|
-
def
|
71
|
-
|
72
|
-
attempt_peek_with_partial_resolve(key)
|
73
|
-
rescue ConfigNotResolvedError => e
|
74
|
-
raise Hocon::Impl::ConfigImpl.improve_not_resolved(original_path, e)
|
75
|
-
end
|
176
|
+
def resolve_substitutions(context, source)
|
177
|
+
raise ConfigBugOrBrokenError, "subclasses of AbstractConfigObject should override `resolve_substituions`"
|
76
178
|
end
|
77
179
|
|
78
|
-
def
|
79
|
-
|
80
|
-
return peek_path_impl(self, path, nil)
|
81
|
-
rescue ConfigNotResolvedError => e
|
82
|
-
raise ConfigBugOrBrokenError.new("NotPossibleToResolve happened though we had no ResolveContext in peek_path", nil)
|
83
|
-
end
|
180
|
+
def relativized(path)
|
181
|
+
raise ConfigBugOrBrokenError, "subclasses of AbstractConfigObject should override `relativized`"
|
84
182
|
end
|
85
183
|
|
86
|
-
def
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
184
|
+
def [](key)
|
185
|
+
raise ConfigBugOrBrokenError, "subclasses of AbstractConfigObject should override `[]`"
|
186
|
+
end
|
187
|
+
|
188
|
+
def render_value_to_sb(sb, indent, at_root, options)
|
189
|
+
raise ConfigBugOrBrokenError, "subclasses of AbstractConfigObject should override `render_value_to_sb`"
|
190
|
+
end
|
191
|
+
|
192
|
+
def we_are_immutable(method)
|
193
|
+
Hocon::Impl::UnsupportedOperationError.new("ConfigObject is immutable, you can't call Map.#{method}")
|
194
|
+
end
|
195
|
+
|
196
|
+
def clear
|
197
|
+
raise we_are_immutable("clear")
|
198
|
+
end
|
199
|
+
|
200
|
+
def []=(key, value)
|
201
|
+
raise we_are_immutable("[]=")
|
202
|
+
end
|
203
|
+
|
204
|
+
def putAll(map)
|
205
|
+
raise we_are_immutable("putAll")
|
206
|
+
end
|
207
|
+
|
208
|
+
def remove(key)
|
209
|
+
raise we_are_immutable("remove")
|
210
|
+
end
|
211
|
+
|
212
|
+
def delete(key)
|
213
|
+
raise we_are_immutable("delete")
|
214
|
+
end
|
215
|
+
|
216
|
+
def with_origin(origin)
|
217
|
+
super(origin)
|
112
218
|
end
|
113
|
-
end
|
219
|
+
end
|
@@ -1,19 +1,27 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require 'hocon/impl'
|
2
4
|
require 'stringio'
|
3
5
|
require 'hocon/config_render_options'
|
4
6
|
require 'hocon/config_object'
|
5
7
|
require 'hocon/impl/resolve_status'
|
8
|
+
require 'hocon/impl/resolve_result'
|
6
9
|
require 'hocon/impl/unmergeable'
|
7
|
-
require 'hocon/impl/abstract_config_object'
|
8
10
|
require 'hocon/impl/config_impl_util'
|
11
|
+
require 'hocon/config_error'
|
12
|
+
require 'hocon/config_value'
|
9
13
|
|
10
14
|
##
|
11
15
|
## Trying very hard to avoid a parent reference in config values; when you have
|
12
16
|
## a tree like this, the availability of parent() tends to result in a lot of
|
13
17
|
## improperly-factored and non-modular code. Please don't add parent().
|
14
18
|
##
|
15
|
-
|
19
|
+
module Hocon::Impl::AbstractConfigValue
|
20
|
+
include Hocon::ConfigValue
|
21
|
+
|
16
22
|
ConfigImplUtil = Hocon::Impl::ConfigImplUtil
|
23
|
+
ConfigBugOrBrokenError = Hocon::ConfigError::ConfigBugOrBrokenError
|
24
|
+
ResolveStatus = Hocon::Impl::ResolveStatus
|
17
25
|
|
18
26
|
def initialize(origin)
|
19
27
|
@origin = origin
|
@@ -21,10 +29,110 @@ class Hocon::Impl::AbstractConfigValue
|
|
21
29
|
|
22
30
|
attr_reader :origin
|
23
31
|
|
32
|
+
# This exception means that a value is inherently not resolveable, at the
|
33
|
+
# moment the only known cause is a cycle of substitutions. This is a
|
34
|
+
# checked exception since it's internal to the library and we want to be
|
35
|
+
# sure we handle it before passing it out to public API. This is only
|
36
|
+
# supposed to be thrown by the target of a cyclic reference and it's
|
37
|
+
# supposed to be caught by the ConfigReference looking up that reference,
|
38
|
+
# so it should be impossible for an outermost resolve() to throw this.
|
39
|
+
#
|
40
|
+
# Contrast with ConfigException.NotResolved which just means nobody called
|
41
|
+
# resolve().
|
42
|
+
class NotPossibleToResolve < Exception
|
43
|
+
def initialize(context)
|
44
|
+
super("was not possible to resolve")
|
45
|
+
@trace_string = context.trace_string
|
46
|
+
end
|
47
|
+
|
48
|
+
attr_reader :trace_string
|
49
|
+
end
|
50
|
+
|
51
|
+
# Called only by ResolveContext.resolve
|
52
|
+
#
|
53
|
+
# @param context
|
54
|
+
# state of the current resolve
|
55
|
+
# @param source
|
56
|
+
# where to look up values
|
57
|
+
# @return a new value if there were changes, or this if no changes
|
58
|
+
def resolve_substitutions(context, source)
|
59
|
+
Hocon::Impl::ResolveResult.make(context, self)
|
60
|
+
end
|
61
|
+
|
24
62
|
def resolve_status
|
25
63
|
Hocon::Impl::ResolveStatus::RESOLVED
|
26
64
|
end
|
27
65
|
|
66
|
+
def self.replace_child_in_list(list, child, replacement)
|
67
|
+
i = 0
|
68
|
+
while (i < list.size) && (! list[i].equal?(child))
|
69
|
+
i += 1
|
70
|
+
end
|
71
|
+
if (i == list.size)
|
72
|
+
raise ConfigBugOrBrokenError, "tried to replace #{child} which is not in #{list}"
|
73
|
+
end
|
74
|
+
|
75
|
+
new_stack = list.clone
|
76
|
+
if ! replacement.nil?
|
77
|
+
new_stack[i] = replacement
|
78
|
+
else
|
79
|
+
new_stack.delete(i)
|
80
|
+
end
|
81
|
+
|
82
|
+
if new_stack.empty?
|
83
|
+
nil
|
84
|
+
else
|
85
|
+
new_stack
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.has_descendant_in_list?(list, descendant)
|
90
|
+
list.each do |v|
|
91
|
+
if v.equal?(descendant)
|
92
|
+
return true
|
93
|
+
end
|
94
|
+
end
|
95
|
+
# now the expensive traversal
|
96
|
+
list.each do |v|
|
97
|
+
if v.is_a?(Hocon::Impl::Container) && v.has_descendant?(descendant)
|
98
|
+
return true
|
99
|
+
end
|
100
|
+
end
|
101
|
+
false
|
102
|
+
end
|
103
|
+
|
104
|
+
# This is used when including one file in another; the included file is
|
105
|
+
# relativized to the path it's included into in the parent file. The point
|
106
|
+
# is that if you include a file at foo.bar in the parent, and the included
|
107
|
+
# file as a substitution ${a.b.c}, the included substitution now needs to
|
108
|
+
# be ${foo.bar.a.b.c} because we resolve substitutions globally only after
|
109
|
+
# parsing everything.
|
110
|
+
#
|
111
|
+
# @param prefix
|
112
|
+
# @return value relativized to the given path or the same value if nothing
|
113
|
+
# to do
|
114
|
+
def relativized(prefix)
|
115
|
+
self
|
116
|
+
end
|
117
|
+
|
118
|
+
module NoExceptionsModifier
|
119
|
+
def modify_child_may_throw(key_or_nil, v)
|
120
|
+
begin
|
121
|
+
modify_child(key_or_nil, v)
|
122
|
+
rescue Hocon::ConfigError => e
|
123
|
+
raise e
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def to_fallback_value
|
129
|
+
self
|
130
|
+
end
|
131
|
+
|
132
|
+
def new_copy(origin)
|
133
|
+
raise ConfigBugOrBrokenError, "subclasses of AbstractConfigValue should provide their own implementation of `new_copy` (#{self.class})"
|
134
|
+
end
|
135
|
+
|
28
136
|
# this is virtualized rather than a field because only some subclasses
|
29
137
|
# really need to store the boolean, and they may be able to pack it
|
30
138
|
# with another boolean to save space.
|
@@ -34,16 +142,97 @@ class Hocon::Impl::AbstractConfigValue
|
|
34
142
|
resolve_status == Hocon::Impl::ResolveStatus::RESOLVED
|
35
143
|
end
|
36
144
|
|
145
|
+
def with_fallbacks_ignored
|
146
|
+
if ignores_fallbacks?
|
147
|
+
self
|
148
|
+
else
|
149
|
+
raise ConfigBugOrBrokenError, "value class doesn't implement forced fallback-ignoring #{self}"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
37
153
|
# the withFallback() implementation is supposed to avoid calling
|
38
154
|
# mergedWith* if we're ignoring fallbacks.
|
39
155
|
def require_not_ignoring_fallbacks
|
40
156
|
if ignores_fallbacks?
|
41
|
-
raise
|
157
|
+
raise ConfigBugOrBrokenError, "method should not have been called with ignoresFallbacks=true #{self.class.name}"
|
42
158
|
end
|
43
159
|
end
|
44
160
|
|
161
|
+
def construct_delayed_merge(origin, stack)
|
162
|
+
# TODO: this might not work because ConfigDelayedMerge inherits
|
163
|
+
# from this class, so we can't `require` it from this file
|
164
|
+
require 'hocon/impl/config_delayed_merge'
|
165
|
+
Hocon::Impl::ConfigDelayedMerge.new(origin, stack)
|
166
|
+
end
|
167
|
+
|
168
|
+
def merged_stack_with_the_unmergeable(stack, fallback)
|
169
|
+
require_not_ignoring_fallbacks
|
170
|
+
|
171
|
+
# if we turn out to be an object, and the fallback also does,
|
172
|
+
# then a merge may be required; delay until we resolve.
|
173
|
+
new_stack = stack.clone
|
174
|
+
new_stack.concat(fallback.unmerged_values)
|
175
|
+
# TODO: this might not work because AbstractConfigObject inherits
|
176
|
+
# from this class, so we can't `require` it from this file
|
177
|
+
construct_delayed_merge(Hocon::Impl::AbstractConfigObject.merge_origins(new_stack), new_stack)
|
178
|
+
end
|
179
|
+
|
180
|
+
def delay_merge(stack, fallback)
|
181
|
+
# if we turn out to be an object, and the fallback also does,
|
182
|
+
# then a merge may be required.
|
183
|
+
# if we contain a substitution, resolving it may need to look
|
184
|
+
# back to the fallback
|
185
|
+
new_stack = stack.clone
|
186
|
+
new_stack << fallback
|
187
|
+
# TODO: this might not work because AbstractConfigObject inherits
|
188
|
+
# from this class, so we can't `require` it from this file
|
189
|
+
construct_delayed_merge(Hocon::Impl::AbstractConfigObject.merge_origins(new_stack), new_stack)
|
190
|
+
end
|
191
|
+
|
192
|
+
def merged_stack_with_object(stack, fallback)
|
193
|
+
require_not_ignoring_fallbacks
|
194
|
+
|
195
|
+
# TODO: this might not work because AbstractConfigObject inherits
|
196
|
+
# from this class, so we can't `require` it from this file
|
197
|
+
if self.is_a?(Hocon::Impl::AbstractConfigObject)
|
198
|
+
raise ConfigBugOrBrokenError, "Objects must reimplement merged_with_object"
|
199
|
+
end
|
200
|
+
|
201
|
+
merged_stack_with_non_object(stack, fallback)
|
202
|
+
end
|
203
|
+
|
204
|
+
def merged_stack_with_non_object(stack, fallback)
|
205
|
+
require_not_ignoring_fallbacks
|
206
|
+
|
207
|
+
if resolve_status == ResolveStatus::RESOLVED
|
208
|
+
# falling back to a non-object doesn't merge anything, and also
|
209
|
+
# prohibits merging any objects that we fall back to later.
|
210
|
+
# so we have to switch to ignoresFallbacks mode.
|
211
|
+
with_fallbacks_ignored
|
212
|
+
else
|
213
|
+
# if unresolved we may have to look back to fallbacks as part of
|
214
|
+
# the resolution process, so always delay
|
215
|
+
delay_merge(stack, fallback)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def merged_with_the_unmergeable(fallback)
|
220
|
+
require_not_ignoring_fallbacks
|
221
|
+
merged_stack_with_the_unmergeable([self], fallback)
|
222
|
+
end
|
223
|
+
|
224
|
+
def merged_with_object(fallback)
|
225
|
+
require_not_ignoring_fallbacks
|
226
|
+
merged_stack_with_object([self], fallback)
|
227
|
+
end
|
228
|
+
|
229
|
+
def merged_with_non_object(fallback)
|
230
|
+
require_not_ignoring_fallbacks
|
231
|
+
merged_stack_with_non_object([self], fallback)
|
232
|
+
end
|
233
|
+
|
45
234
|
def with_origin(origin)
|
46
|
-
if @origin
|
235
|
+
if @origin.equal?(origin)
|
47
236
|
self
|
48
237
|
else
|
49
238
|
new_copy(origin)
|
@@ -57,6 +246,8 @@ class Hocon::Impl::AbstractConfigValue
|
|
57
246
|
other = mergeable.to_fallback_value
|
58
247
|
if other.is_a?(Hocon::Impl::Unmergeable)
|
59
248
|
merged_with_the_unmergeable(other)
|
249
|
+
# TODO: this probably isn't going to work because AbstractConfigObject inherits
|
250
|
+
# from this class, so we can't `require` it from this file
|
60
251
|
elsif other.is_a?(Hocon::Impl::AbstractConfigObject)
|
61
252
|
merged_with_object(other)
|
62
253
|
else
|
@@ -65,13 +256,42 @@ class Hocon::Impl::AbstractConfigValue
|
|
65
256
|
end
|
66
257
|
end
|
67
258
|
|
259
|
+
def can_equal(other)
|
260
|
+
other.is_a?(Hocon::Impl::AbstractConfigValue)
|
261
|
+
end
|
262
|
+
|
263
|
+
def ==(other)
|
264
|
+
# note that "origin" is deliberately NOT part of equality
|
265
|
+
if other.is_a?(Hocon::Impl::AbstractConfigValue)
|
266
|
+
can_equal(other) &&
|
267
|
+
value_type == other.value_type &&
|
268
|
+
ConfigImplUtil.equals_handling_nil?(unwrapped, other.unwrapped)
|
269
|
+
else
|
270
|
+
false
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def hash
|
275
|
+
# note that "origin" is deliberately NOT part of equality
|
276
|
+
unwrapped_value = unwrapped
|
277
|
+
if unwrapped_value.nil?
|
278
|
+
0
|
279
|
+
else
|
280
|
+
unwrapped_value.hash
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
68
284
|
def to_s
|
69
285
|
sb = StringIO.new
|
70
286
|
render_to_sb(sb, 0, true, nil, Hocon::ConfigRenderOptions.concise)
|
71
|
-
"#{self.class.name}(#{sb.string})"
|
287
|
+
"#{self.class.name.split('::').last}(#{sb.string})"
|
72
288
|
end
|
73
289
|
|
74
|
-
def
|
290
|
+
def inspect
|
291
|
+
to_s
|
292
|
+
end
|
293
|
+
|
294
|
+
def self.indent(sb, indent_size, options)
|
75
295
|
if options.formatted?
|
76
296
|
remaining = indent_size
|
77
297
|
while remaining > 0
|
@@ -127,20 +347,40 @@ class Hocon::Impl::AbstractConfigValue
|
|
127
347
|
sb.string[0, sb.pos]
|
128
348
|
end
|
129
349
|
|
130
|
-
|
350
|
+
# toString() is a debugging-oriented string but this is defined
|
351
|
+
# to create a string that would parse back to the value in JSON.
|
352
|
+
# It only works for primitive values (that would be a single
|
353
|
+
# which are auto-converted to strings when concatenating with
|
354
|
+
# other strings or by the DefaultTransformer.
|
355
|
+
def transform_to_string
|
356
|
+
nil
|
357
|
+
end
|
358
|
+
|
359
|
+
def at_key(key)
|
360
|
+
at_key_with_origin(Hocon::Impl::SimpleConfigOrigin.new_simple("at_key(#{key})"), key)
|
361
|
+
end
|
362
|
+
|
363
|
+
# Renamed this to be consistent with the other at_key* overloaded methods
|
364
|
+
def at_key_with_origin(origin, key)
|
131
365
|
m = {key=>self}
|
132
366
|
Hocon::Impl::SimpleConfigObject.new(origin, m).to_config
|
133
367
|
end
|
134
368
|
|
135
|
-
|
369
|
+
# In java this is an overloaded version of atPath
|
370
|
+
def at_path_with_origin(origin, path)
|
136
371
|
parent = path.parent
|
137
|
-
result =
|
372
|
+
result = at_key_with_origin(origin, path.last)
|
138
373
|
while not parent.nil? do
|
139
374
|
key = parent.last
|
140
|
-
result = result.
|
375
|
+
result = result.at_key_with_origin(origin, key)
|
141
376
|
parent = parent.parent
|
142
377
|
end
|
143
378
|
result
|
144
379
|
end
|
145
380
|
|
146
|
-
|
381
|
+
def at_path(path_expression)
|
382
|
+
origin = Hocon::Impl::SimpleConfigOrigin.new_simple("at_path(#{path_expression})")
|
383
|
+
at_path_with_origin(origin, Hocon::Impl::Path.new_path(path_expression))
|
384
|
+
end
|
385
|
+
|
386
|
+
end
|