Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,37 @@ npx stylelint "lib/rdoc/generator/template/aliki/css/rdoc.css"
- Style and formatting checks
- Many issues auto-fixable with `--fix`

### Type annotations

Annotate method types using [Sorbet flavored RBS](https://sorbet.org/docs/rbs-support) in inline comments.
For more information about RBS syntax, see the [documentation](https://github.com/ruby/rbs/blob/master/docs/syntax.md).

A few examples:

```ruby
# Method that receives an integer and doesn't return anything
#: (Integer) -> void
def foo(something); end

# Method that receives a string and returns an integer
#: (String) -> Integer
def bar(something)
123
end

# Method that doesn't accept arguments and returns a hash of symbol to string
#: () -> Hash[Symbol, String]
def bar
{ key: "value" }
end

# Method that accepts a block, which yields a single integer argument and returns whatever the block returns
#: [T] () { (Integer) -> T } -> T
def bar
yield(5)
end
```

### Documentation Generation

```bash
Expand Down
9 changes: 9 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,15 @@ npm run lint:css
npm run lint:css -- --fix
```

## Type annotations

RDoc is currently not a typed codebase. Despite not running a type checker, contributors have been
adding some comment annotations to make the codebase easier to navigate and understand.

These annotations use [Sorbet flavored RBS](https://sorbet.org/docs/rbs-support) annotations,
so that we can tag definitions as abstract and override. For more information on RBS syntax,
see the [documentation](https://github.com/ruby/rbs/blob/master/docs/syntax.md).

## Parser Generation

RDoc uses generated parsers for Markdown and RD formats.
Expand Down
2 changes: 1 addition & 1 deletion lib/rdoc/generator/template/aliki/_sidebar_pages.rhtml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
<%= h f.page_name %>
</a>
</li>
<%- next %>
<%- next -%>
<%- end %>

<li>
Expand Down
2 changes: 1 addition & 1 deletion lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<%- f = files.shift %>
<%- if files.empty? %>
<li><a href="<%= rel_prefix %>/<%= h f.path %>"><%= h f.page_name %></a></li>
<%- next %>
<%- next -%>
<%- end %>
<li><details<%= ' open' if dir == n %>><summary><%
if n == f.page_name
Expand Down
1 change: 1 addition & 0 deletions lib/rdoc/markup.rb
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ def convert(input, formatter)
autoload :BlankLine, "#{__dir__}/markup/blank_line"
autoload :BlockQuote, "#{__dir__}/markup/block_quote"
autoload :Document, "#{__dir__}/markup/document"
autoload :Element, "#{__dir__}/markup/element"
autoload :HardBreak, "#{__dir__}/markup/hard_break"
autoload :Heading, "#{__dir__}/markup/heading"
autoload :Include, "#{__dir__}/markup/include"
Expand Down
48 changes: 25 additions & 23 deletions lib/rdoc/markup/blank_line.rb
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
# frozen_string_literal: true
##
# An empty line. This class is a singleton.

class RDoc::Markup::BlankLine

@instance = new

##
# RDoc::Markup::BlankLine is a singleton

def self.new
@instance
module RDoc
class Markup
# An empty line
class BlankLine < Element
@instance = new

# RDoc::Markup::BlankLine is a singleton
#: () -> BlankLine
def self.new
@instance
end

# Calls #accept_blank_line on +visitor+
# @override
#: (untyped) -> void
def accept(visitor)
visitor.accept_blank_line(self)
end

# @override
#: (PP) -> void
def pretty_print(q) # :nodoc:
q.text("blankline")
end
end
end

##
# Calls #accept_blank_line on +visitor+

def accept(visitor)
visitor.accept_blank_line self
end

def pretty_print(q) # :nodoc:
q.text 'blankline'
end

end
21 changes: 21 additions & 0 deletions lib/rdoc/markup/element.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true

module RDoc
class Markup
# Base class defining the interface for all markup elements found in documentation
# @abstract
class Element
# @abstract
#: (untyped) -> void
def accept(visitor)
raise NotImplementedError, "#{self.class} must implement the accept method"
end

# @abstract
#: (PP) -> void
def pretty_print(q)
raise NotImplementedError, "#{self.class} must implement the pretty_print method"
end
end
end
end
57 changes: 30 additions & 27 deletions lib/rdoc/markup/hard_break.rb
Original file line number Diff line number Diff line change
@@ -1,31 +1,34 @@
# frozen_string_literal: true
##
# A hard-break in the middle of a paragraph.

class RDoc::Markup::HardBreak

@instance = new

##
# RDoc::Markup::HardBreak is a singleton

def self.new
@instance
end

##
# Calls #accept_hard_break on +visitor+

def accept(visitor)
visitor.accept_hard_break self
module RDoc
class Markup
# A hard-break in the middle of a paragraph.
class HardBreak < Element
@instance = new

# RDoc::Markup::HardBreak is a singleton
#: () -> HardBreak
def self.new
@instance
end

# Calls #accept_hard_break on +visitor+
# @override
#: (untyped) -> void
def accept(visitor)
visitor.accept_hard_break(self)
end

#: (top) -> bool
def ==(other) # :nodoc:
self.class === other
end

# @override
#: (PP) -> void
def pretty_print(q) # :nodoc:
q.text("[break]")
end
end
end

def ==(other) # :nodoc:
self.class === other
end

def pretty_print(q) # :nodoc:
q.text "[break]"
end

end
175 changes: 96 additions & 79 deletions lib/rdoc/markup/heading.rb
Original file line number Diff line number Diff line change
@@ -1,84 +1,101 @@
# frozen_string_literal: true
##
# A heading with a level (1-6) and text

RDoc::Markup::Heading =
Struct.new :level, :text do

@to_html = nil
@to_label = nil

##
# A singleton RDoc::Markup::ToLabel formatter for headings.

def self.to_label
@to_label ||= RDoc::Markup::ToLabel.new
end

##
# A singleton plain HTML formatter for headings. Used for creating labels
# for the Table of Contents

def self.to_html
return @to_html if @to_html

markup = RDoc::Markup.new
markup.add_regexp_handling RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF

@to_html = RDoc::Markup::ToHtml.new nil

def @to_html.handle_regexp_CROSSREF(target)
target.text.sub(/^\\/, '')
module RDoc
class Markup
# A heading with a level (1-6) and text
#
# RDoc syntax:
# = Heading 1
# == Heading 2
# === Heading 3
#
# Markdown syntax:
# # Heading 1
# ## Heading 2
# ### Heading 3
class Heading < Element
#: String
attr_reader :text

#: Integer
attr_accessor :level

# A singleton RDoc::Markup::ToLabel formatter for headings.
#: () -> RDoc::Markup::ToLabel
def self.to_label
@to_label ||= Markup::ToLabel.new
end

# A singleton plain HTML formatter for headings. Used for creating labels for the Table of Contents
#: () -> RDoc::Markup::ToHtml
def self.to_html
@to_html ||= begin
markup = Markup.new
markup.add_regexp_handling CrossReference::CROSSREF_REGEXP, :CROSSREF

to_html = Markup::ToHtml.new nil

def to_html.handle_regexp_CROSSREF(target)
target.text.sub(/^\\/, '')
end

to_html
end
end

#: (Integer, String) -> void
def initialize(level, text)
super()

@level = level
@text = text
end

#: (Object) -> bool
def ==(other)
other.is_a?(Heading) && other.level == @level && other.text == @text
end

# @override
#: (untyped) -> void
def accept(visitor)
visitor.accept_heading(self)
end

# An HTML-safe anchor reference for this header.
#: () -> String
def aref
"label-#{self.class.to_label.convert text.dup}"
end

# Creates a fully-qualified label which will include the label from +context+. This helps keep ids unique in HTML.
#: (RDoc::Context?) -> String
def label(context = nil)
label = +""
label << "#{context.aref}-" if context&.respond_to?(:aref)
label << aref
label
end

# HTML markup of the text of this label without the surrounding header element.
#: () -> String
def plain_html
no_image_text = text

if matched = no_image_text.match(/rdoc-image:[^:]+:(.*)/)
no_image_text = matched[1]
end

self.class.to_html.to_html(no_image_text)
end

# @override
#: (PP) -> void
def pretty_print(q)
q.group 2, "[head: #{level} ", ']' do
q.pp text
end
end
end

@to_html
end

##
# Calls #accept_heading on +visitor+

def accept(visitor)
visitor.accept_heading self
end

##
# An HTML-safe anchor reference for this header.

def aref
"label-#{self.class.to_label.convert text.dup}"
end

##
# Creates a fully-qualified label which will include the label from
# +context+. This helps keep ids unique in HTML.

def label(context = nil)
label = aref

label = [context.aref, label].compact.join '-' if
context and context.respond_to? :aref

label
end

##
# HTML markup of the text of this label without the surrounding header
# element.

def plain_html
text = self.text.dup

if matched = text.match(/rdoc-image:[^:]+:(.*)/)
text = matched[1]
end

self.class.to_html.to_html(text)
end

def pretty_print(q) # :nodoc:
q.group 2, "[head: #{level} ", ']' do
q.pp text
end
end

end
Loading
Loading