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
Source
# File lib/hocon/impl/parseable.rb, line 123 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
Source
# File lib/hocon/impl/parseable.rb, line 465 def self.new_file(file_path, options) ParseableFile.new(file_path, options) end
Source
# File lib/hocon/impl/parseable.rb, line 349 def self.new_not_found(what_not_found, message, options) ParseableNotFound.new(what_not_found, message, options) end
Source
# File lib/hocon/impl/parseable.rb, line 545 def self.new_resources(resource, options) ParseableResources.new(resource, options) end
Source
# File lib/hocon/impl/parseable.rb, line 391 def self.new_string(string, options) ParseableString.new(string, options) end
Source
# File lib/hocon/impl/parseable.rb, line 40 def self.parse_stack Thread.current[:hocon_parse_stack] ||= [] end
The upstream library seems to use this as a global way of keeping track of how many files have been included, to avoid cycles
Source
# File lib/hocon/impl/parseable.rb, line 314 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
NOTE: skipping ‘relativeTo(URL, String)` because we’re not supporting URLs for now
Source
# File lib/hocon/impl/parseable.rb, line 300 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
Source
# File lib/hocon/impl/parseable.rb, line 93 def self.trace(message) if Hocon::Impl::ConfigImpl.trace_loads_enabled Hocon::Impl::ConfigImpl.trace(message) end end
Public Instance Methods
Source
# File lib/hocon/impl/parseable.rb, line 288 def create_origin raise Hocon::ConfigError::ConfigBugOrBrokenError, "subclasses of `Parseable` must implement `create_origin` (#{self.class})" end
Source
# File lib/hocon/impl/parseable.rb, line 85 def custom_reader raise Hocon::ConfigError::ConfigBugOrBrokenError, "subclasses of `Parseable` must implement `custom_reader` (#{self.class})" end
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.
Source
# File lib/hocon/impl/parseable.rb, line 50 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
Source
# File lib/hocon/impl/parseable.rb, line 119 def include_context @include_context end
Source
# File lib/hocon/impl/parseable.rb, line 134 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
Source
# File lib/hocon/impl/parseable.rb, line 280 def parse_config_document parse_document(options) end
Source
# File lib/hocon/impl/parseable.rb, line 190 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
Source
# File lib/hocon/impl/parseable.rb, line 211 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
Source
# File lib/hocon/impl/parseable.rb, line 156 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
Source
# File lib/hocon/impl/parseable.rb, line 177 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
Source
# File lib/hocon/impl/parseable.rb, line 68 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
Source
# File lib/hocon/impl/parseable.rb, line 254 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
Source
# File lib/hocon/impl/parseable.rb, line 273 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
Source
# File lib/hocon/impl/parseable.rb, line 227 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
this is parseValue without post-processing the IOException or handling options.getAllowMissing()
Source
# File lib/hocon/impl/parseable.rb, line 248 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
Source
# File lib/hocon/impl/parseable.rb, line 89 def reader(options) custom_reader end
Source
# File lib/hocon/impl/parseable.rb, line 107 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
Source
# File lib/hocon/impl/parseable.rb, line 296 def to_s self.class.name.split('::').last end