Skip to content

Commit 16b47d8

Browse files
committed
refactor RDoc markup handling for improved loading and initialization
1 parent 070e07c commit 16b47d8

File tree

2 files changed

+72
-51
lines changed

2 files changed

+72
-51
lines changed

lib/yard/templates/helpers/markup/rdoc_markdown.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ module YARD
33
module Templates
44
module Helpers
55
module Markup
6-
begin require 'rdoc'; rescue LoadError; nil end
76
begin
7+
require 'rdoc'
88
require 'rdoc/markdown'
99
rescue LoadError
1010
raise NameError, "could not load RDoc Markdown support (rdoc is too old)"

lib/yard/templates/helpers/markup/rdoc_markup.rb

Lines changed: 71 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,56 @@
11
# frozen_string_literal: true
22
require 'thread'
33

4+
gem 'rdoc', '>= 6.0'
5+
require 'rdoc'
6+
require 'rdoc/markup'
7+
require 'rdoc/markup/to_html'
8+
49
module YARD
510
module Templates
611
module Helpers
712
module Markup
8-
begin require 'rdoc'; rescue LoadError; nil end
9-
begin
10-
require 'rdoc/markup'
11-
require 'rdoc/markup/to_html'
12-
class RDocMarkup; MARKUP = RDoc::Markup end
13-
class RDocMarkupToHtml < RDoc::Markup::ToHtml
14-
if defined?(RDoc::VERSION) && RDoc::VERSION >= '4.0.0' &&
15-
defined?(RDoc::Options)
16-
def initialize
17-
options = RDoc::Options.new
18-
options.pipe = true
19-
super(options)
20-
end
21-
end
22-
end
23-
rescue LoadError
24-
begin
25-
require 'rdoc/markup/simple_markup'
26-
require 'rdoc/markup/simple_markup/to_html'
27-
class RDocMarkup; MARKUP = SM::SimpleMarkup end
28-
class RDocMarkupToHtml < SM::ToHtml; end
29-
rescue LoadError
30-
raise NameError, "could not load RDocMarkup (rdoc is not installed)"
31-
end
32-
end
33-
3413
class RDocMarkup
14+
MARKUP = RDoc::Markup
15+
3516
attr_accessor :from_path
3617

37-
@@mutex = Mutex.new
38-
@@formatter = nil
39-
@@markup = nil
18+
# Class instance variables initialized once
19+
@mutex = Mutex.new
20+
@formatter = nil
21+
@markup = nil
4022

41-
def initialize(text)
42-
@text = text
23+
class << self
24+
attr_reader :mutex, :formatter, :markup
25+
26+
def initialize_markup_components
27+
return if @markup && @formatter
4328

44-
@@mutex.synchronize do
45-
@@formatter ||= RDocMarkupToHtml.new
46-
@@markup ||= MARKUP.new
29+
@mutex.synchronize do
30+
@formatter ||= RDocMarkupToHtml.new
31+
@markup ||= MARKUP.new
32+
end
4733
end
4834
end
4935

36+
def initialize(text)
37+
@text = text
38+
self.class.initialize_markup_components
39+
end
40+
5041
def to_html
5142
html = nil
52-
@@mutex.synchronize do
53-
@@formatter.from_path = from_path
54-
html = @@markup.convert(@text, @@formatter)
43+
self.class.mutex.synchronize do
44+
self.class.formatter.from_path = from_path
45+
html = self.class.markup.convert(@text, self.class.formatter)
5546
end
56-
html = fix_dash_dash(html)
57-
html = fix_typewriter(html)
58-
html
47+
48+
fix_dash_dash(fix_typewriter(html))
5949
end
6050

6151
private
6252

6353
# Fixes RDoc behaviour with ++ only supporting alphanumeric text.
64-
#
65-
# @todo Refactor into own SimpleMarkup subclass
6654
def fix_typewriter(text)
6755
code_tags = 0
6856
text.gsub(%r{<(/)?(pre|code|tt)|(\s|^|>)\+(?! )([^\n\+]{1,900})(?! )\+}) do |str|
@@ -76,33 +64,66 @@ def fix_typewriter(text)
7664
next str
7765
end
7866
next str unless code_tags == 0
79-
first_text + '<tt>' + type_text + '</tt>'
67+
"#{first_text}<tt>#{type_text}</tt>"
8068
end
8169
end
8270

83-
# Don't allow -- to turn into &#8212; element. The chances of this being
84-
# some --option is far more likely than the typographical meaning.
85-
#
86-
# @todo Refactor into own SimpleMarkup subclass
71+
# Don't allow -- to turn into &#8212; element (em dash)
8772
def fix_dash_dash(text)
8873
text.gsub(/&#8212;(?=\S)/, '--')
8974
end
9075
end
9176

92-
class RDocMarkupToHtml
77+
# Specialized ToHtml formatter for YARD
78+
class RDocMarkupToHtml < RDoc::Markup::ToHtml
9379
attr_accessor :from_path
9480

81+
def initialize
82+
options = RDoc::Options.new
83+
options.pipe = true
84+
super(options)
85+
86+
# The hyperlink detection state
87+
@hyperlink = false
88+
end
89+
9590
# Disable auto-link of URLs
96-
def handle_special_HYPERLINK(special) # rubocop:disable Style/MethodName
91+
def handle_special_HYPERLINK(special)
9792
@hyperlink ? special.text : super
9893
end
9994

10095
def accept_paragraph(*args)
10196
par = args.last
10297
text = par.respond_to?(:txt) ? par.txt : par.text
103-
@hyperlink = text =~ /\{(https?:|mailto:|link:|www\.)/ ? true : false
98+
@hyperlink = text =~ /\{(https?:|mailto:|link:|www\.)/
10499
super
105100
end
101+
102+
# Override gen_url to support from_path in relative links
103+
def gen_url(url, text)
104+
scheme, path, id = parse_url(url)
105+
106+
if scheme == 'link' && !path.start_with?('/') && !from_path.nil? && !from_path.empty?
107+
# Make the path relative to from_path for link: URLs
108+
path = File.expand_path(path, File.dirname(from_path))
109+
end
110+
111+
super("#{scheme}:#{path}#{id}", text)
112+
end
113+
114+
# Override parse_url to handle custom schemes
115+
def parse_url(url)
116+
case url
117+
when /^mailto:(.*)$/i
118+
['mailto', $1, '']
119+
when /^(https?|ftp|irc):(.*)$/i
120+
[$1, $2, '']
121+
when /^link:(.*)$/i
122+
['link', $1, '']
123+
else
124+
['http', url, '']
125+
end
126+
end
106127
end
107128
end
108129
end

0 commit comments

Comments
 (0)