class MarkdownIncluder

Constants

INCLUDE_MARKDOWN_REGEXP
INCLUDE_REGEXP

Public Class Methods

backtrace_inclusions(inclusions) click to toggle source
# File lib/markdown_helper/markdown_includer.rb, line 277
def self.backtrace_inclusions(inclusions)
  lines = ['  Backtrace (innermost include first):']
  inclusions.reverse.each_with_index do |inclusion, i|
    lines.push("#{'    Level'} #{i}:")
    level_lines = inclusion.to_lines(indentation_level = 3)
    lines.push(*level_lines)
  end
  lines.join("\n")
end
details(text) click to toggle source
# File lib/markdown_helper/markdown_includer.rb, line 23
def MarkdownIncluder.details(text)
  "<details>\n#{text}</details>"
end
pre(text) click to toggle source
# File lib/markdown_helper/markdown_includer.rb, line 19
def MarkdownIncluder.pre(text)
  "<pre>\n#{text}</pre>"
end

Public Instance Methods

add_inclusion_comments(treatment, includee_file_path, lines) click to toggle source
# File lib/markdown_helper/markdown_includer.rb, line 193
def add_inclusion_comments(treatment, includee_file_path, lines)
  unless pristine
    path_in_project = MarkdownHelper.path_in_project(includee_file_path)
    treatment = treatment.sub(/^:/, '')
    comment = format(' >>>>>> BEGIN INCLUDED FILE (%s): SOURCE %s ', treatment, path_in_project)
    lines.unshift(MarkdownHelper.comment(comment))
    comment = format(' <<<<<< END INCLUDED FILE (%s): SOURCE %s ', treatment, path_in_project)
    lines.push(MarkdownHelper.comment(comment))
  end
end
check_circularity(inclusion) click to toggle source
# File lib/markdown_helper/markdown_includer.rb, line 248
def check_circularity(inclusion)
  included_file_paths = @inclusions.collect { |x| x.includee_real_file_path}
  previously_included = included_file_paths.include?(inclusion.includee_real_file_path)
  if previously_included
    @inclusions.push(inclusion)
    message = [
        'Includes are circular:',
        MarkdownIncluder.backtrace_inclusions(@inclusions),
    ].join("\n")
    e = CircularIncludeError.new(message)
    e.set_backtrace([])
    raise e
  end
end
check_includee(inclusion) click to toggle source
# File lib/markdown_helper/markdown_includer.rb, line 263
def check_includee(inclusion)
  unless File.readable?(inclusion.includee_absolute_file_path)
    @inclusions.push(inclusion)
    message = [
        'Could not read includee file:',
        MarkdownIncluder.backtrace_inclusions(@inclusions),
    ].join("\n")
    e = UnreadableIncludeeError.new(message)
    e.set_backtrace([])
    raise e
  end

end
check_template(template_file_path) click to toggle source
# File lib/markdown_helper/markdown_includer.rb, line 180
def check_template(template_file_path)
  unless File.readable?(template_file_path)
    path_in_project = MarkdownHelper.path_in_project(template_file_path)
    message = [
      "Could not read template file: #{path_in_project}",
      MarkdownIncluder.backtrace_inclusions(@inclusions),
    ].join("\n")
    e = UnreadableTemplateError.new(message)
    e.set_backtrace([])
    raise e
  end
end
gather_markdown(template_file_path) click to toggle source
# File lib/markdown_helper/markdown_includer.rb, line 27
def gather_markdown(template_file_path)
  template_dir_path = File.dirname(template_file_path)
  template_file_name = File.basename(template_file_path)
  Dir.chdir(template_dir_path) do
    check_template(template_file_name)
    markdown_lines = []
    template_lines = File.readlines(template_file_path)
    template_lines.each_with_index do |template_line, i|
      template_line.chomp!
      treatment, includee_file_path = *parse_include(template_line)
      unless treatment == ':markdown'
        markdown_lines.push(template_line)
        next
      end
      inclusion = Inclusion.new(
          includer_file_path: template_file_path,
          include_pragma: template_line,
          includer_line_number: i,
          treatment: treatment,
          cited_includee_file_path: includee_file_path,
          inclusions: @inclusions
      )
      check_includee(inclusion)
      check_circularity(inclusion)
      @inclusions.push(inclusion)
      includee_lines = gather_markdown(File.absolute_path(includee_file_path))
      markdown_lines.concat(includee_lines)
      @inclusions.pop
      add_inclusion_comments(treatment, includee_file_path, markdown_lines)
    end
    markdown_lines
  end
end
get_page_toc_lines(template_file_path) click to toggle source
# File lib/markdown_helper/markdown_includer.rb, line 61
def get_page_toc_lines(template_file_path)
  markdown_lines = gather_markdown(template_file_path)
  toc_line_index = nil
  toc_title = nil
  anchor_counts = Hash.new(0)
  markdown_lines.each_with_index do |markdown_line, i|
    match_data = markdown_line.match(INCLUDE_REGEXP)
    next unless match_data
    treatment = match_data[1]
    next unless treatment == ':page_toc'
    unless toc_line_index.nil?
      message = 'Multiple page TOC not allowed'
      raise MultiplePageTocError.new(message)
    end
    toc_line_index = i
    toc_title = match_data[2]
    title_regexp = /^\#{1,6}\s/
    unless toc_title.match(title_regexp)
      message = "TOC title must be a valid markdown header, not #{toc_title}"
      raise InvalidTocTitleError.new(message)
    end
  end
  return markdown_lines unless toc_line_index
  toc_lines = [toc_title]
  first_heading_level = nil
  markdown_lines.each_with_index do |input_line, i|
    line = input_line.chomp
    heading = Heading.parse(line)
    next unless heading
    if i < toc_line_index
      heading.link(anchor_counts)
      next
    end
    first_heading_level ||= heading.level
    indentation = '  ' * (heading.level - first_heading_level)
    toc_line = "#{indentation}- #{heading.link(anchor_counts)}"
    toc_lines.push(toc_line)
  end
  toc_lines
end
include(template_file_path, markdown_file_path) click to toggle source
# File lib/markdown_helper/markdown_includer.rb, line 8
def include(template_file_path, markdown_file_path)
  @inclusions = []
  generate_file(:include, template_file_path, markdown_file_path) do |output_lines|
    Dir.chdir(File.dirname(template_file_path)) do
      page_toc_lines = get_page_toc_lines(template_file_path)
      include_all(template_file_path, page_toc_lines, is_nested = false, output_lines)
    end
  end

end
include_all(includer_file_path, page_toc_lines, is_nested, output_lines) click to toggle source
# File lib/markdown_helper/markdown_includer.rb, line 102
def include_all(includer_file_path, page_toc_lines, is_nested, output_lines)
  includer_dir_path = File.dirname(includer_file_path)
  includer_file_name = File.basename(includer_file_path)
  absolute_includer_file_path = File.absolute_path(includer_file_path)
  Dir.chdir(includer_dir_path) do
    check_template(includer_file_name)
    template_lines = File.readlines(includer_file_name)
    if is_nested
      add_inclusion_comments(':markdown', includer_file_path, template_lines)
    end
    template_lines.each_with_index do |template_line, i|
      treatment, includee_file_path = *parse_include(template_line)
      if treatment.nil?
        output_lines.push(template_line)
        next
      end
      if treatment == ':page_toc'
        output_lines.concat(page_toc_lines)
        next
      end
      inclusion = Inclusion.new(
          includer_file_path: absolute_includer_file_path,
          include_pragma: template_line,
          includer_line_number: i,
          treatment: treatment,
          cited_includee_file_path: includee_file_path,
          inclusions: @inclusions
      )
      @inclusions.push(inclusion)
      check_includee(inclusion)
      case treatment
      when ':comment'
        include_comment(includee_file_path, treatment, inclusion, output_lines)
      when ':pre'
        include_pre(includee_file_path, treatment, inclusion, output_lines)
      when ':details'
        include_details(includee_file_path, treatment, inclusion, output_lines)
      when ':markdown'
        include_all(includee_file_path, page_toc_lines, is_nested = true, output_lines)
      else
        include_file(includee_file_path, treatment, inclusion, output_lines)
      end
      @inclusions.pop
    end
  end
end
include_comment(includee_file_path, treatment, inclusion, output_lines) click to toggle source
# File lib/markdown_helper/markdown_includer.rb, line 149
def include_comment(includee_file_path, treatment, inclusion, output_lines)
  text = File.read(includee_file_path)
  output_lines.push(MarkdownHelper.comment(text))
  add_inclusion_comments(treatment, includee_file_path, output_lines)
end
include_details(includee_file_path, treatment, inclusion, output_lines) click to toggle source
# File lib/markdown_helper/markdown_includer.rb, line 161
def include_details(includee_file_path, treatment, inclusion, output_lines)
  text = File.read(includee_file_path)
  output_lines.push(MarkdownIncluder.details(text))
  add_inclusion_comments(treatment, includee_file_path, output_lines)
end
include_file(includee_file_path, treatment, inclusion, output_lines) click to toggle source
# File lib/markdown_helper/markdown_includer.rb, line 167
def include_file(includee_file_path, treatment, inclusion, output_lines)
  file_marker = format('```%s```:', File.basename(includee_file_path))
  begin_backticks = '```'
  end_backticks = '```'
  begin_backticks += treatment unless treatment.start_with?(':')
  includee_lines = File.read(includee_file_path).split("\n")
  includee_lines.unshift(begin_backticks)
  includee_lines.unshift(file_marker)
  includee_lines.push(end_backticks)
  add_inclusion_comments(treatment, includee_file_path, includee_lines)
  output_lines.concat(includee_lines)
end
include_pre(includee_file_path, treatment, inclusion, output_lines) click to toggle source
# File lib/markdown_helper/markdown_includer.rb, line 155
def include_pre(includee_file_path, treatment, inclusion, output_lines)
  text = File.read(includee_file_path)
  output_lines.push(MarkdownIncluder.pre(text))
  add_inclusion_comments(treatment, includee_file_path, output_lines)
end
parse_include(line) click to toggle source
# File lib/markdown_helper/markdown_includer.rb, line 204
def parse_include(line)
  match_data = line.match(INCLUDE_REGEXP)
  return [nil, nil] unless match_data
  treatment = match_data[1]
  includee_file_path = match_data[2]
  [treatment, includee_file_path]
end