1 # frozen_string_literal: true
4 # A parser for TomDoc based on TomDoc 1.0.0-rc1 (02adef9b5a)
6 # The TomDoc specification can be found at:
10 # The latest version of the TomDoc specification can be found at:
12 # https://github.com/mojombo/tomdoc/blob/master/tomdoc.md
14 # To choose TomDoc as your only default format see RDoc::Options@Saved+Options
15 # for instructions on setting up a <code>.rdoc_options</code> file to store
16 # your project default.
18 # There are a few differences between this parser and the specification. A
19 # best-effort was made to follow the specification as closely as possible but
20 # some choices to deviate were made.
22 # A future version of RDoc will warn when a MUST or MUST NOT is violated and
23 # may warn when a SHOULD or SHOULD NOT is violated. RDoc will always try
24 # to emit documentation even if given invalid TomDoc.
26 # Here are some implementation choices this parser currently makes:
28 # This parser allows rdoc-style inline markup but you should not depended on
31 # This parser allows a space between the comment and the method body.
33 # This parser does not require the default value to be described for an
36 # This parser does not examine the order of sections. An Examples section may
37 # precede the Arguments section.
39 # This class is documented in TomDoc format. Since this is a subclass of the
40 # RDoc markup parser there isn't much to see here, unfortunately.
42 class RDoc::TomDoc < RDoc::Markup::Parser
44 # Internal: Token accessor
48 # Internal: Adds a post-processor which sets the RDoc section based on the
53 def self.add_post_processor # :nodoc:
54 RDoc::Markup::PreProcess.post_process do |comment, code_object|
55 next unless code_object and
56 RDoc::Comment === comment and comment.format == 'tomdoc'
58 comment.text.gsub!(/(\A\s*# )(Public|Internal|Deprecated):\s+/) do
59 section = code_object.add_section $2
60 code_object.temporary_section = section
69 # Public: Parses TomDoc from text
71 # text - A String containing TomDoc-format text.
75 # RDoc::TomDoc.parse <<-TOMDOC
76 # This method does some things
80 # # => #<RDoc::Markup::Document:0xXXX @parts=[...], @file=nil>
82 # Returns an RDoc::Markup::Document representing the TomDoc format.
88 doc = RDoc::Markup::Document.new
93 # Internal: Extracts the Signature section's method signature
95 # comment - An RDoc::Comment that will be parsed and have the signature
98 # Returns a String containing the signature and nil if not
100 def self.signature comment
101 return unless comment.tomdoc?
103 document = comment.parse
106 found_heading = false
107 found_signature = false
109 document.parts.delete_if do |part|
110 next false if found_signature
113 RDoc::Markup::Heading === part && part.text == 'Signature'
115 next false unless found_heading
117 next true if RDoc::Markup::BlankLine === part
119 if RDoc::Markup::Verbatim === part then
121 found_signature = true
125 signature and signature.text
128 # Public: Creates a new TomDoc parser. See also RDoc::Markup::parse
134 @seen_returns = false
137 # Internal: Builds a heading from the token stream
139 # level - The level of heading to create
141 # Returns an RDoc::Markup::Heading
143 def build_heading level
146 @section = heading.text
151 # Internal: Builds a verbatim from the token stream. A verbatim in the
152 # Examples section will be marked as in Ruby format.
154 # margin - The indentation from the margin for lines that belong to this
157 # Returns an RDoc::Markup::Verbatim
159 def build_verbatim margin
162 verbatim.format = :ruby if @section == 'Examples'
167 # Internal: Builds a paragraph from the token stream
171 # Returns an RDoc::Markup::Paragraph.
173 def build_paragraph margin
174 p :paragraph_start => margin if @debug
176 paragraph = RDoc::Markup::Paragraph.new
178 until @tokens.empty? do
183 @section = 'Returns' if data =~ /\A(Returns|Raises)/
187 if :TEXT == peek_token[0] then
188 # Lines beginning with 'Raises' in the Returns section should not be
189 # treated as multiline text
190 if 'Returns' == @section and
191 peek_token[1].start_with?('Raises') then
205 p :paragraph_end => margin if @debug
211 # Detects a section change to "Returns" and adds a heading
213 def parse_text parent, indent # :nodoc:
214 paragraph = build_paragraph indent
216 if false == @seen_returns and 'Returns' == @section then
218 parent << RDoc::Markup::Heading.new(3, 'Returns')
219 parent << RDoc::Markup::BlankLine.new
225 # Internal: Turns text into an Array of tokens
227 # text - A String containing TomDoc-format text.
232 text = text.sub(/\A(Public|Internal|Deprecated):\s+/, '')
239 # leading spaces will be reflected by the column of the next token
240 # the only thing we loose are trailing spaces at the end of the file
241 next if @s.scan(/ +/)
244 when @s.scan(/\r?\n/) then
245 token = [:NEWLINE, @s.matched, *pos]
248 when @s.scan(/(Examples|Signature)$/) then
249 @tokens << [:HEADER, 3, *pos]
252 when @s.scan(/([:\w][\w\[\]]*)[ ]+- /) then
256 [:TEXT, @s.matched.sub(/\r$/, ''), *pos]