Module: RDoc::Text

Overview

Methods for manipulating comment text

Constant Summary collapse

MARKUP_FORMAT =

Maps markup formats to classes that can parse them. If the format is unknown, “rdoc” format is used.

{
  'markdown' => RDoc::Markdown,
  'rdoc'     => RDoc::Markup,
  'rd'       => RDoc::RD,
  'tomdoc'   => RDoc::TomDoc,
}
SPACE_SEPARATED_LETTER_CLASS =

Character class to be separated by a space when concatenating lines.

/[\p{Nd}\p{Lc}\p{Pc}]|[!-~&&\W]/

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#languageObject

The language for this text. This affects stripping comments markers.



17
18
19
# File 'lib/rdoc/text.rb', line 17

def language
  @language
end

Class Method Details

.decode_legacy_label(label) ⇒ Object

Decodes a label that may be in legacy RDoc format where CGI.escape was applied and then ‘%’ was replaced with ‘-’. Converts ‘+’ to space, then reverses -XX hex encoding for non-alphanumeric characters.

Labels in new format pass through unchanged because -XX patterns that decode to alphanumeric characters are left as-is (CGI.escape never encodes alphanumerics).

Examples:

"What-27s+Here"  -> "What's Here"  (legacy: -27 is apostrophe)
"Foo-3A-3ABar"   -> "Foo::Bar"     (legacy: -3A is colon)
"Whats-Here"     -> "Whats-Here"   (new format, unchanged)


235
236
237
238
239
240
241
242
# File 'lib/rdoc/text.rb', line 235

module_function def decode_legacy_label(label)
  label = label.tr('+', ' ')
  label.gsub!(/-([0-7][0-9A-F])/) do
    char = [$1.hex].pack('C')
    char.match?(/[a-zA-Z0-9]/) ? $& : char
  end
  label
end

.expand_tabs(text) ⇒ Object

Expands tab characters in text to eight spaces



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/rdoc/text.rb', line 35

module_function def expand_tabs(text)
  expanded = []

  text.each_line do |line|
    nil while line.gsub!(/(?:\G|\r)((?:.{8})*?)([^\t\r\n]{0,7})\t/) do
      r = "#{$1}#{$2}#{' ' * (8 - $2.size)}"
      r = RDoc::Encoding.change_encoding r, text.encoding
      r
    end

    expanded << line
  end

  expanded.join
end

.to_anchor(text) ⇒ Object

Converts text to a GitHub-style anchor ID:

  • Lowercase

  • Remove characters that aren’t alphanumeric, space, or hyphen

  • Replace spaces with hyphens

Examples:

"Hello World"  -> "hello-world"
"Foo::Bar"     -> "foobar"
"What's New?"  -> "whats-new"


217
218
219
# File 'lib/rdoc/text.rb', line 217

module_function def to_anchor(text)
  text.downcase.gsub(/[^a-z0-9 \-]/, '').gsub(' ', '-')
end

Instance Method Details

#flush_left(text) ⇒ Object

Flush text left based on the shortest line



54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/rdoc/text.rb', line 54

def flush_left(text)
  indent = 9999

  text.each_line do |line|
    line_indent = line =~ /\S/ || 9999
    indent = line_indent if indent > line_indent
  end

  empty = ''
  empty = RDoc::Encoding.change_encoding empty, text.encoding

  text.gsub(/^ {0,#{indent}}/, empty)
end

#markup(text) ⇒ Object

Convert a string in markup format into HTML.

Requires the including class to implement #formatter



73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/rdoc/text.rb', line 73

def markup(text)
  if @store.options
    locale = @store.options.locale
  else
    locale = nil
  end
  if locale
    i18n_text = RDoc::I18n::Text.new(text)
    text = i18n_text.translate(locale)
  end
  parse(text).accept formatter
end

#normalize_comment(text) ⇒ Object

Strips hashes, expands tabs then flushes text to the left



89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/rdoc/text.rb', line 89

def normalize_comment(text)
  return text if text.empty?

  case language
  when :ruby
    text = strip_hashes text
  when :c
    text = strip_stars text
  end
  text = expand_tabs    text
  text = flush_left     text
  text = strip_newlines text
  text
end

#parse(text, format = 'rdoc') ⇒ Object

Normalizes text then builds a RDoc::Markup::Document from it



107
108
109
110
111
112
113
114
115
116
# File 'lib/rdoc/text.rb', line 107

def parse(text, format = 'rdoc')
  return text if RDoc::Markup::Document === text
  return text.parse if RDoc::Comment === text

  text = normalize_comment text # TODO remove, should not be necessary

  return RDoc::Markup::Document.new if text =~ /\A\n*\z/

  MARKUP_FORMAT[format].parse text
end

#snippet(text, limit = 100) ⇒ Object

The first limit characters of text as HTML



121
122
123
124
125
# File 'lib/rdoc/text.rb', line 121

def snippet(text, limit = 100)
  document = parse text

  RDoc::Markup::ToHtmlSnippet.new(limit).convert document
end

#strip_hashes(text) ⇒ Object

Strips leading # characters from text



130
131
132
133
134
135
136
137
# File 'lib/rdoc/text.rb', line 130

def strip_hashes(text)
  return text if text =~ /^(?>\s*)[^\#]/

  empty = ''
  empty = RDoc::Encoding.change_encoding empty, text.encoding

  text.gsub(/^\s*(#+)/) { $1.tr '#', ' ' }.gsub(/^\s+$/, empty)
end

#strip_newlines(text) ⇒ Object

Strips leading and trailing n characters from text



142
143
144
# File 'lib/rdoc/text.rb', line 142

def strip_newlines(text)
  text.gsub(/\A\n*(.*?)\n*\z/m) do $1 end # block preserves String encoding
end

#strip_stars(text) ⇒ Object

Strips /* */ style comments



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/rdoc/text.rb', line 149

def strip_stars(text)
  return text unless text =~ %r%/\*.*\*/%m

  encoding = text.encoding

  text = text.gsub %r%Document-method:\s+[\w:.#=!?|^&<>~+\-/*\%@`\[\]]+%, ''

  space = ' '
  space = RDoc::Encoding.change_encoding space, encoding if encoding

  text.sub!  %r%/\*+%       do space * $&.length end
  text.sub!  %r%\*+/%       do space * $&.length end
  text.gsub! %r%^[ \t]*\*%m do space * $&.length end

  empty = ''
  empty = RDoc::Encoding.change_encoding empty, encoding if encoding
  text.gsub(/^\s+$/, empty)
end

#wrap(txt, line_len = 76) ⇒ Object

Wraps txt to line_len



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/rdoc/text.rb', line 171

def wrap(txt, line_len = 76)
  res = []
  sp = 0
  ep = txt.length

  while sp < ep
    # scan back for a space
    p = sp + line_len - 1
    if p >= ep
      p = ep
    else
      while p > sp and txt[p] != ?\s
        p -= 1
      end
      if p <= sp
        p = sp + line_len
        while p < ep and txt[p] != ?\s
          p += 1
        end
      end
    end
    res << txt[sp...p] << "\n"
    sp = p
    sp += 1 while sp < ep and txt[sp] == ?\s
  end

  res.join.strip
end