Module: Hocon::Impl::AbstractConfigValue

Overview

Trying very hard to avoid a parent reference in config values; when you have a tree like this, the availability of parent() tends to result in a lot of improperly-factored and non-modular code. Please don’t add parent().

Defined Under Namespace

Modules: NoExceptionsModifier Classes: NotPossibleToResolve

Constant Summary collapse

ConfigImplUtil =
Hocon::Impl::ConfigImplUtil
ConfigBugOrBrokenError =
Hocon::ConfigError::ConfigBugOrBrokenError
ResolveStatus =
Hocon::Impl::ResolveStatus

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ConfigValue

#unwrapped, #value_type

Instance Attribute Details

#originObject (readonly)

Returns the value of attribute origin.



30
31
32
# File 'lib/hocon/impl/abstract_config_value.rb', line 30

def origin
  @origin
end

Class Method Details

.has_descendant_in_list?(list, descendant) ⇒ Boolean

Returns:

  • (Boolean)


89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/hocon/impl/abstract_config_value.rb', line 89

def self.has_descendant_in_list?(list, descendant)
  list.each do |v|
    if v.equal?(descendant)
      return true
    end
  end
  # now the expensive traversal
  list.each do |v|
    if v.is_a?(Hocon::Impl::Container) && v.has_descendant?(descendant)
      return true
    end
  end
  false
end

.indent(sb, indent_size, options) ⇒ Object



294
295
296
297
298
299
300
301
302
# File 'lib/hocon/impl/abstract_config_value.rb', line 294

def self.indent(sb, indent_size, options)
  if options.formatted?
    remaining = indent_size
    while remaining > 0
      sb << "    "
      remaining -= 1
    end
  end
end

.replace_child_in_list(list, child, replacement) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/hocon/impl/abstract_config_value.rb', line 66

def self.replace_child_in_list(list, child, replacement)
  i = 0
  while (i < list.size) && (! list[i].equal?(child))
    i += 1
  end
  if (i == list.size)
    raise ConfigBugOrBrokenError, "tried to replace #{child} which is not in #{list}"
  end

  new_stack = list.clone
  if ! replacement.nil?
    new_stack[i] = replacement
  else
    new_stack.delete(i)
  end

  if new_stack.empty?
    nil
  else
    new_stack
  end
end

Instance Method Details

#==(other) ⇒ Object



263
264
265
266
267
268
269
270
271
272
# File 'lib/hocon/impl/abstract_config_value.rb', line 263

def ==(other)
  # note that "origin" is deliberately NOT part of equality
  if other.is_a?(Hocon::Impl::AbstractConfigValue)
    can_equal(other) &&
        value_type == other.value_type &&
        ConfigImplUtil.equals_handling_nil?(unwrapped, other.unwrapped)
  else
    false
  end
end

#at_key(key) ⇒ Object



359
360
361
# File 'lib/hocon/impl/abstract_config_value.rb', line 359

def at_key(key)
  at_key_with_origin(Hocon::Impl::SimpleConfigOrigin.new_simple("at_key(#{key})"), key)
end

#at_key_with_origin(origin, key) ⇒ Object

Renamed this to be consistent with the other at_key* overloaded methods



364
365
366
367
# File 'lib/hocon/impl/abstract_config_value.rb', line 364

def at_key_with_origin(origin, key)
  m = {key=>self}
  Hocon::Impl::SimpleConfigObject.new(origin, m).to_config
end

#at_path(path_expression) ⇒ Object



381
382
383
384
# File 'lib/hocon/impl/abstract_config_value.rb', line 381

def at_path(path_expression)
  origin = Hocon::Impl::SimpleConfigOrigin.new_simple("at_path(#{path_expression})")
  at_path_with_origin(origin, Hocon::Impl::Path.new_path(path_expression))
end

#at_path_with_origin(origin, path) ⇒ Object

In java this is an overloaded version of atPath



370
371
372
373
374
375
376
377
378
379
# File 'lib/hocon/impl/abstract_config_value.rb', line 370

def at_path_with_origin(origin, path)
  parent = path.parent
  result = at_key_with_origin(origin, path.last)
  while not parent.nil? do
    key = parent.last
    result = result.at_key_with_origin(origin, key)
    parent = parent.parent
  end
  result
end

#can_equal(other) ⇒ Object



259
260
261
# File 'lib/hocon/impl/abstract_config_value.rb', line 259

def can_equal(other)
  other.is_a?(Hocon::Impl::AbstractConfigValue)
end

#construct_delayed_merge(origin, stack) ⇒ Object



161
162
163
164
165
166
# File 'lib/hocon/impl/abstract_config_value.rb', line 161

def construct_delayed_merge(origin, stack)
  # TODO: this might not work because ConfigDelayedMerge inherits
  # from this class, so we can't `require` it from this file
  require 'hocon/impl/config_delayed_merge'
  Hocon::Impl::ConfigDelayedMerge.new(origin, stack)
end

#delay_merge(stack, fallback) ⇒ Object



180
181
182
183
184
185
186
187
188
189
190
# File 'lib/hocon/impl/abstract_config_value.rb', line 180

def delay_merge(stack, fallback)
  # if we turn out to be an object, and the fallback also does,
  # then a merge may be required.
  # if we contain a substitution, resolving it may need to look
  # back to the fallback
  new_stack = stack.clone
  new_stack << fallback
  # TODO: this might not work because AbstractConfigObject inherits
  # from this class, so we can't `require` it from this file
  construct_delayed_merge(Hocon::Impl::AbstractConfigObject.merge_origins(new_stack), new_stack)
end

#hashObject



274
275
276
277
278
279
280
281
282
# File 'lib/hocon/impl/abstract_config_value.rb', line 274

def hash
  # note that "origin" is deliberately NOT part of equality
  unwrapped_value = unwrapped
  if unwrapped_value.nil?
    0
  else
    unwrapped_value.hash
  end
end

#ignores_fallbacks?Boolean

this is virtualized rather than a field because only some subclasses really need to store the boolean, and they may be able to pack it with another boolean to save space.

Returns:

  • (Boolean)


139
140
141
142
143
# File 'lib/hocon/impl/abstract_config_value.rb', line 139

def ignores_fallbacks?
  # if we are not resolved, then somewhere in this value there's
  # a substitution that may need to look at the fallbacks.
  resolve_status == Hocon::Impl::ResolveStatus::RESOLVED
end

#initialize(origin) ⇒ Object



26
27
28
# File 'lib/hocon/impl/abstract_config_value.rb', line 26

def initialize(origin)
  @origin = origin
end

#inspectObject



290
291
292
# File 'lib/hocon/impl/abstract_config_value.rb', line 290

def inspect
  to_s
end

#merged_stack_with_non_object(stack, fallback) ⇒ Object



204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/hocon/impl/abstract_config_value.rb', line 204

def merged_stack_with_non_object(stack, fallback)
  require_not_ignoring_fallbacks

  if resolve_status == ResolveStatus::RESOLVED
    # falling back to a non-object doesn't merge anything, and also
    # prohibits merging any objects that we fall back to later.
    # so we have to switch to ignoresFallbacks mode.
    with_fallbacks_ignored
  else
    # if unresolved we may have to look back to fallbacks as part of
    # the resolution process, so always delay
    delay_merge(stack, fallback)
  end
end

#merged_stack_with_object(stack, fallback) ⇒ Object



192
193
194
195
196
197
198
199
200
201
202
# File 'lib/hocon/impl/abstract_config_value.rb', line 192

def merged_stack_with_object(stack, fallback)
  require_not_ignoring_fallbacks

  # TODO: this might not work because AbstractConfigObject inherits
  # from this class, so we can't `require` it from this file
  if self.is_a?(Hocon::Impl::AbstractConfigObject)
    raise ConfigBugOrBrokenError, "Objects must reimplement merged_with_object"
  end

  merged_stack_with_non_object(stack, fallback)
end

#merged_stack_with_the_unmergeable(stack, fallback) ⇒ Object



168
169
170
171
172
173
174
175
176
177
178
# File 'lib/hocon/impl/abstract_config_value.rb', line 168

def merged_stack_with_the_unmergeable(stack, fallback)
  require_not_ignoring_fallbacks

  # if we turn out to be an object, and the fallback also does,
  # then a merge may be required; delay until we resolve.
  new_stack = stack.clone
  new_stack.concat(fallback.unmerged_values)
  # TODO: this might not work because AbstractConfigObject inherits
  # from this class, so we can't `require` it from this file
  construct_delayed_merge(Hocon::Impl::AbstractConfigObject.merge_origins(new_stack), new_stack)
end

#merged_with_non_object(fallback) ⇒ Object



229
230
231
232
# File 'lib/hocon/impl/abstract_config_value.rb', line 229

def merged_with_non_object(fallback)
  require_not_ignoring_fallbacks
  merged_stack_with_non_object([self], fallback)
end

#merged_with_object(fallback) ⇒ Object



224
225
226
227
# File 'lib/hocon/impl/abstract_config_value.rb', line 224

def merged_with_object(fallback)
  require_not_ignoring_fallbacks
  merged_stack_with_object([self], fallback)
end

#merged_with_the_unmergeable(fallback) ⇒ Object



219
220
221
222
# File 'lib/hocon/impl/abstract_config_value.rb', line 219

def merged_with_the_unmergeable(fallback)
  require_not_ignoring_fallbacks
  merged_stack_with_the_unmergeable([self], fallback)
end

#new_copy(origin) ⇒ Object



132
133
134
# File 'lib/hocon/impl/abstract_config_value.rb', line 132

def new_copy(origin)
  raise ConfigBugOrBrokenError, "subclasses of AbstractConfigValue should provide their own implementation of `new_copy` (#{self.class})"
end

#relativized(prefix) ⇒ Object

This is used when including one file in another; the included file is relativized to the path it’s included into in the parent file. The point is that if you include a file at foo.bar in the parent, and the included file as a substitution $Hocon::Impl::AbstractConfigValue.aa.ba.b.c, the included substitution now needs to be $Hocon::Impl::AbstractConfigValue.foofoo.barfoo.bar.afoo.bar.a.bfoo.bar.a.b.c because we resolve substitutions globally only after parsing everything.

Parameters:

  • prefix

Returns:

  • value relativized to the given path or the same value if nothing to do



114
115
116
# File 'lib/hocon/impl/abstract_config_value.rb', line 114

def relativized(prefix)
  self
end

#render(options = Hocon::ConfigRenderOptions.defaults) ⇒ Object



341
342
343
344
345
346
347
348
# File 'lib/hocon/impl/abstract_config_value.rb', line 341

def render(options = Hocon::ConfigRenderOptions.defaults)
  sb = StringIO.new
  render_to_sb(sb, 0, true, nil, options)
  # We take a substring that ends at sb.pos, because we've been decrementing
  # sb.pos at various points in the code as a means to remove characters from
  # the end of the StringIO
  sb.string[0, sb.pos]
end

#render_to_sb(sb, indent, at_root, at_key, options) ⇒ Object



304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'lib/hocon/impl/abstract_config_value.rb', line 304

def render_to_sb(sb, indent, at_root, at_key, options)
  if !at_key.nil?
    rendered_key =
        if options.json?
          ConfigImplUtil.render_json_string(at_key)
        else
          ConfigImplUtil.render_string_unquoted_if_possible(at_key)
        end

    sb << rendered_key

    if options.json?
      if options.formatted?
        sb << " : "
      else
        sb << ":"
      end
    else
      # in non-JSON we can omit the colon or equals before an object
      if self.is_a?(Hocon::ConfigObject)
        if options.formatted?
          sb << ' '
        end
      else
        sb << "="
      end
    end
  end
  render_value_to_sb(sb, indent, at_root, options)
end

#render_value_to_sb(sb, indent, at_root, options) ⇒ Object

to be overridden by subclasses



336
337
338
339
# File 'lib/hocon/impl/abstract_config_value.rb', line 336

def render_value_to_sb(sb, indent, at_root, options)
  u = unwrapped
  sb << u.to_s
end

#require_not_ignoring_fallbacksObject

the withFallback() implementation is supposed to avoid calling mergedWith* if we’re ignoring fallbacks.



155
156
157
158
159
# File 'lib/hocon/impl/abstract_config_value.rb', line 155

def require_not_ignoring_fallbacks
  if ignores_fallbacks?
    raise ConfigBugOrBrokenError, "method should not have been called with ignoresFallbacks=true #{self.class.name}"
  end
end

#resolve_statusObject



62
63
64
# File 'lib/hocon/impl/abstract_config_value.rb', line 62

def resolve_status
  Hocon::Impl::ResolveStatus::RESOLVED
end

#resolve_substitutions(context, source) ⇒ Object

Called only by ResolveContext.resolve

Parameters:

  • context

    state of the current resolve

  • source

    where to look up values

Returns:

  • a new value if there were changes, or this if no changes



58
59
60
# File 'lib/hocon/impl/abstract_config_value.rb', line 58

def resolve_substitutions(context, source)
  Hocon::Impl::ResolveResult.make(context, self)
end

#to_fallback_valueObject



128
129
130
# File 'lib/hocon/impl/abstract_config_value.rb', line 128

def to_fallback_value
  self
end

#to_sObject



284
285
286
287
288
# File 'lib/hocon/impl/abstract_config_value.rb', line 284

def to_s
  sb = StringIO.new
  render_to_sb(sb, 0, true, nil, Hocon::ConfigRenderOptions.concise)
  "#{self.class.name.split('::').last}(#{sb.string})"
end

#transform_to_stringObject

toString() is a debugging-oriented string but this is defined to create a string that would parse back to the value in JSON. It only works for primitive values (that would be a single which are auto-converted to strings when concatenating with other strings or by the DefaultTransformer.



355
356
357
# File 'lib/hocon/impl/abstract_config_value.rb', line 355

def transform_to_string
  nil
end

#with_fallback(mergeable) ⇒ Object



242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/hocon/impl/abstract_config_value.rb', line 242

def with_fallback(mergeable)
  if ignores_fallbacks?
    self
  else
    other = mergeable.to_fallback_value
    if other.is_a?(Hocon::Impl::Unmergeable)
      merged_with_the_unmergeable(other)
      # TODO: this probably isn't going to work because AbstractConfigObject inherits
      # from this class, so we can't `require` it from this file
    elsif other.is_a?(Hocon::Impl::AbstractConfigObject)
      merged_with_object(other)
    else
      merged_with_non_object(other)
    end
  end
end

#with_fallbacks_ignoredObject



145
146
147
148
149
150
151
# File 'lib/hocon/impl/abstract_config_value.rb', line 145

def with_fallbacks_ignored
  if ignores_fallbacks?
    self
  else
    raise ConfigBugOrBrokenError, "value class doesn't implement forced fallback-ignoring #{self}"
  end
end

#with_origin(origin) ⇒ Object



234
235
236
237
238
239
240
# File 'lib/hocon/impl/abstract_config_value.rb', line 234

def with_origin(origin)
  if @origin.equal?(origin)
    self
  else
    new_copy(origin)
  end
end