Class: YARD::Readme::DocstringParser

Inherits:
Object
  • Object
show all
Defined in:
lib/yard/readme/docstring_parser.rb

Overview

This custom DocstringParser extends YARD's default parser to provide special handling for @readme tags. The main functionality includes:

  1. Preserving the text content of @readme tags in the docstring (instead of moving it to a separate "readme" section)
  2. Supporting nested @readme tags with custom names (like @readme comment)
  3. Properly handling empty/blank @readme tags

This implementation allows source code comments to signal README dependencies without altering how the YARD documentation is organized and displayed.

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Attribute Details

.readme_tag_namesObject

Custom readme tag names that should be stripped from the docstring but preserved in the tag's text. This is used to support the nested tag feature of readme_yard, where tags like @readme comment, @readme code, and @readme source control what content gets embedded in the README.

By setting this attribute with an array of tag names (without the "@readme" prefix), the parser will recognize these as special readme tags and handle them appropriately.

Examples:

YARD::Readme::DocstringParser.readme_tag_names = ["comment", "code", "source"]


30
31
32
# File 'lib/yard/readme/docstring_parser.rb', line 30

def readme_tag_names
  @readme_tag_names
end

Class Method Details

.readme_tag_names_regexObject



32
33
34
# File 'lib/yard/readme/docstring_parser.rb', line 32

def readme_tag_names_regex
  @readme_tag_names_regex ||= /\A(#{readme_tag_names.join("|")})/
end

.readme_tag_names_regex?Boolean

Returns:

  • (Boolean)


36
37
38
# File 'lib/yard/readme/docstring_parser.rb', line 36

def readme_tag_names_regex?
  readme_tag_names && !readme_tag_names.empty?
end

.strip_readme_tag_arg(text) ⇒ Object



40
41
42
43
44
# File 'lib/yard/readme/docstring_parser.rb', line 40

def strip_readme_tag_arg(text)
  return text unless readme_tag_names_regex?

  text.sub(readme_tag_names_regex, "")
end

Instance Method Details

#parse_content(content) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/yard/readme/docstring_parser.rb', line 47

def parse_content(content)
  content = content.split(/\r?\n/) if content.is_a?(String)
  return '' if !content || content.empty?
  docstring = String.new("")

  indent = content.first[/^\s*/].length
  last_indent = 0
  orig_indent = 0
  directive = false
  last_line = ""
  tag_name = nil
  tag_buf = []

  (content + ['']).each_with_index do |line, index|
    indent = line[/^\s*/].length
    empty = (line =~ /^\s*$/ ? true : false)
    done = content.size == index

    if tag_name && (((indent < orig_indent && !empty) || done ||
        (indent == 0 && !empty)) || (indent <= last_indent && line =~ META_MATCH))
      buf = tag_buf.join("\n")
      if directive || tag_is_directive?(tag_name)
        directive = create_directive(tag_name, buf)
        if directive
          docstring << parse_content(directive.expanded_text).chomp
        end
      else
        readme_text = parse_readme_text(buf) if parse_readme_text?(tag_name, buf)
        docstring << readme_text if readme_text
        create_tag(tag_name, buf)
      end
      tag_name = nil
      tag_buf = []
      directive = false
      orig_indent = 0
    end

    # Found a meta tag
    if line =~ META_MATCH
      directive = $1
      tag_name = $2
      tag_buf = [($3 || '')]
    elsif tag_name && indent >= orig_indent && !empty
      orig_indent = indent if orig_indent == 0
      # Extra data added to the tag on the next line
      last_empty = last_line =~ /^[ \t]*$/ ? true : false

      tag_buf << '' if last_empty
      tag_buf << line.gsub(/^[ \t]{#{orig_indent}}/, '')
    elsif !tag_name
      # Regular docstring text
      docstring << line
      docstring << "\n"
    end

    last_indent = indent
    last_line = line
  end

  docstring
end

#parse_readme_text(text) ⇒ String?

Strips the @readme text of any readme-specific tag names (as defined in readme_tag_names) and adds appropriate spacing.

Parameters:

  • text (String)

    the raw text from the @readme tag

Returns:

  • (String, nil)

    the processed text or nil if no processing was done



116
117
118
119
# File 'lib/yard/readme/docstring_parser.rb', line 116

def parse_readme_text(text)
  readme_text = self.class.strip_readme_tag_arg(text)
  readme_text << "\n\n" if readme_text
end

#parse_readme_text?(tag_name, buf) ⇒ Boolean

Determines whether a tag's text should be processed as readme text. Only non-empty @readme tags are processed.

Parameters:

  • tag_name (String)

    the name of the tag

  • buf (String)

    the tag's text buffer

Returns:

  • (Boolean)

    true if the tag should be processed as readme text



129
130
131
# File 'lib/yard/readme/docstring_parser.rb', line 129

def parse_readme_text?(tag_name, buf)
  tag_name == 'readme' && !buf.empty?
end