class YARD::DocstringParser
@since 0.8.0
@see #parse_content
YARD::Docstring.default_parser = ReverseDocstringParser
# Set the parser as default when parsing
end
end
super(content.reverse)
def parse_content(content)
class ReverseDocstringParser
# Parses docstrings backwards!
@example Creating a Custom DocstringParser
DocstringParser.new.parse(“text here”).to_docstring
@example Creating a Docstring with a DocstringParser
parsed, allowing for completely different docstring syntaxes.
subclass. This allows developers to change the way docstrings are
setting the {Docstring.default_parser} attribute with the name of the
The DocstringParser can be subclassed and substituted during parsing by
== Subclassing Notes
the parser and call {#parse} followed by {#to_docstring}.
for a {CodeObjects::Base}. To create a new docstring, you should initialize
Parses text and creates a {Docstring} object to represent documentation
def self.after_parse(&block)
-
(void)
-
Other tags:
- Yieldreturn: -
Other tags:
- Yieldparam: parser - the docstring parser object
Other tags:
- Yield: - a block to be called after a docstring is parsed
def self.after_parse(&block) after_parse_callbacks << block end
def self.after_parse_callbacks
-
(Array
- the {after_parse} callback proc objects)
def self.after_parse_callbacks @after_parse_callbacks ||= [] end
def call_after_parse_callbacks
def call_after_parse_callbacks self.class.after_parse_callbacks.each do |cb| cb.call(self) end end
def call_directives_after_parse
Calls the {Tags::Directive#after_parse} callback on all the
def call_directives_after_parse directives.each(&:after_parse) end
def create_directive(tag_name, tag_buf)
-
(Tags::Directive)
- the directive object that is created
def create_directive(tag_name, tag_buf) if library.has_directive?(tag_name) dir = library.directive_create(tag_name, tag_buf, self) if dir.is_a?(Tags::Directive) @directives << dir dir end else log.warn "Unknown directive @!#{tag_name}" + (object ? " in file `#{object.file}` near line #{object.line}" : "") nil end rescue Tags::TagFormatError log.warn "Invalid directive format for @!#{tag_name}" + (object ? " in file `#{object.file}` near line #{object.line}" : "") nil end
def create_ref_tag(tag_name, name, object_name)
def create_ref_tag(tag_name, name, object_name) @tags << Tags::RefTagList.new(tag_name, P(object, object_name), name) end
def create_tag(tag_name, tag_buf = '')
-
(Tags::Tag, Tags::RefTag)
- a tag
Parameters:
-
tag_buf
(String
) -- the text attached to the tag with newlines removed. -
tag_name
(String
) -- the tag name
def create_tag(tag_name, tag_buf = '') if tag_buf =~ /\A\s*(?:(\S+)\s+)?\(\s*see\s+(\S+)\s*\)\s*\Z/ return create_ref_tag(tag_name, $1, $2) end if library.has_tag?(tag_name) @tags += [library.tag_create(tag_name, tag_buf)].flatten else log.warn "Unknown tag @#{tag_name}" + (object ? " in file `#{object.file}` near line #{object.line}" : "") end rescue Tags::TagFormatError log.warn "Invalid tag format for @#{tag_name}" + (object ? " in file `#{object.file}` near line #{object.line}" : "") end
def detect_reference(content)
def detect_reference(content) if content =~ /\A\s*\(see (\S+)\s*\)(?:\s|$)/ path = $1 extra = $' [CodeObjects::Proxy.new(namespace, path), extra] else [nil, content] end end
def initialize(library = Tags::Library.instance)
-
library
(Tags::Library
) -- a tag library for recognizing
def initialize(library = Tags::Library.instance) @text = "" @raw_text = "" @tags = [] @directives = [] @library = library @object = nil @reference = nil @handler = nil @state = OpenStruct.new end
def namespace
def namespace object && object.namespace end
def parse(content, object = nil, handler = nil)
- See: #to_docstring -
Returns:
-
(self)
- the parser object. To get the docstring,
Parameters:
-
handler
(Handlers::Base, nil
) -- the handler object that is -
object
(CodeObjects::Base
) -- the object that the docstring -
content
(String
) -- the docstring text to parse
def parse(content, object = nil, handler = nil) @object = object @handler = handler @reference, @raw_text = detect_reference(content) text = parse_content(@raw_text) @text = text.strip call_directives_after_parse post_process self end
def parse_content(content)
- Note: - Subclasses can override this method to perform custom
Parameters:
-
content
(String
) -- the content to parse
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 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
def post_process
-
(void)
-
def post_process call_after_parse_callbacks end
def tag_is_directive?(tag_name)
Backward compatibility to detect old tags that should be specified
def tag_is_directive?(tag_name) list = %w(attribute endgroup group macro method scope visibility) list.include?(tag_name) end
def to_docstring
-
(Docstring)
- translates parsed text into
def to_docstring Docstring.new!(text, tags, object, raw_text, reference) end