class Hocon::Impl::ResolveSource

Constants

ConfigBugOrBrokenError
ConfigNotResolvedError

Attributes

path_from_root[RW]

'path_from_root' is used for knowing the chain of parents we used to get here. null if we should assume we are not a descendant of the root. the root itself should be a node in this if non-null.

root[RW]

'path_from_root' is used for knowing the chain of parents we used to get here. null if we should assume we are not a descendant of the root. the root itself should be a node in this if non-null.

Public Class Methods

new(root, path_from_root = nil) click to toggle source
# File lib/hocon/impl/resolve_source.rb, line 19
def initialize(root, path_from_root = nil)
  @root = root
  @path_from_root = path_from_root
end

Private Class Methods

find_in_object_impl(obj, path, parents = nil) click to toggle source
# File lib/hocon/impl/resolve_source.rb, line 290
def self.find_in_object_impl(obj, path, parents = nil)
  begin
    # we 'll fail if anything along the path can' t
    # be looked at without resolving.
    find_in_object_impl_impl(obj, path, nil)
  rescue ConfigNotResolvedError => e
    raise Hocon::Impl::ConfigImpl.improve_not_resolved(path, e)
  end
end
find_in_object_impl_impl(obj, path, parents) click to toggle source
# File lib/hocon/impl/resolve_source.rb, line 300
def self.find_in_object_impl_impl(obj, path, parents)
  key = path.first
  remainder = path.remainder
  if Hocon::Impl::ConfigImpl.trace_substitution_enabled
    Hocon::Impl::ConfigImpl.trace("*** looking up '#{key}' in #{obj}")
  end
  v = obj.attempt_peek_with_partial_resolve(key)
  new_parents = parents == nil ? Node.new(obj) : parents.prepend(obj)

  if remainder == nil
    ValueWithPath.new(v, new_parents)
  else
    if v.is_a?(Hocon::Impl::AbstractConfigObject)
      find_in_object_impl_impl(v, remainder, new_parents)
    else
      ValueWithPath.new(nil, new_parents)
    end
  end
end
replace(list, old, replacement) click to toggle source

returns null if the replacement results in deleting all the nodes.

# File lib/hocon/impl/resolve_source.rb, line 321
def self.replace(list, old, replacement)
  child = list.head
  unless child.equal?(old)
    raise ConfigBugOrBrokenError.new("Can only replace() the top node we're resolving; had " + child +
                                         " on top and tried to replace " + old + " overall list was " + list)
  end
  parent = list.tail == nil ? nil : list.tail.head
  if replacement == nil || !replacement.is_a?(Hocon::Impl::Container)
    if parent == nil
      return nil
    else
      # we are deleting the child from the stack of containers
      # because it's either going away or not a container
      new_parent = parent.replace_child(old, nil)

      return replace(list.tail, parent, new_parent)
    end
  else
    # we replaced the container with another container
    if parent == nil
      return Node.new(replacement)
    else
      new_parent = parent.replace_child(old, replacement)
      new_tail = replace(list.tail, parent, new_parent)
      if new_tail != nil
        return new_tail.prepend(replacement)
      else
        return Node.new(replacement)
      end
    end
  end
end

Public Instance Methods

find_in_object(obj, context, path) click to toggle source

as a side effect, findInObject() will have to resolve all parents of the child being peeked, but NOT the child itself.Caller has to resolve the child itself if Hocon::Impl::ResolveSource::ValueWithPath#value can be null but the ValueWithPath instance itself should not be.

# File lib/hocon/impl/resolve_source.rb, line 28
def find_in_object(obj, context, path)
  # resolve ONLY portions of the object which are along our path
  if Hocon::Impl::ConfigImpl.trace_substitution_enabled
    Hocon::Impl::ConfigImpl.trace("*** finding '#{path}' in #{obj}")
  end
  restriction = context.restrict_to_child
  partially_resolved = context.restrict(path).resolve(obj, self.class.new(obj))
  new_context = partially_resolved.context.restrict(restriction)
  if partially_resolved.value.is_a?(Hocon::Impl::AbstractConfigObject)
    pair = self.class.find_in_object_impl(partially_resolved.value, path)
    ResultWithPath.new(Hocon::Impl::ResolveResult.make(new_context, pair.value), pair.path_from_root)
  else
    raise ConfigBugOrBrokenError.new("resolved object to non-object " + obj + " to " + partially_resolved)
  end
end
lookup_subst(context, subst, prefix_length) click to toggle source
# File lib/hocon/impl/resolve_source.rb, line 44
def lookup_subst(context, subst, prefix_length)
  if Hocon::Impl::ConfigImpl.trace_substitution_enabled
    Hocon::Impl::ConfigImpl.trace("searching for #{subst}", context.depth)
  end

  if Hocon::Impl::ConfigImpl.trace_substitution_enabled
    Hocon::Impl::ConfigImpl.trace("#{subst} - looking up relative to file it occurred in",
                                  context.depth)
  end
  # First we look up the full path, which means relative to the
  # included file if we were not a root file
  result = find_in_object(@root, context, subst.path)

  if result.result.value == nil
    # Then we want to check relative to the root file.We don 't
    # want the prefix we were included at to be used when looking
    # up env variables either.
    unprefixed = subst.path.sub_path_to_end(prefix_length)

    if prefix_length > 0
      if Hocon::Impl::ConfigImpl.trace_substitution_enabled
        Hocon::Impl::ConfigImpl.trace(
            unprefixed + " - looking up relative to parent file",
            result.result.context.depth)
      end
      result = find_in_object(@root, result.result.context, unprefixed)
    end

    if result.result.value == nil && result.result.context.options.use_system_environment
      if Hocon::Impl::ConfigImpl.trace_substitution_enabled
        Hocon::Impl::ConfigImpl.trace(
            "#{unprefixed} - looking up in system environment",
            result.result.context.depth)
      end
      result = find_in_object(Hocon::Impl::ConfigImpl.env_variables_as_config_object, context, unprefixed)
    end
  end

  if Hocon::Impl::ConfigImpl.trace_substitution_enabled
    Hocon::Impl::ConfigImpl.trace(
        "resolved to #{result}",
        result.result.context.depth)
  end

  result
end
push_parent(parent) click to toggle source
# File lib/hocon/impl/resolve_source.rb, line 91
def push_parent(parent)
  unless parent
    raise ConfigBugOrBrokenError.new("can't push null parent")
  end

  if Hocon::Impl::ConfigImpl.trace_substitution_enabled
    Hocon::Impl::ConfigImpl.trace("pushing parent #{parent} ==root #{(parent == root)} onto #{self}")
  end

  if @path_from_root == nil
    if parent.equal?(@root)
      return self.class.new(@root, Node.new(parent))
    else
      if Hocon::Impl::ConfigImpl.trace_substitution_enabled
        # this hasDescendant check is super-expensive so it's a
        # trace message rather than an assertion
        if @root.has_descendant?(parent)
          Hocon::Impl::ConfigImpl.trace(
              "***** BUG ***** tried to push parent #{parent} without having a path to it in #{self}")
        end
      end
      # ignore parents if we aren't proceeding from the
      # root
      return self
    end
  else
    parent_parent = @path_from_root.head
    if Hocon::Impl::ConfigImpl.trace_substitution_enabled
      # this hasDescendant check is super-expensive so it's a
      # trace message rather than an assertion
      if parent_parent != nil && !parent_parent.has_descendant?(parent)
        Hocon::Impl::ConfigImpl.trace(
            "***** BUG ***** trying to push non-child of #{parent_parent}, non-child was #{parent}")
      end
    end

    self.class.new(@root, @path_from_root.prepend(parent))
  end
end
replace_current_parent(old, replacement) click to toggle source
# File lib/hocon/impl/resolve_source.rb, line 139
def replace_current_parent(old, replacement)
  if Hocon::Impl::ConfigImpl.trace_substitution_enabled
    Hocon::Impl::ConfigImpl.trace("replaceCurrentParent old #{old}@#{old.hash} replacement " +
                                      "#{replacement}@#{old.hash} in #{self}")
  end
  if old.equal?(replacement)
    self
  elsif @path_from_root != nil
    new_path = self.class.replace(@path_from_root, old, replacement)
    if Hocon::Impl::ConfigImpl.trace_substitution_enabled
      Hocon::Impl::ConfigImpl.trace("replaced #{old} with #{replacement} in #{self}")
      Hocon::Impl::ConfigImpl.trace("path was: #{@path_from_root} is now #{new_path}")
    end
    # if we end up nuking the root object itself, we replace it with an
    # empty root
    if new_path != nil
      return self.class.new(new_path.last, new_path)
    else
      return self.class.new(Hocon::Impl::SimpleConfigObject.empty)
    end
  else
    if old.equal?(@root)
      return self.class.new(root_must_be_obj(replacement))
    else
      raise ConfigBugOrBrokenError.new("attempt to replace root #{root} with #{replacement}")
    end
  end
end
replace_within_current_parent(old, replacement) click to toggle source

replacement may be null to delete

# File lib/hocon/impl/resolve_source.rb, line 169
def replace_within_current_parent(old, replacement)
  if Hocon::Impl::ConfigImpl.trace_substitution_enabled
    Hocon::Impl::ConfigImpl.trace("replaceWithinCurrentParent old #{old}@#{old.hash}" +
                                      " replacement #{replacement}@#{old.hash} in #{self}")
  end
  if old.equal?(replacement)
    self
  elsif @path_from_root != nil
    parent = @path_from_root.head
    new_parent = parent.replace_child(old, replacement)
    return replace_current_parent(parent, new_parent.is_a?(Hocon::Impl::Container) ? new_parent : nil)
  else
    if old.equal?(@root) && replacement.is_a?(Hocon::Impl::Container)
      return self.class.new(root_must_be_obj(replacement))
    else
      raise ConfigBugOrBrokenError.new("replace in parent not possible #{old} with #{replacement}" +
                                           " in #{self}")
    end
  end
end
reset_parents() click to toggle source
# File lib/hocon/impl/resolve_source.rb, line 131
def reset_parents
  if @path_from_root == nil
    this
  else
    self.class.new(@root)
  end
end
to_s() click to toggle source
# File lib/hocon/impl/resolve_source.rb, line 190
def to_s
  "ResolveSource(root=#{@root}, pathFromRoot=#{@path_from_root})"
end

Private Instance Methods

root_must_be_obj(value) click to toggle source
# File lib/hocon/impl/resolve_source.rb, line 282
def root_must_be_obj(value)
  if value.is_a?(Hocon::Impl::AbstractConfigObject)
    value
  else
    Hocon::Impl::SimpleConfigObject.empty
  end
end