hocon 0.0.7 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +4 -2
  3. data/lib/hocon.rb +2 -0
  4. data/lib/hocon/config.rb +1010 -0
  5. data/lib/hocon/config_error.rb +32 -2
  6. data/lib/hocon/config_factory.rb +46 -0
  7. data/lib/hocon/config_include_context.rb +49 -0
  8. data/lib/hocon/config_includer_file.rb +27 -0
  9. data/lib/hocon/config_list.rb +49 -0
  10. data/lib/hocon/config_mergeable.rb +74 -0
  11. data/lib/hocon/config_object.rb +144 -1
  12. data/lib/hocon/config_parse_options.rb +33 -9
  13. data/lib/hocon/config_parseable.rb +51 -0
  14. data/lib/hocon/config_render_options.rb +4 -2
  15. data/lib/hocon/config_resolve_options.rb +31 -0
  16. data/lib/hocon/config_syntax.rb +5 -2
  17. data/lib/hocon/config_util.rb +73 -0
  18. data/lib/hocon/config_value.rb +122 -0
  19. data/lib/hocon/config_value_factory.rb +66 -2
  20. data/lib/hocon/config_value_type.rb +5 -2
  21. data/lib/hocon/impl.rb +2 -0
  22. data/lib/hocon/impl/abstract_config_node.rb +29 -0
  23. data/lib/hocon/impl/abstract_config_node_value.rb +11 -0
  24. data/lib/hocon/impl/abstract_config_object.rb +148 -42
  25. data/lib/hocon/impl/abstract_config_value.rb +251 -11
  26. data/lib/hocon/impl/array_iterator.rb +19 -0
  27. data/lib/hocon/impl/config_boolean.rb +7 -1
  28. data/lib/hocon/impl/config_concatenation.rb +177 -28
  29. data/lib/hocon/impl/config_delayed_merge.rb +329 -0
  30. data/lib/hocon/impl/config_delayed_merge_object.rb +274 -0
  31. data/lib/hocon/impl/config_document_parser.rb +647 -0
  32. data/lib/hocon/impl/config_double.rb +44 -0
  33. data/lib/hocon/impl/config_impl.rb +143 -19
  34. data/lib/hocon/impl/config_impl_util.rb +18 -0
  35. data/lib/hocon/impl/config_include_kind.rb +10 -0
  36. data/lib/hocon/impl/config_int.rb +13 -1
  37. data/lib/hocon/impl/config_node_array.rb +11 -0
  38. data/lib/hocon/impl/config_node_comment.rb +19 -0
  39. data/lib/hocon/impl/config_node_complex_value.rb +54 -0
  40. data/lib/hocon/impl/config_node_concatenation.rb +11 -0
  41. data/lib/hocon/impl/config_node_field.rb +81 -0
  42. data/lib/hocon/impl/config_node_include.rb +33 -0
  43. data/lib/hocon/impl/config_node_object.rb +276 -0
  44. data/lib/hocon/impl/config_node_path.rb +48 -0
  45. data/lib/hocon/impl/config_node_root.rb +60 -0
  46. data/lib/hocon/impl/config_node_simple_value.rb +42 -0
  47. data/lib/hocon/impl/config_node_single_token.rb +17 -0
  48. data/lib/hocon/impl/config_null.rb +15 -7
  49. data/lib/hocon/impl/config_number.rb +43 -4
  50. data/lib/hocon/impl/config_parser.rb +403 -0
  51. data/lib/hocon/impl/config_reference.rb +142 -0
  52. data/lib/hocon/impl/config_string.rb +55 -7
  53. data/lib/hocon/impl/container.rb +29 -0
  54. data/lib/hocon/impl/default_transformer.rb +24 -15
  55. data/lib/hocon/impl/from_map_mode.rb +3 -1
  56. data/lib/hocon/impl/full_includer.rb +2 -0
  57. data/lib/hocon/impl/memo_key.rb +42 -0
  58. data/lib/hocon/impl/mergeable_value.rb +8 -0
  59. data/lib/hocon/impl/origin_type.rb +8 -2
  60. data/lib/hocon/impl/parseable.rb +455 -91
  61. data/lib/hocon/impl/path.rb +181 -59
  62. data/lib/hocon/impl/path_builder.rb +24 -3
  63. data/lib/hocon/impl/path_parser.rb +280 -0
  64. data/lib/hocon/impl/replaceable_merge_stack.rb +22 -0
  65. data/lib/hocon/impl/resolve_context.rb +254 -0
  66. data/lib/hocon/impl/resolve_memos.rb +21 -0
  67. data/lib/hocon/impl/resolve_result.rb +39 -0
  68. data/lib/hocon/impl/resolve_source.rb +354 -0
  69. data/lib/hocon/impl/resolve_status.rb +3 -1
  70. data/lib/hocon/impl/simple_config.rb +264 -10
  71. data/lib/hocon/impl/simple_config_document.rb +48 -0
  72. data/lib/hocon/impl/simple_config_list.rb +282 -8
  73. data/lib/hocon/impl/simple_config_object.rb +424 -88
  74. data/lib/hocon/impl/simple_config_origin.rb +263 -71
  75. data/lib/hocon/impl/simple_include_context.rb +31 -1
  76. data/lib/hocon/impl/simple_includer.rb +196 -1
  77. data/lib/hocon/impl/substitution_expression.rb +38 -0
  78. data/lib/hocon/impl/token.rb +17 -4
  79. data/lib/hocon/impl/token_type.rb +6 -2
  80. data/lib/hocon/impl/tokenizer.rb +339 -109
  81. data/lib/hocon/impl/tokens.rb +330 -79
  82. data/lib/hocon/impl/unmergeable.rb +14 -1
  83. data/lib/hocon/impl/unsupported_operation_error.rb +6 -0
  84. data/lib/hocon/impl/url.rb +37 -0
  85. data/lib/hocon/parser.rb +7 -0
  86. data/lib/hocon/parser/config_document.rb +92 -0
  87. data/lib/hocon/parser/config_document_factory.rb +36 -0
  88. data/lib/hocon/parser/config_node.rb +30 -0
  89. metadata +67 -43
  90. data/lib/hocon/impl/config_float.rb +0 -13
  91. data/lib/hocon/impl/parser.rb +0 -977
  92. data/lib/hocon/impl/properties_parser.rb +0 -83
@@ -1,28 +1,34 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'hocon/impl'
2
4
  require 'hocon/impl/simple_config_origin'
3
5
  require 'hocon/impl/abstract_config_object'
4
6
  require 'hocon/impl/resolve_status'
7
+ require 'hocon/impl/resolve_result'
8
+ require 'hocon/impl/path'
5
9
  require 'hocon/config_error'
6
10
  require 'set'
11
+ require 'forwardable'
12
+
7
13
 
8
- class Hocon::Impl::SimpleConfigObject < Hocon::Impl::AbstractConfigObject
14
+ class Hocon::Impl::SimpleConfigObject
15
+ include Hocon::Impl::AbstractConfigObject
16
+ extend Forwardable
9
17
 
10
18
  ConfigBugOrBrokenError = Hocon::ConfigError::ConfigBugOrBrokenError
11
19
  ResolveStatus = Hocon::Impl::ResolveStatus
20
+ ResolveResult = Hocon::Impl::ResolveResult
12
21
  SimpleConfigOrigin = Hocon::Impl::SimpleConfigOrigin
22
+ Path = Hocon::Impl::Path
13
23
 
14
- def self.empty_missing(base_origin)
15
- self.new(
16
- Hocon::Impl::SimpleConfigOrigin.new_simple("#{base_origin.description} (not found)"),
17
- {})
18
- end
19
24
 
20
- def initialize(origin, value,
21
- status = Hocon::Impl::ResolveStatus.from_values(value.values),
22
- ignores_fallbacks = false)
25
+ def initialize(origin,
26
+ value,
27
+ status = Hocon::Impl::ResolveStatus.from_values(value.values),
28
+ ignores_fallbacks = false)
23
29
  super(origin)
24
30
  if value.nil?
25
- raise ConfigBugError, "creating config object with null map"
31
+ raise ConfigBugOrBrokenError, "creating config object with null map"
26
32
  end
27
33
  @value = value
28
34
  @resolved = (status == Hocon::Impl::ResolveStatus::RESOLVED)
@@ -30,15 +36,170 @@ class Hocon::Impl::SimpleConfigObject < Hocon::Impl::AbstractConfigObject
30
36
 
31
37
  # Kind of an expensive debug check. Comment out?
32
38
  if status != Hocon::Impl::ResolveStatus.from_values(value.values)
33
- raise ConfigBugError, "Wrong resolved status on #{self}"
39
+ raise ConfigBugOrBrokenError, "Wrong resolved status on #{self}"
34
40
  end
35
41
  end
36
42
 
37
43
  attr_reader :value
44
+ # To support accessing ConfigObjects like a hash
45
+ def_delegators :@value, :[], :has_key?, :has_value?, :empty?, :size, :keys, :values, :each, :map
46
+
47
+
48
+ def with_only_key(key)
49
+ with_only_path(Path.new_key(key))
50
+ end
51
+
52
+ def without_key(key)
53
+ without_path(Path.new_key(key))
54
+ end
55
+
56
+ # gets the object with only the path if the path
57
+ # exists, otherwise null if it doesn't. this ensures
58
+ # that if we have { a : { b : 42 } } and do
59
+ # withOnlyPath("a.b.c") that we don't keep an empty
60
+ # "a" object.
61
+ def with_only_path_or_nil(path)
62
+ key = path.first
63
+ path_next = path.remainder
64
+ v = value[key]
65
+
66
+ if ! path_next.nil?
67
+ if (!v.nil?) && (v.is_a?(Hocon::Impl::AbstractConfigObject))
68
+ v = v.with_only_path_or_nil(path_next)
69
+ else
70
+ # if the path has more elements but we don't have an object,
71
+ # then the rest of the path does not exist.
72
+ v = nil
73
+ end
74
+ end
75
+
76
+ if v.nil?
77
+ nil
78
+ else
79
+ self.class.new(origin, {key => v}, v.resolve_status, @ignores_fallbacks)
80
+ end
81
+ end
82
+
83
+ def with_only_path(path)
84
+ o = with_only_path_or_nil(path)
85
+ if o.nil?
86
+ self.class.new(origin, {}, ResolveStatus::RESOLVED, @ignores_fallbacks)
87
+ else
88
+ o
89
+ end
90
+ end
91
+
92
+ def without_path(path)
93
+ key = path.first
94
+ remainder = path.remainder
95
+ v = @value[key]
96
+
97
+ if (not v.nil?) && (not remainder.nil?) && v.is_a?(Hocon::Impl::AbstractConfigObject)
98
+ v = v.without_path(remainder)
99
+ updated = @value.clone
100
+ updated[key] = v
101
+ self.class.new(origin,
102
+ updated,
103
+ ResolveStatus.from_values(updated.values), @ignores_fallbacks)
104
+ elsif (not remainder.nil?) || v.nil?
105
+ return self
106
+ else
107
+ smaller = Hash.new
108
+ @value.each do |old_key, old_value|
109
+ unless old_key == key
110
+ smaller[old_key] = old_value
111
+ end
112
+ end
113
+ self.class.new(origin,
114
+ smaller,
115
+ ResolveStatus.from_values(smaller.values), @ignores_fallbacks)
116
+ end
117
+ end
118
+
119
+ def with_value(path, v)
120
+ key = path.first
121
+ remainder = path.remainder
122
+
123
+ if remainder.nil?
124
+ with_key_value(key, v)
125
+ else
126
+ child = @value[key]
127
+ if (not child.nil?) && child.is_a?(Hocon::Impl::AbstractConfigObject)
128
+ return with_key_value(key, child.with_value(remainder, v))
129
+ else
130
+ subtree = v.at_path_with_origin(
131
+ SimpleConfigOrigin.new_simple("with_value(#{remainder.render})"), remainder)
132
+ with_key_value(key, subtree.root)
133
+ end
134
+ end
135
+ end
136
+
137
+ def with_key_value(key, v)
138
+ if v.nil?
139
+ raise ConfigBugOrBrokenError.new("Trying to store null ConfigValue in a ConfigObject")
140
+ end
141
+
142
+ new_map = Hash.new
143
+ if @value.empty?
144
+ new_map[key] = v
145
+ else
146
+ new_map = @value.clone
147
+ new_map[key] = v
148
+ end
149
+ self.class.new(origin, new_map, ResolveStatus.from_values(new_map.values), @ignores_fallbacks)
150
+ end
151
+
152
+ def attempt_peek_with_partial_resolve(key)
153
+ @value[key]
154
+ end
38
155
 
39
156
  def new_copy_with_status(new_status, new_origin, new_ignores_fallbacks = nil)
40
- Hocon::Impl::SimpleConfigObject.new(new_origin,
41
- @value, new_status, new_ignores_fallbacks)
157
+ self.class.new(new_origin, @value, new_status, new_ignores_fallbacks)
158
+ end
159
+
160
+ def with_fallbacks_ignored()
161
+ if @ignores_fallbacks
162
+ self
163
+ else
164
+ new_copy_with_status(resolve_status, origin, true)
165
+ end
166
+ end
167
+
168
+ def resolve_status
169
+ ResolveStatus.from_boolean(@resolved)
170
+ end
171
+
172
+ def replace_child(child, replacement)
173
+ new_children = @value.clone
174
+ new_children.each do |old, old_value|
175
+ if old_value.equal?(child)
176
+ if replacement != nil
177
+ new_children[old] = replacement
178
+ else
179
+ new_children.delete(old)
180
+ end
181
+
182
+ return self.class.new(origin, new_children, ResolveStatus.from_values(new_children.values),
183
+ @ignores_fallbacks)
184
+ end
185
+ end
186
+ raise ConfigBugOrBrokenError, "SimpleConfigObject.replaceChild did not find #{child} in #{self}"
187
+ end
188
+
189
+ def has_descendant?(descendant)
190
+ value.values.each do |child|
191
+ if child.equal?(descendant)
192
+ return true
193
+ end
194
+ end
195
+ # now do the expensive search
196
+ value.values.each do |child|
197
+ if child.is_a?(Hocon::Impl::Container) && child.has_descendant?(descendant)
198
+ return true
199
+ end
200
+ end
201
+
202
+ false
42
203
  end
43
204
 
44
205
  def ignores_fallbacks?
@@ -46,14 +207,18 @@ class Hocon::Impl::SimpleConfigObject < Hocon::Impl::AbstractConfigObject
46
207
  end
47
208
 
48
209
  def unwrapped
49
- @value.merge(@value) { |k,v| v.unwrapped }
210
+ m = {}
211
+ @value.each do |k,v|
212
+ m[k] = v.unwrapped
213
+ end
214
+ m
50
215
  end
51
216
 
52
217
  def merged_with_object(abstract_fallback)
53
218
  require_not_ignoring_fallbacks
54
219
 
55
220
  unless abstract_fallback.is_a?(Hocon::Impl::SimpleConfigObject)
56
- raise ConfigBugError, "should not be reached (merging non-SimpleConfigObject)"
221
+ raise ConfigBugOrBrokenError, "should not be reached (merging non-SimpleConfigObject)"
57
222
  end
58
223
 
59
224
  fallback = abstract_fallback
@@ -87,46 +252,204 @@ class Hocon::Impl::SimpleConfigObject < Hocon::Impl::AbstractConfigObject
87
252
  new_ignores_fallbacks = fallback.ignores_fallbacks?
88
253
 
89
254
  if changed
90
- Hocon::Impl::SimpleConfigObject.new(merge_origins([self, fallback]),
91
- merged, new_resolve_status,
92
- new_ignores_fallbacks)
255
+ Hocon::Impl::SimpleConfigObject.new(Hocon::Impl::AbstractConfigObject.merge_origins([self, fallback]),
256
+ merged, new_resolve_status,
257
+ new_ignores_fallbacks)
93
258
  elsif (new_resolve_status != resolve_status) || (new_ignores_fallbacks != ignores_fallbacks?)
94
- newCopy(new_resolve_status, origin, new_ignores_fallbacks)
259
+ new_copy_with_status(new_resolve_status, origin, new_ignores_fallbacks)
95
260
  else
96
261
  self
97
262
  end
98
263
  end
99
264
 
100
- def render_value_to_sb(sb, indent_size, at_root, options)
265
+ def modify(modifier)
266
+ begin
267
+ modify_may_throw(modifier)
268
+ rescue Hocon::ConfigError => e
269
+ raise e
270
+ end
271
+ end
272
+
273
+ def modify_may_throw(modifier)
274
+ changes = nil
275
+ keys.each do |k|
276
+ v = value[k]
277
+ # "modified" may be null, which means remove the child;
278
+ # to do that we put null in the "changes" map.
279
+ modified = modifier.modify_child_may_throw(k, v)
280
+ if ! modified.equal?(v)
281
+ if changes.nil?
282
+ changes = {}
283
+ end
284
+ changes[k] = modified
285
+ end
286
+ end
287
+ if changes.nil?
288
+ self
289
+ else
290
+ modified = {}
291
+ saw_unresolved = false
292
+ keys.each do |k|
293
+ if changes.has_key?(k)
294
+ new_value = changes[k]
295
+ if ! new_value.nil?
296
+ modified[k] = new_value
297
+ if new_value.resolve_status == ResolveStatus::UNRESOLVED
298
+ saw_unresolved = true
299
+ end
300
+ else
301
+ # remove this child; don't put it in the new map
302
+ end
303
+ else
304
+ new_value = value[k]
305
+ modified[k] = new_value
306
+ if new_value.resolve_status == ResolveStatus::UNRESOLVED
307
+ saw_unresolved = true
308
+ end
309
+ end
310
+ end
311
+ self.class.new(origin, modified,
312
+ saw_unresolved ? ResolveStatus::UNRESOLVED : ResolveStatus::RESOLVED,
313
+ @ignores_fallbacks)
314
+ end
315
+ end
316
+
317
+
318
+ class ResolveModifier
319
+
320
+ attr_accessor :context
321
+ attr_reader :source
322
+
323
+ def initialize(context, source)
324
+ @context = context
325
+ @source = source
326
+ @original_restrict = context.restrict_to_child
327
+ end
328
+
329
+ def modify_child_may_throw(key, v)
330
+ if @context.is_restricted_to_child
331
+ if key == @context.restrict_to_child.first
332
+ remainder = @context.restrict_to_child.remainder
333
+ if remainder != nil
334
+ result = @context.restrict(remainder).resolve(v, @source)
335
+ @context = result.context.unrestricted.restrict(@original_restrict)
336
+ return result.value
337
+ else
338
+ # we don't want to resolve the leaf child
339
+ return v
340
+ end
341
+ else
342
+ # not in the restrictToChild path
343
+ return v
344
+ end
345
+ else
346
+ # no restrictToChild, resolve everything
347
+ result = @context.unrestricted.resolve(v, @source)
348
+ @context = result.context.unrestricted.restrict(@original_restrict)
349
+ result.value
350
+ end
351
+ end
352
+ end
353
+
354
+ def resolve_substitutions(context, source)
355
+ if resolve_status == ResolveStatus::RESOLVED
356
+ return ResolveResult.make(context, self)
357
+ end
358
+
359
+ source_with_parent = source.push_parent(self)
360
+
361
+ begin
362
+ modifier = ResolveModifier.new(context, source_with_parent)
363
+
364
+ value = modify_may_throw(modifier)
365
+ ResolveResult.make(modifier.context, value)
366
+
367
+ rescue NotPossibleToResolve => e
368
+ raise e
369
+ rescue Hocon::ConfigError => e
370
+ raise e
371
+ end
372
+ end
373
+
374
+ def relativized(prefix)
375
+
376
+ modifier = Class.new do
377
+ include Hocon::Impl::AbstractConfigValue::NoExceptionsModifier
378
+
379
+ # prefix isn't in scope inside of a def, but it is in scope inside of Class.new
380
+ # so manually define a method that has access to prefix
381
+ # I feel dirty
382
+ define_method(:modify_child) do |key, v|
383
+ v.relativized(prefix)
384
+ end
385
+ end
386
+
387
+ modify(modifier.new)
388
+ end
389
+
390
+ class RenderComparator
391
+ def self.all_digits?(s)
392
+ s =~ /^\d+$/
393
+ end
394
+
395
+ # This is supposed to sort numbers before strings,
396
+ # and sort the numbers numerically. The point is
397
+ # to make objects which are really list-like
398
+ # (numeric indices) appear in order.
399
+ def self.sort(arr)
400
+ arr.sort do |a, b|
401
+ a_digits = all_digits?(a)
402
+ b_digits = all_digits?(b)
403
+ if a_digits && b_digits
404
+ Integer(a) <=> Integer(b)
405
+ elsif a_digits
406
+ -1
407
+ elsif b_digits
408
+ 1
409
+ else
410
+ a <=> b
411
+ end
412
+ end
413
+ end
414
+ end
415
+
416
+ def render_value_to_sb(sb, indent, at_root, options)
101
417
  if empty?
102
418
  sb << "{}"
103
419
  else
104
420
  outer_braces = options.json? || !at_root
105
421
 
106
- inner_indent =
107
- if outer_braces
108
- sb << "{"
109
- if options.formatted?
110
- sb << "\n"
111
- end
112
- indent_size + 1
113
- else
114
- indent_size
422
+ if outer_braces
423
+ inner_indent = indent + 1
424
+ sb << "{"
425
+
426
+ if options.formatted?
427
+ sb << "\n"
115
428
  end
429
+ else
430
+ inner_indent = indent
431
+ end
116
432
 
117
433
  separator_count = 0
118
- key_set.each do |k|
434
+ sorted_keys = RenderComparator.sort(keys)
435
+ sorted_keys.each do |k|
119
436
  v = @value[k]
120
437
 
121
438
  if options.origin_comments?
122
- indent(sb, inner_indent, options)
123
- sb << "# "
124
- sb << v.origin.description
125
- sb << "\n"
439
+ lines = v.origin.description.split("\n")
440
+ lines.each { |l|
441
+ Hocon::Impl::AbstractConfigValue.indent(sb, indent + 1, options)
442
+ sb << '#'
443
+ unless l.empty?
444
+ sb << ' '
445
+ end
446
+ sb << l
447
+ sb << "\n"
448
+ }
126
449
  end
127
450
  if options.comments?
128
451
  v.origin.comments.each do |comment|
129
- indent(sb, inner_indent, options)
452
+ Hocon::Impl::AbstractConfigValue.indent(sb, inner_indent, options)
130
453
  sb << "#"
131
454
  if !comment.start_with?(" ")
132
455
  sb << " "
@@ -135,7 +458,7 @@ class Hocon::Impl::SimpleConfigObject < Hocon::Impl::AbstractConfigObject
135
458
  sb << "\n"
136
459
  end
137
460
  end
138
- indent(sb, inner_indent, options)
461
+ Hocon::Impl::AbstractConfigValue.indent(sb, inner_indent, options)
139
462
  v.render_to_sb(sb, inner_indent, false, k.to_s, options)
140
463
 
141
464
  if options.formatted?
@@ -161,7 +484,7 @@ class Hocon::Impl::SimpleConfigObject < Hocon::Impl::AbstractConfigObject
161
484
  if options.formatted?
162
485
  sb << "\n" # put a newline back
163
486
  if outer_braces
164
- indent(sb, indent_size, options)
487
+ Hocon::Impl::AbstractConfigValue.indent(sb, indent, options)
165
488
  end
166
489
  end
167
490
  sb << "}"
@@ -172,74 +495,87 @@ class Hocon::Impl::SimpleConfigObject < Hocon::Impl::AbstractConfigObject
172
495
  end
173
496
  end
174
497
 
498
+ def self.map_equals(a, b)
499
+ if a.equal?(b)
500
+ return true
501
+ end
175
502
 
176
- def key_set
177
- Set.new(@value.keys)
178
- end
503
+ # Hashes aren't ordered in ruby, so sort first
504
+ if not a.keys.sort == b.keys.sort
505
+ return false
506
+ end
507
+
508
+ a.keys.each do |key|
509
+ if a[key] != b[key]
510
+ return false
511
+ end
512
+ end
179
513
 
180
- def empty?
181
- @value.empty?
514
+ true
182
515
  end
183
516
 
184
- def attempt_peek_with_partial_resolve(key)
517
+ def get(key)
185
518
  @value[key]
186
519
  end
187
520
 
188
- def without_path(path)
189
- key = path.first
190
- remainder = path.remainder
191
- v = @value[key]
521
+ def self.map_hash(m)
522
+ # the keys have to be sorted, otherwise we could be equal
523
+ # to another map but have a different hashcode.
524
+ keys = m.keys.sort
192
525
 
193
- if (not v.nil?) && (not remainder.nil?) && v.is_a?(Hocon::Impl::AbstractConfigObject)
194
- v = v.without_path(remainder)
195
- updated = @value.clone
196
- updated[key] = v
197
- return Hocon::Impl::SimpleConfigObject.new(origin, updated,
198
- ResolveStatus.from_values(updated.values), @ignores_fallbacks)
199
- elsif (not remainder.nil?) || v.nil?
200
- return self
201
- else
202
- smaller = Hash.new
203
- @value.each do |old_key, old_value|
204
- if not old_key == key
205
- smaller[old_key] = old_value
206
- end
207
- end
208
- return Hocon::Impl::SimpleConfigObject.new(origin, smaller,
209
- ResolveStatus.from_values(smaller.values), @ignores_fallbacks)
526
+ value_hash = 0
527
+
528
+ keys.each do |key|
529
+ value_hash += m[key].hash
210
530
  end
531
+
532
+ 41 * (41 + keys.hash) + value_hash
211
533
  end
212
534
 
213
- def with_value(path, v)
214
- key = path.first
215
- remainder = path.remainder
535
+ def can_equal(other)
536
+ other.is_a? Hocon::ConfigObject
537
+ end
216
538
 
217
- if remainder.nil?
218
- return with_value_impl(key, v)
539
+ def ==(other)
540
+ # note that "origin" is deliberately NOT part of equality.
541
+ # neither are other "extras" like ignoresFallbacks or resolve status.
542
+ if other.is_a? Hocon::ConfigObject
543
+ # optimization to avoid unwrapped() for two ConfigObject,
544
+ # which is what AbstractConfigValue does.
545
+ can_equal(other) && self.class.map_equals(self, other)
219
546
  else
220
- child = @value[key]
221
- if (not child.nil?) && child.is_a?(Hocon::Impl::AbstractConfigObject)
222
- return with_value_impl(key, child.with_value(remainder, v))
223
- else
224
- subtree = v.at_path(
225
- SimpleConfigOrigin.new_simple("with_value(#{remainder.render})"), remainder)
226
- with_value_impl(key, subtree.root)
227
- end
547
+ false
228
548
  end
229
549
  end
230
550
 
231
- def with_value_impl(key, v)
232
- if v.nil?
233
- raise ConfigBugOrBrokenError.new("Trying to store null ConfigValue in a ConfigObject", nil)
234
- end
551
+ def hash
552
+ self.class.map_hash(@value)
553
+ end
235
554
 
236
- new_map = Hash.new
237
- if @value.empty?
238
- new_map[key] = v
555
+ def contains_key?(key)
556
+ @value.has_key?(key)
557
+ end
558
+
559
+ def key_set
560
+ Set.new(@value.keys)
561
+ end
562
+
563
+ def contains_value?(v)
564
+ @value.has_value?(v)
565
+ end
566
+
567
+ def self.empty(origin = nil)
568
+ if origin.nil?
569
+ empty(Hocon::Impl::SimpleConfigOrigin.new_simple("empty config"))
239
570
  else
240
- new_map = @value.clone
241
- new_map[key] = v
571
+ self.new(origin, {})
242
572
  end
243
- self.class.new(origin, new_map, ResolveStatus.from_values(new_map.values), @ignores_fallbacks)
244
573
  end
245
- end
574
+
575
+ def self.empty_missing(base_origin)
576
+ self.new(
577
+ Hocon::Impl::SimpleConfigOrigin.new_simple("#{base_origin.description} (not found)"),
578
+ {})
579
+ end
580
+ end
581
+