hocon 0.0.7 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|