class RDoc::Markup::PreProcess - rdoc: Ruby Standard Library Documentation

# class RDoc::Markup::PreProcess

Handle common directives that can occur in a block of text:

    :include: filename

Directives can be escaped by preceding them with a backslash.

`RDoc` plugin authors can register additional directives to be handled by using `RDoc::Markup::PreProcess::register`.

Any directive that is not built-in to `RDoc` (including those registered via plugins) will be stored in the metadata hash on the CodeObject the comment is attached to. See Directives at `RDoc::Markup` for the list of built-in directives.

### Attributes

options[RW]

An `RDoc::Options` instance that will be filled in with overrides from directives

### Public Class Methods

new(input_file_name, include_path) click to toggle source

Creates a new pre-processor for `input_file_name` that will look for included files in `include_path`

    # File rdoc/markup/pre_process.rb, line 78
    def initialize(input_file_name, include_path)
      @input_file_name = input_file_name
      @include_path = include_path
      @options = nil
    end

post_process(&block) click to toggle source

Adds a post-process handler for directives. The handler will be called with the result `RDoc::Comment` (or text String) and the code object for the comment (if any).

    # File rdoc/markup/pre_process.rb, line 30
    def self.post_process &block
      @post_processors << block
    end

post_processors() click to toggle source

Registered post-processors

    # File rdoc/markup/pre_process.rb, line 37
    def self.post_processors
      @post_processors
    end

register(directive, &block) click to toggle source

Registers `directive` as one handled by `RDoc`. If a block is given the directive will be replaced by the result of the block, otherwise the directive will be removed from the processed text.

The block will be called with the directive name and the directive parameter:

    RDoc::Markup::PreProcess.register 'my-directive' do |directive, param|
      # replace text, etc.
    end

    # File rdoc/markup/pre_process.rb, line 53
    def self.register directive, &block
      @registered[directive] = block
    end

registered() click to toggle source

Registered directives

    # File rdoc/markup/pre_process.rb, line 60
    def self.registered
      @registered
    end

reset() click to toggle source

Clears all registered directives and post-processors

    # File rdoc/markup/pre_process.rb, line 67
    def self.reset
      @post_processors = []
      @registered = {}
    end

### Public Instance Methods

find_include_file(name) click to toggle source

Look for the given file in the directory containing the current file, and then in each of the directories specified in the RDOC_INCLUDE path

    # File rdoc/markup/pre_process.rb, line 308
    def find_include_file(name)
      to_search = [File.dirname(@input_file_name)].concat @include_path
      to_search.each do |dir|
        full_name = File.join(dir, name)
        stat = File.stat(full_name) rescue next
        return full_name if stat.readable?
      end
      nil
    end

handle(text, code_object = nil, &block) click to toggle source

Look for directives in the given `text`.

Options that we don’t handle are yielded. If the block returns false the directive is restored to the text. If the block returns nil or no block was given the directive is handled according to the registered directives. If a String was returned the directive is replaced with the string.

If no matching directive was registered the directive is restored to the text.

If `code_object` is given and the directive is unknown then the directive’s parameter is set as metadata on the `code_object`. See `RDoc::CodeObject#metadata` for details.

    # File rdoc/markup/pre_process.rb, line 99
    def handle text, code_object = nil, &block
      first_line = 1
      if RDoc::Comment === text then
        comment = text
        text = text.text
        first_line = comment.line || 1
      end

      # regexp helper (square brackets for optional)
      # $1      $2  $3        $4      $5
      # [prefix][\]:directive:[spaces][param]newline
      text = text.lines.map.with_index(first_line) do |line, num|
        next line unless line =~ /\A([ \t]*(?:#|\/?\*)?[ \t]*)(\\?):([\w-]+):([ \t]*)(.+)?(\r?\n|$)/
        # skip something like ':toto::'
        next $& if $4.empty? and $5 and $5[0, 1] == ':'

        # skip if escaped
        next "#$1:#$3:#$4#$5\n" unless $2.empty?

        # This is not in handle_directive because I didn't want to pass another
        # argument into it
        if comment and $3 == 'markup' then
          next "#{$1.strip}\n" unless $5
          comment.format = $5.downcase
          next "#{$1.strip}\n"
        end

        handle_directive $1, $3, $5, code_object, text.encoding, num, &block
      end.join

      if comment then
        comment.text = text
      else
        comment = text
      end

      self.class.post_processors.each do |handler|
        handler.call comment, code_object
      end

      text
    end

handle_directive(prefix, directive, param, code_object = nil, encoding = nil, line = nil) { |directive, param, line| ... } click to toggle source

Performs the actions described by `directive` and its parameter `param`.

`code_object` is used for directives that operate on a class or module. `prefix` is used to ensure the replacement for handled directives is correct. `encoding` is used for the `include` directive.

For a list of directives in `RDoc` see `RDoc::Markup`.

    # File rdoc/markup/pre_process.rb, line 153
      def handle_directive prefix, directive, param, code_object = nil,
                           encoding = nil, line = nil
        blankline = "#{prefix.strip}\n"
        directive = directive.downcase

        case directive
        when 'arg', 'args' then
          return "#{prefix}:#{directive}: #{param}\n" unless code_object && code_object.kind_of?(RDoc::AnyMethod)

          code_object.params = param

          blankline
        when 'category' then
          if RDoc::Context === code_object then
            section = code_object.add_section param
            code_object.temporary_section = section
          elsif RDoc::AnyMethod === code_object then
            code_object.section_title = param
          end

          blankline # ignore category if we're not on an RDoc::Context
        when 'doc' then
          return blankline unless code_object
          code_object.document_self = true
          code_object.force_documentation = true

          blankline
        when 'enddoc' then
          return blankline unless code_object
          code_object.done_documenting = true

          blankline
        when 'include' then
          filename = param.split(' ', 2).first
          include_file filename, prefix, encoding
        when 'main' then
          @options.main_page = param if @options.respond_to? :main_page
          warn <<~MSG
            The :main: directive is deprecated and will be removed in RDoc 7.

            You can use these options to specify the initial page displayed instead:
            - `--main=#{param}` via the command line
            - `rdoc.main = "#{param}"` if you use `RDoc::Task`
            - `main_page: #{param}` in your `.rdoc_options` file
          MSG

          blankline
        when 'nodoc' then
          return blankline unless code_object
          code_object.document_self = nil # notify nodoc
          code_object.document_children = param !~ /all/i

          blankline
        when 'notnew', 'not_new', 'not-new' then
          return blankline unless RDoc::AnyMethod === code_object

          code_object.dont_rename_initialize = true

          blankline
        when 'startdoc' then
          return blankline unless code_object

          code_object.start_doc
          code_object.force_documentation = true

          blankline
        when 'stopdoc' then
          return blankline unless code_object

          code_object.stop_doc

          blankline
        when 'title' then
          @options.default_title = param if @options.respond_to? :default_title=

          warn <<~MSG
            The :title: directive is deprecated and will be removed in RDoc 7.

            You can use these options to specify the title displayed instead:
            - `--title=#{param}` via the command line
            - `rdoc.title = "#{param}"` if you use `RDoc::Task`
            - `title: #{param}` in your `.rdoc_options` file
          MSG

          blankline
        when 'yield', 'yields' then
          return blankline unless code_object
          # remove parameter &block
          code_object.params = code_object.params.sub(/,?\s*&\w+/, '') if code_object.params

          code_object.block_params = param || ''

          blankline
        else
          result = yield directive, param, line if block_given?

          case result
          when nil then
            code_object.metadata[directive] = param if code_object

            if RDoc::Markup::PreProcess.registered.include? directive then
              handler = RDoc::Markup::PreProcess.registered[directive]
              result = handler.call directive, param if handler
            else
              result = "#{prefix}:#{directive}: #{param}\n"
            end
          when false then
            result = "#{prefix}:#{directive}: #{param}\n"
          end

          result
        end
      end

include_file(name, indent, encoding) click to toggle source

Handles the `:include: filename` directive.

If the first line of the included file starts with ‘#’, and contains an encoding information in the form ‘coding:’ or ‘coding=’, it is removed.

If all lines in the included file start with a ‘#’, this leading ‘#’ is removed before inclusion. The included content is indented like the `:include:` directive.

    # File rdoc/markup/pre_process.rb, line 282
    def include_file name, indent, encoding
      full_name = find_include_file name

      unless full_name then
        warn "Couldn't find file to include '#{name}' from #{@input_file_name}"
        return ''
      end

      content = RDoc::Encoding.read_file full_name, encoding, true
      content = RDoc::Encoding.remove_magic_comment content

      # strip magic comment
      content = content.sub(/\A# .*coding[=:].*$/, '').lstrip

      # strip leading '#'s, but only if all lines start with them
      if content =~ /^[^#]/ then
        content.gsub(/^/, indent)
      else
        content.gsub(/^#?/, indent)
      end
    end