class Asciidoctor::PreprocessorReader
def preprocess_include raw_target, raw_attributes
target slot of the include::[] macro
target - The name of the source document to include as specified in the
If none of the above apply, emit the include directive line verbatim.
of the Array of source data.
stack size, normalize the target path and read the lines onto the beginning
Otherwise, if the max depth is greater than 0, and is not exceeded by the
attributes to that processor and expect an Array of String lines in return.
Otherwise, if an include processor is specified pass the target and
directive line is emitted verbatim.
If SafeMode is SECURE or greater, the directive is ignore and the include
are as follows:
Preprocess the directive to include the target document. The scenarios
Internal: Preprocess the directive (macro) to include the target document.
def preprocess_include raw_target, raw_attributes if (target = @document.sub_attributes raw_target, :attribute_missing => 'drop-line').empty? if @document.attributes.fetch('attribute-missing', Compliance.attribute_missing) == 'skip' replace_line %(Unresolved directive in #{@path} - include::#{raw_target}[#{raw_attributes}]) true else advance true end # assume that if an include processor is given, the developer wants # to handle when and how to process the include elsif include_processors? && (extension = @include_processor_extensions.find {|candidate| candidate.instance.handles? target }) advance # FIXME parse attributes if requested by extension extension.process_method[@document, self, target, AttributeList.new(raw_attributes).parse] true # if running in SafeMode::SECURE or greater, don't process this directive # however, be friendly and at least make it a link to the source document elsif @document.safe >= SafeMode::SECURE # FIXME we don't want to use a link macro if we are in a verbatim context replace_line %(link:#{target}[]) true elsif (abs_maxdepth = @maxdepth[:abs]) > 0 && @include_stack.size >= abs_maxdepth warn %(asciidoctor: ERROR: #{line_info}: maximum include depth of #{@maxdepth[:rel]} exceeded) false elsif abs_maxdepth > 0 if ::RUBY_ENGINE_OPAL # NOTE resolves uri relative to currently loaded document # NOTE we defer checking if file exists and catch the 404 error if it does not # TODO only use this logic if env-browser is set target_type = :file include_file = path = if @include_stack.empty? ::Dir.pwd == @document.base_dir ? target : (::File.join @dir, target) else ::File.join @dir, target end elsif target.include?(':') && UriSniffRx =~ target unless @document.attributes.has_key? 'allow-uri-read' replace_line %(link:#{target}[]) return true end target_type = :uri include_file = path = target if @document.attributes.has_key? 'cache-uri' # caching requires the open-uri-cached gem to be installed # processing will be automatically aborted if these libraries can't be opened Helpers.require_library 'open-uri/cached', 'open-uri-cached' elsif !::RUBY_ENGINE_OPAL # autoload open-uri ::OpenURI end else target_type = :file # include file is resolved relative to dir of current include, or base_dir if within original docfile include_file = @document.normalize_system_path(target, @dir, nil, :target_name => 'include file') unless ::File.file? include_file warn "asciidoctor: WARNING: #{line_info}: include file not found: #{include_file}" replace_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}]) return true end #path = @document.relative_path include_file path = PathResolver.new.relative_path include_file, @document.base_dir end inc_lines = nil tags = nil attributes = {} if !raw_attributes.empty? # QUESTION should we use @document.parse_attribues? attributes = AttributeList.new(raw_attributes).parse if attributes.has_key? 'lines' inc_lines = [] attributes['lines'].split(DataDelimiterRx).each do |linedef| if linedef.include?('..') from, to = linedef.split('..').map(&:to_i) if to == -1 inc_lines << from inc_lines << 1.0/0.0 else inc_lines.concat ::Range.new(from, to).to_a end else inc_lines << linedef.to_i end end inc_lines = inc_lines.sort.uniq elsif attributes.has_key? 'tag' tags = [attributes['tag']].to_set elsif attributes.has_key? 'tags' tags = attributes['tags'].split(DataDelimiterRx).uniq.to_set end end if !inc_lines.nil? if !inc_lines.empty? selected = [] inc_line_offset = 0 inc_lineno = 0 begin open(include_file, 'r') do |f| f.each_line do |l| inc_lineno += 1 take = inc_lines[0] if take.is_a?(::Float) && take.infinite? selected.push l inc_line_offset = inc_lineno if inc_line_offset == 0 else if f.lineno == take selected.push l inc_line_offset = inc_lineno if inc_line_offset == 0 inc_lines.shift end break if inc_lines.empty? end end end rescue warn %(asciidoctor: WARNING: #{line_info}: include #{target_type} not readable: #{include_file}) replace_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}]) return true end advance # FIXME not accounting for skipped lines in reader line numbering push_include selected, include_file, path, inc_line_offset, attributes end elsif !tags.nil? if !tags.empty? selected = [] inc_line_offset = 0 inc_lineno = 0 active_tag = nil tags_found = ::Set.new begin open(include_file, 'r') do |f| f.each_line do |l| inc_lineno += 1 # must force encoding here since we're performing String operations on line l.force_encoding(::Encoding::UTF_8) if FORCE_ENCODING l = l.rstrip if active_tag if l.end_with?(%(end::#{active_tag}[])) && TagDirectiveRx =~ l active_tag = nil else selected.push l unless l.end_with?('[]') && TagDirectiveRx =~ l inc_line_offset = inc_lineno if inc_line_offset == 0 end else tags.each do |tag| if l.end_with?(%(tag::#{tag}[])) && TagDirectiveRx =~ l active_tag = tag tags_found << tag break end end end end end rescue warn %(asciidoctor: WARNING: #{line_info}: include #{target_type} not readable: #{include_file}) replace_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}]) return true end unless (missing_tags = tags.to_a - tags_found.to_a).empty? warn "asciidoctor: WARNING: #{line_info}: tag#{missing_tags.size > 1 ? 's' : nil} '#{missing_tags * ','}' not found in include #{target_type}: #{include_file}" end advance # FIXME not accounting for skipped lines in reader line numbering push_include selected, include_file, path, inc_line_offset, attributes end else begin advance push_include open(include_file, 'r') {|f| f.read }, include_file, path, 1, attributes rescue warn %(asciidoctor: WARNING: #{line_info}: include #{target_type} not readable: #{include_file}) replace_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}]) return true end end true else false end end