class Hocon::Impl::Parseable

Internal implementation detail, not ABI stable, do not touch. For use only by the {@link com.typesafe.config} package. The point of this class is to avoid “propagating” each overload on “thing which can be parsed” through multiple interfaces. Most interfaces can have just one overload that takes a Parseable. Also it's used as an abstract “resource handle” in the ConfigIncluder interface.

Constants

MAX_INCLUDE_DEPTH

Public Class Methods

force_parsed_to_object(value) click to toggle source
# File lib/hocon/impl/parseable.rb, line 122
def self.force_parsed_to_object(value)
  if value.is_a? Hocon::Impl::AbstractConfigObject
    value
  else
    raise Hocon::ConfigError::ConfigWrongTypeError.with_expected_actual(value.origin,
                                                       "",
                                                       "object at file root",
                                                       Hocon::ConfigValueType.value_type_name(value.value_type))
  end
end
new() click to toggle source
# File lib/hocon/impl/parseable.rb, line 45
def initialize

end
new_file(file_path, options) click to toggle source
# File lib/hocon/impl/parseable.rb, line 464
def self.new_file(file_path, options)
  ParseableFile.new(file_path, options)
end
new_not_found(what_not_found, message, options) click to toggle source
# File lib/hocon/impl/parseable.rb, line 348
def self.new_not_found(what_not_found, message, options)
  ParseableNotFound.new(what_not_found, message, options)
end
new_resources(resource, options) click to toggle source
# File lib/hocon/impl/parseable.rb, line 544
def self.new_resources(resource, options)
  ParseableResources.new(resource, options)
end
new_string(string, options) click to toggle source
# File lib/hocon/impl/parseable.rb, line 390
def self.new_string(string, options)
  ParseableString.new(string, options)
end
parse_stack() click to toggle source

The upstream library seems to use this as a global way of keeping track of how many files have been included, to avoid cycles

# File lib/hocon/impl/parseable.rb, line 39
def self.parse_stack
  Thread.current[:hocon_parse_stack] ||= []
end
relative_to(file, filename) click to toggle source

NOTE: skipping `relativeTo(URL, String)` because we're not supporting URLs for now

# File lib/hocon/impl/parseable.rb, line 313
def self.relative_to(file, filename)
  child = Pathname.new(filename)
  file = Pathname.new(file)

  if child.absolute?
    nil
  end

  parent = file.parent

  if parent.nil?
    nil
  else
    File.join(parent, filename)
  end
end
syntax_from_extension(name) click to toggle source
# File lib/hocon/impl/parseable.rb, line 299
def self.syntax_from_extension(name)
  if name.end_with?(".json")
    Hocon::ConfigSyntax::JSON
  elsif name.end_with?(".conf")
    Hocon::ConfigSyntax::CONF
  else
    # Skipping PROPERTIES because we can't really support that in ruby
    nil
  end
end
trace(message) click to toggle source
# File lib/hocon/impl/parseable.rb, line 92
def self.trace(message)
  if Hocon::Impl::ConfigImpl.trace_loads_enabled
    Hocon::Impl::ConfigImpl.trace(message)
  end
end

Public Instance Methods

content_type() click to toggle source
# File lib/hocon/impl/parseable.rb, line 102
def content_type
  nil
end
create_origin() click to toggle source
# File lib/hocon/impl/parseable.rb, line 287
def create_origin
  raise Hocon::ConfigError::ConfigBugOrBrokenError, "subclasses of `Parseable` must implement `create_origin` (#{self.class})"
end
custom_reader() click to toggle source
the general idea is that any work should be in here, not in the
constructor, so that exceptions are thrown from the public parse()
function and not from the creation of the Parseable.
Essentially this is a lazy field. The parser should close the
reader when it's done with it.

{//}# ALSO, IMPORTANT: if the file or URL is not found, this must throw. {//}# to support the “allow missing” feature.

# File lib/hocon/impl/parseable.rb, line 84
def custom_reader
  raise Hocon::ConfigError::ConfigBugOrBrokenError, "subclasses of `Parseable` must implement `custom_reader` (#{self.class})"
end
fixup_options(base_options) click to toggle source
# File lib/hocon/impl/parseable.rb, line 49
def fixup_options(base_options)
  syntax = base_options.syntax
  if !syntax
    syntax = guess_syntax
  end
  if !syntax
    syntax = Hocon::ConfigSyntax::CONF
  end
  modified = base_options.set_syntax(syntax)

  # make sure the app-provided includer falls back to default
  modified = modified.append_includer(Hocon::Impl::ConfigImpl.default_includer)
  # make sure the app-provided includer is complete
  modified = modified.set_includer(Hocon::Impl::SimpleIncluder.make_full(modified.includer))

  modified
end
guess_syntax() click to toggle source
# File lib/hocon/impl/parseable.rb, line 98
def guess_syntax
  nil
end
include_context() click to toggle source
# File lib/hocon/impl/parseable.rb, line 118
def include_context
  @include_context
end
options() click to toggle source
# File lib/hocon/impl/parseable.rb, line 291
def options
  @initial_options
end
origin() click to toggle source
# File lib/hocon/impl/parseable.rb, line 283
def origin
  @initial_origin
end
parse(base_options = nil) click to toggle source
# File lib/hocon/impl/parseable.rb, line 133
def parse(base_options = nil)
  if (base_options.nil?)
    base_options = options
  end
  stack = self.class.parse_stack
  if stack.length >= MAX_INCLUDE_DEPTH
    raise Hocon::ConfigError::ConfigParseError.new(@initial_origin,
          "include statements nested more than #{MAX_INCLUDE_DEPTH} times, " +
          "you probably have a cycle in your includes.  Trace: #{stack}",
          nil)
  end

  # Push into beginning of stack
  stack.unshift(self)
  begin
    self.class.force_parsed_to_object(parse_value(base_options))
  ensure
    # Pop from beginning of stack
    stack.shift
  end
end
parse_config_document() click to toggle source
# File lib/hocon/impl/parseable.rb, line 279
def parse_config_document
  parse_document(options)
end
parse_document(base_options = nil) click to toggle source
# File lib/hocon/impl/parseable.rb, line 189
def parse_document(base_options = nil)
  if base_options.nil?
    base_options = options
  end

  # note that we are NOT using our "initialOptions",
  # but using the ones from the passed-in options. The idea is that
  # callers can get our original options and then parse with different
  # ones if they want.
  options = fixup_options(base_options)

  # passed-in option can override origin
  origin = nil
  if ! options.origin_description.nil?
    origin = Hocon::Impl::SimpleConfigOrigin.new_simple(options.origin_description)
  else
    origin = @initial_origin
  end
  parse_document_from_origin(origin, options)
end
parse_document_from_origin(origin, final_options) click to toggle source
# File lib/hocon/impl/parseable.rb, line 210
def parse_document_from_origin(origin, final_options)
  begin
    raw_parse_document(origin, final_options)
  rescue IOError => e
    if final_options.allow_missing?
      Hocon::Impl::SimpleConfigDocument.new(
        Hocon::Impl::ConfigNodeObject.new([]), final_options)
    else
      self.class.trace("exception loading #{origin.description}: #{e.class}: #{e.message}")
      raise ConfigIOError.new(origin, "#{e.class.name}: #{e.message}", e)
    end
  end
end
parse_value(base_options = nil) click to toggle source
# File lib/hocon/impl/parseable.rb, line 155
def parse_value(base_options = nil)
  if base_options.nil?
    base_options = options
  end

  # note that we are NOT using our "initialOptions",
  # but using the ones from the passed-in options. The idea is that
  # callers can get our original options and then parse with different
  # ones if they want.
  options = fixup_options(base_options)

  # passed-in options can override origin
  origin =
      if options.origin_description
        Hocon::Impl::SimpleConfigOrigin.new_simple(options.origin_description)
      else
        @initial_origin
      end
  parse_value_from_origin(origin, options)
end
parse_value_from_origin(origin, final_options) click to toggle source
# File lib/hocon/impl/parseable.rb, line 176
def parse_value_from_origin(origin, final_options)
  begin
    raw_parse_value(origin, final_options)
  rescue IOError => e
    if final_options.allow_missing?
      Hocon::Impl::SimpleConfigObject.empty_missing(origin)
    else
      self.class.trace("exception loading #{origin.description}: #{e.class}: #{e.message}")
      raise Hocon::ConfigError::ConfigIOError.new(origin, "#{e.class.name}: #{e.message}", e)
    end
  end
end
post_construct(base_options) click to toggle source
# File lib/hocon/impl/parseable.rb, line 67
def post_construct(base_options)
  @initial_options = fixup_options(base_options)
  @include_context = Hocon::Impl::SimpleIncludeContext.new(self)
  if @initial_options.origin_description
    @initial_origin = Hocon::Impl::SimpleConfigOrigin.new_simple(@initial_options.origin_description)
  else
    @initial_origin = create_origin
  end
end
raw_parse_document(origin, final_options) click to toggle source
# File lib/hocon/impl/parseable.rb, line 253
def raw_parse_document(origin, final_options)
  reader = reader(final_options)
  content_type = content_type()

  options_with_content_type = nil
  if !(content_type.nil?)
    if Hocon::Impl::ConfigImpl.trace_loads_enabled && (! final_options.get_syntax.nil?)
      self.class.trace("Overriding syntax #{final_options.get_syntax} with Content-Type which specified #{content-type}")
    end
    options_with_content_type = final_options.set_syntax(content_type)
  else
    options_with_content_type = final_options
  end

  reader.open { |io|
    raw_parse_document_from_io(io, origin, options_with_content_type)
  }
end
raw_parse_document_from_io(reader, origin, final_options) click to toggle source
# File lib/hocon/impl/parseable.rb, line 272
def raw_parse_document_from_io(reader, origin, final_options)
  tokens = Hocon::Impl::Tokenizer.tokenize(origin, reader, final_options.syntax)
  Hocon::Impl::SimpleConfigDocument.new(
                 Hocon::Impl::ConfigDocumentParser.parse(tokens, origin, final_options),
                 final_options)
end
raw_parse_value(origin, final_options) click to toggle source

this is parseValue without post-processing the IOException or handling options.getAllowMissing()

# File lib/hocon/impl/parseable.rb, line 226
def raw_parse_value(origin, final_options)
  reader = reader(final_options)

  # after reader() we will have loaded the Content-Type
  content_type = content_type()

  options_with_content_type = nil
  if !(content_type.nil?)
    if Hocon::Impl::ConfigImpl.trace_loads_enabled && (! final_options.get_syntax.nil?)
      self.class.trace("Overriding syntax #{final_options.get_syntax} with Content-Type which specified #{content-type}")
    end
    options_with_content_type = final_options.set_syntax(content_type)
  else
    options_with_content_type = final_options
  end

  reader.open { |io|
    raw_parse_value_from_io(io, origin, options_with_content_type)
  }
end
raw_parse_value_from_io(io, origin, final_options) click to toggle source
# File lib/hocon/impl/parseable.rb, line 247
def raw_parse_value_from_io(io, origin, final_options)
  tokens = Hocon::Impl::Tokenizer.tokenize(origin, io, final_options.syntax)
  document = Hocon::Impl::ConfigDocumentParser.parse(tokens, origin, final_options)
  Hocon::Impl::ConfigParser.parse(document, origin, final_options, include_context)
end
reader(options) click to toggle source
# File lib/hocon/impl/parseable.rb, line 88
def reader(options)
  custom_reader
end
relative_to(filename) click to toggle source
# File lib/hocon/impl/parseable.rb, line 106
def relative_to(filename)
  # fall back to classpath; we treat the "filename" as absolute
  # (don't add a package name in front),
  # if it starts with "/" then remove the "/", for consistency
  # with ParseableResources.relativeTo
  resource = filename
  if filename.start_with?("/")
    resource = filename.slice(1)
  end
  self.class.new_resources(resource, options.set_origin_description(nil))
end
to_s() click to toggle source
# File lib/hocon/impl/parseable.rb, line 295
def to_s
  self.class.name.split('::').last
end