markdown_helper 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/LICENSE +1 -1
- data/README.md +4 -9
- data/Rakefile +0 -1
- data/lib/markdown_helper.rb +249 -279
- data/lib/markdown_helper/version.rb +1 -1
- data/markdown/readme/README.template.md +2 -7
- data/markdown/readme/highlighted_ruby.md +2 -2
- data/markdown/use_cases/Rakefile +0 -6
- metadata +2 -16
- data/LICENSE.txt +0 -21
- data/bin/_create_page_toc +0 -46
- data/bin/usage/create_page_toc.txt +0 -14
- data/markdown/use_cases/tables_of_contents/create_and_include_page_toc/create_and_include.rb +0 -6
- data/markdown/use_cases/tables_of_contents/create_and_include_page_toc/create_and_include.sh +0 -3
- data/markdown/use_cases/tables_of_contents/create_and_include_page_toc/included.md +0 -44
- data/markdown/use_cases/tables_of_contents/create_and_include_page_toc/includer.md +0 -5
- data/markdown/use_cases/tables_of_contents/create_and_include_page_toc/page.md +0 -38
- data/markdown/use_cases/tables_of_contents/create_and_include_page_toc/text.md +0 -28
- data/markdown/use_cases/tables_of_contents/create_and_include_page_toc/toc.md +0 -7
- data/markdown/use_cases/tables_of_contents/create_and_include_page_toc/use_case.md +0 -62
- data/markdown/use_cases/tables_of_contents/create_and_include_page_toc/use_case_builder.rb +0 -94
- data/markdown/use_cases/tables_of_contents/create_and_include_page_toc/use_case_template.md +0 -42
- data/markdown/use_cases/tables_of_contents/create_page_toc_use_case.rb +0 -81
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '09204d578d4034b5940afc983b9d3989adff2d1b05763b0e6e867e3183b338c8'
|
4
|
+
data.tar.gz: a90232dc47c8d901f1fa1a5bed7964e0deee6fb3b3bd9d2713f46ea105b162b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ad9d3e8cbf0a1fa17eba25579c02165571e5408ea979747600aa6db74b52122fd2157d61d6f2a65e7302eac52a443e40343d10d0c291eae7912d64ccd099ed6f
|
7
|
+
data.tar.gz: 4ee21575e5d049259b9c365ab9842d904127ebe8df9f023304bcb35c34242f3eb81edf37a055aee6cdce61283c635fb4d38bb4ffbfa7cdc54f6b7f8584fb8672
|
data/Gemfile.lock
CHANGED
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,16 +1,11 @@
|
|
1
|
-
<!-- >>>>>> BEGIN GENERATED FILE (include): SOURCE README.template.md -->
|
1
|
+
<!-- >>>>>> BEGIN GENERATED FILE (include): SOURCE markdown/readme/README.template.md -->
|
2
2
|
# Markdown Helper
|
3
3
|
|
4
4
|
[](http://rubygems.org/gems/markdown_helper "View this project in Rubygems")
|
5
5
|
|
6
6
|
## What's New?
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
- **Old**: You would first run the markdown helper to generate a page TOC, then run the helper a second time to include the page TOC where you want it.
|
11
|
-
- **New**: You specify the site for the page TOC in the page itself, and the page TOC is automatically generated and inserted there. See the [use case](markdown/use_cases/include_files/include_page_toc/use_case.md#include-page-toc)
|
12
|
-
|
13
|
-
The old way is now deprecated.
|
8
|
+
Command line creation of page TOC (table of contents), previously deprecated, is removed.
|
14
9
|
|
15
10
|
## Contents
|
16
11
|
- [What's a Markdown Helper?](#whats-a-markdown-helper)
|
@@ -172,7 +167,7 @@ where:
|
|
172
167
|
|
173
168
|
<!-- >>>>>> BEGIN INCLUDED FILE (code_block): SOURCE markdown/readme/include.md -->
|
174
169
|
```include.md```:
|
175
|
-
```
|
170
|
+
```
|
176
171
|
@[ruby](my_ruby.rb)
|
177
172
|
|
178
173
|
@[:code_block](my_language.xyzzy)
|
@@ -213,4 +208,4 @@ I have opened some enhancement Issues in the GitHub [markdown_helper](https://gi
|
|
213
208
|
* [Pagination](https://github.com/BurdetteLamar/markdown_helper/issues/40): series of markdown pages connected by prev/next navigation links.
|
214
209
|
|
215
210
|
Feel free to comment on any of these, or to add more Issues (enhancement or otherwise).
|
216
|
-
<!-- <<<<<< END GENERATED FILE (include): SOURCE README.template.md -->
|
211
|
+
<!-- <<<<<< END GENERATED FILE (include): SOURCE markdown/readme/README.template.md -->
|
data/Rakefile
CHANGED
data/lib/markdown_helper.rb
CHANGED
@@ -1,19 +1,20 @@
|
|
1
1
|
require 'pathname'
|
2
|
+
|
2
3
|
require 'markdown_helper/version'
|
3
4
|
|
4
5
|
class MarkdownHelper
|
5
6
|
|
6
7
|
class MarkdownHelperError < RuntimeError; end
|
7
|
-
class CircularIncludeError < MarkdownHelperError; end
|
8
|
-
class UnreadableInputError < MarkdownHelperError; end
|
9
|
-
class TocHeadingsError < MarkdownHelperError; end
|
10
8
|
class OptionError < MarkdownHelperError; end
|
11
|
-
class EnvironmentError < MarkdownHelperError; end
|
12
|
-
class InvalidTocTitleError < MarkdownHelperError; end
|
13
|
-
class MisplacedPageTocError < MarkdownHelperError; end
|
14
9
|
class MultiplePageTocError < MarkdownHelperError; end
|
10
|
+
class InvalidTocTitleError < MarkdownHelperError; end
|
11
|
+
class UnreadableTemplateError < MarkdownHelperError; end
|
12
|
+
class UnwritableMarkdownError < MarkdownHelperError; end
|
13
|
+
class CircularIncludeError < MarkdownHelperError; end
|
14
|
+
class UnreadableIncludeeError < MarkdownHelperError; end
|
15
15
|
|
16
16
|
INCLUDE_REGEXP = /^@\[([^\[]+)\]\(([^)]+)\)$/
|
17
|
+
INCLUDE_MARKDOWN_REGEXP = /^@\[:markdown\]\(([^)]+)\)$/
|
17
18
|
|
18
19
|
attr_accessor :pristine
|
19
20
|
|
@@ -35,187 +36,192 @@ class MarkdownHelper
|
|
35
36
|
send(setter_method, value)
|
36
37
|
merged_options.delete(method)
|
37
38
|
end
|
39
|
+
@inclusions = []
|
38
40
|
end
|
39
41
|
|
40
42
|
def include(template_file_path, markdown_file_path)
|
41
|
-
send(:generate_file, template_file_path, markdown_file_path
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
message = <<EOT
|
48
|
-
Method create_page_toc is deprecated.
|
49
|
-
Please use method include with embedded :page_toc treatment.
|
50
|
-
See https://github.com/BurdetteLamar/markdown_helper/blob/master/markdown/use_cases/include_files/include_page_toc/use_case.md#include-page-toc.
|
51
|
-
EOT
|
52
|
-
warn(message)
|
53
|
-
send(:generate_file, markdown_file_path, toc_file_path, __method__) do |input_lines, output_lines|
|
54
|
-
send(:_create_page_toc, input_lines, output_lines)
|
43
|
+
send(:generate_file, template_file_path, markdown_file_path) do |output_lines|
|
44
|
+
Dir.chdir(File.dirname(template_file_path)) do
|
45
|
+
markdown_lines = include_markdown(template_file_path)
|
46
|
+
markdown_lines = include_page_toc(markdown_lines)
|
47
|
+
include_all(template_file_path, markdown_lines, output_lines)
|
48
|
+
end
|
55
49
|
end
|
56
50
|
end
|
57
51
|
|
58
52
|
private
|
59
53
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
end
|
68
|
-
|
69
|
-
def self.parse(line)
|
70
|
-
# Four leading spaces not allowed (but three are allowed).
|
71
|
-
return nil if line.start_with?(' ' * 4)
|
72
|
-
stripped_line = line.sub(/^ */, '')
|
73
|
-
# Now must begin with hash marks and space.
|
74
|
-
return nil unless stripped_line.match(/^#+ /)
|
75
|
-
hash_marks, title = stripped_line.split(' ', 2)
|
76
|
-
level = hash_marks.size
|
77
|
-
# Seventh level heading not allowed.
|
78
|
-
return nil if level > 6
|
79
|
-
self.new(level, title)
|
80
|
-
end
|
81
|
-
|
82
|
-
|
83
|
-
def link
|
84
|
-
remove_regexp = /[\#\(\)\[\]\{\}\.\?\+\*\`\"\']+/
|
85
|
-
to_hyphen_regexp = /\W+/
|
86
|
-
anchor = title.
|
87
|
-
gsub(remove_regexp, '').
|
88
|
-
gsub(to_hyphen_regexp, '-').
|
89
|
-
downcase
|
90
|
-
"[#{title}](##{anchor})"
|
54
|
+
def generate_file(template_file_path, markdown_file_path)
|
55
|
+
template_path_in_project = MarkdownHelper.path_in_project(template_file_path)
|
56
|
+
output_lines = []
|
57
|
+
yield output_lines
|
58
|
+
unless pristine
|
59
|
+
output_lines.unshift(MarkdownHelper.comment(" >>>>>> BEGIN GENERATED FILE (include): SOURCE #{template_path_in_project} "))
|
60
|
+
output_lines.push(MarkdownHelper.comment(" <<<<<< END GENERATED FILE (include): SOURCE #{template_path_in_project} "))
|
91
61
|
end
|
92
|
-
|
62
|
+
output_lines.push('')
|
63
|
+
output = output_lines.join("\n")
|
64
|
+
File.write(markdown_file_path, output)
|
93
65
|
end
|
94
66
|
|
95
|
-
def
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
67
|
+
def include_markdown(template_file_path)
|
68
|
+
Dir.chdir(File.dirname(template_file_path)) do
|
69
|
+
markdown_lines = []
|
70
|
+
unless File.readable?(template_file_path)
|
71
|
+
message = [
|
72
|
+
'Could not read template file:',
|
73
|
+
MarkdownHelper.backtrace_inclusions(@inclusions),
|
74
|
+
].join("\n")
|
75
|
+
e = UnreadableTemplateError.new(message)
|
76
|
+
e.set_backtrace([])
|
77
|
+
raise e
|
78
|
+
end
|
79
|
+
template_lines = File.readlines(template_file_path)
|
80
|
+
template_lines.each_with_index do |template_line, i|
|
81
|
+
template_line.chomp!
|
82
|
+
treatment, includee_file_path = *parse_include(template_line)
|
83
|
+
if treatment.nil?
|
84
|
+
markdown_lines.push(template_line)
|
85
|
+
next
|
86
|
+
end
|
87
|
+
if treatment == ':page_toc'
|
88
|
+
markdown_lines.push(template_line)
|
89
|
+
next
|
90
|
+
end
|
91
|
+
inclusion = Inclusion.new(
|
92
|
+
template_file_path,
|
93
|
+
template_line,
|
94
|
+
i,
|
95
|
+
treatment,
|
96
|
+
includee_file_path,
|
97
|
+
@inclusions
|
98
|
+
)
|
99
|
+
treatment.sub!(/^:/, '')
|
100
|
+
case treatment
|
101
|
+
when 'markdown'
|
102
|
+
check_includee(inclusion)
|
103
|
+
check_circularity(inclusion)
|
104
|
+
@inclusions.push(inclusion)
|
105
|
+
includee_lines = include_markdown(File.absolute_path(includee_file_path))
|
106
|
+
markdown_lines.concat(includee_lines)
|
107
|
+
when 'comment'
|
108
|
+
text = File.read(includee_file_path)
|
109
|
+
markdown_lines.push(MarkdownHelper.comment(text))
|
110
|
+
@inclusions.push(inclusion)
|
111
|
+
when 'pre'
|
112
|
+
text = File.read(includee_file_path)
|
113
|
+
markdown_lines.push(MarkdownHelper.pre(text))
|
114
|
+
@inclusions.push(inclusion)
|
115
|
+
else
|
116
|
+
markdown_lines.push(template_line)
|
117
|
+
next
|
118
|
+
end
|
119
|
+
@inclusions.pop
|
120
|
+
add_inclusion_comments(treatment, includee_file_path, markdown_lines)
|
118
121
|
end
|
122
|
+
markdown_lines
|
119
123
|
end
|
120
124
|
end
|
121
125
|
|
122
|
-
def
|
126
|
+
def include_page_toc(template_lines)
|
127
|
+
toc_line_index = nil
|
128
|
+
toc_title = nil
|
129
|
+
template_lines.each_with_index do |template_line, i|
|
130
|
+
match_data = template_line.match(INCLUDE_REGEXP)
|
131
|
+
next unless match_data
|
132
|
+
treatment = match_data[1]
|
133
|
+
next unless treatment == ':page_toc'
|
134
|
+
unless toc_line_index.nil?
|
135
|
+
message = 'Multiple page TOC not allowed'
|
136
|
+
raise MultiplePageTocError.new(message)
|
137
|
+
end
|
138
|
+
toc_line_index = i
|
139
|
+
toc_title = match_data[2]
|
140
|
+
title_regexp = /^\#{1,6}\s/
|
141
|
+
unless toc_title.match(title_regexp)
|
142
|
+
message = "TOC title must be a valid markdown header, not #{toc_title}"
|
143
|
+
raise InvalidTocTitleError.new(message)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
return template_lines unless toc_line_index
|
147
|
+
toc_lines = [toc_title]
|
123
148
|
first_heading_level = nil
|
124
|
-
|
149
|
+
template_lines.each_with_index do |input_line, i|
|
150
|
+
next if i < toc_line_index
|
125
151
|
line = input_line.chomp
|
126
152
|
heading = Heading.parse(line)
|
127
153
|
next unless heading
|
128
154
|
first_heading_level ||= heading.level
|
129
155
|
indentation = ' ' * (heading.level - first_heading_level)
|
130
|
-
|
131
|
-
|
156
|
+
toc_line = "#{indentation}- #{heading.link}"
|
157
|
+
toc_lines.push(toc_line)
|
132
158
|
end
|
159
|
+
template_lines.delete_at(toc_line_index)
|
160
|
+
template_lines.insert(toc_line_index, *toc_lines)
|
161
|
+
template_lines
|
133
162
|
end
|
134
163
|
|
135
|
-
def
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
unless match_data
|
141
|
-
markdown_lines.push(input_line)
|
164
|
+
def include_all(template_file_path, template_lines, output_lines)
|
165
|
+
template_lines.each_with_index do |template_line, i|
|
166
|
+
treatment, includee_file_path = *parse_include(template_line)
|
167
|
+
if treatment.nil?
|
168
|
+
output_lines.push(template_line)
|
142
169
|
next
|
143
170
|
end
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
treatment
|
171
|
+
inclusion = Inclusion.new(
|
172
|
+
template_file_path,
|
173
|
+
template_line,
|
174
|
+
i,
|
175
|
+
treatment,
|
176
|
+
includee_file_path,
|
177
|
+
@inclusions
|
152
178
|
)
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
unless page_toc_inclusion.nil?
|
166
|
-
message = 'Only one page TOC allowed.'
|
167
|
-
raise MultiplePageTocError.new(message)
|
168
|
-
end
|
169
|
-
page_toc_inclusion = new_inclusion
|
170
|
-
toc_title = match_data[2]
|
171
|
-
title_regexp = /^\#{1,6}\s/
|
172
|
-
unless toc_title.match(title_regexp)
|
173
|
-
message = "TOC title must be a valid markdown header, not #{toc_title}"
|
174
|
-
raise InvalidTocTitleError.new(message)
|
175
|
-
end
|
176
|
-
page_toc_inclusion.page_toc_title = toc_title
|
177
|
-
page_toc_inclusion.page_toc_line = input_line
|
178
|
-
markdown_lines.push(input_line)
|
179
|
-
else
|
180
|
-
markdown_lines.push(input_line)
|
181
|
-
end
|
182
|
-
end
|
183
|
-
# If needed, create page TOC and insert into markdown_lines.
|
184
|
-
unless page_toc_inclusion.nil?
|
185
|
-
toc_lines = [
|
186
|
-
page_toc_inclusion.page_toc_title + "\n",
|
187
|
-
'',
|
188
|
-
]
|
189
|
-
page_toc_index = markdown_lines.index(page_toc_inclusion.page_toc_line)
|
190
|
-
lines_to_scan = markdown_lines[page_toc_index + 1..-1]
|
191
|
-
_create_page_toc(lines_to_scan, toc_lines)
|
192
|
-
markdown_lines.delete_at(page_toc_index)
|
193
|
-
markdown_lines.insert(page_toc_index, *toc_lines)
|
179
|
+
check_includee(inclusion)
|
180
|
+
@inclusions.push(inclusion)
|
181
|
+
file_marker = format('```%s```:', File.basename(includee_file_path))
|
182
|
+
begin_backticks = '```'
|
183
|
+
end_backticks = '```'
|
184
|
+
begin_backticks += treatment unless treatment.start_with?(':')
|
185
|
+
includee_lines = File.read(includee_file_path).split("\n")
|
186
|
+
includee_lines.unshift(begin_backticks)
|
187
|
+
includee_lines.unshift(file_marker)
|
188
|
+
includee_lines.push(end_backticks)
|
189
|
+
add_inclusion_comments(treatment.sub(':', ''), includee_file_path, includee_lines)
|
190
|
+
output_lines.concat(includee_lines)
|
194
191
|
end
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
new_inclusion = Inclusion.new(
|
205
|
-
markdown_line.chomp,
|
206
|
-
includer_file_path,
|
207
|
-
line_index + 1,
|
208
|
-
cited_includee_file_path,
|
209
|
-
treatment
|
210
|
-
)
|
211
|
-
inclusions.include(
|
212
|
-
new_inclusion,
|
213
|
-
output_lines,
|
214
|
-
self
|
215
|
-
)
|
192
|
+
end
|
193
|
+
|
194
|
+
def add_inclusion_comments(treatment, includee_file_path, lines)
|
195
|
+
path_in_project = MarkdownHelper.path_in_project(includee_file_path)
|
196
|
+
unless pristine
|
197
|
+
comment = format(' >>>>>> BEGIN INCLUDED FILE (%s): SOURCE %s ', treatment, path_in_project)
|
198
|
+
lines.unshift(MarkdownHelper.comment(comment))
|
199
|
+
comment = format(' <<<<<< END INCLUDED FILE (%s): SOURCE %s ', treatment, path_in_project)
|
200
|
+
lines.push(MarkdownHelper.comment(comment))
|
216
201
|
end
|
217
202
|
end
|
218
203
|
|
204
|
+
def parse_include(line)
|
205
|
+
match_data = line.match(INCLUDE_REGEXP)
|
206
|
+
return [nil, nil] unless match_data
|
207
|
+
treatment = match_data[1]
|
208
|
+
includee_file_path = match_data[2]
|
209
|
+
[treatment, includee_file_path]
|
210
|
+
end
|
211
|
+
|
212
|
+
def self.path_in_project(file_path)
|
213
|
+
abs_path = File.absolute_path(file_path)
|
214
|
+
abs_path.sub(self.git_clone_dir_path + '/', '')
|
215
|
+
end
|
216
|
+
|
217
|
+
def self.comment(text)
|
218
|
+
"<!--#{text}-->"
|
219
|
+
end
|
220
|
+
|
221
|
+
def self.pre(text)
|
222
|
+
"<pre>\n#{text}</pre>"
|
223
|
+
end
|
224
|
+
|
219
225
|
def self.git_clone_dir_path
|
220
226
|
git_dir = `git rev-parse --show-toplevel`.chomp
|
221
227
|
unless $?.success?
|
@@ -229,157 +235,122 @@ EOT
|
|
229
235
|
git_dir
|
230
236
|
end
|
231
237
|
|
232
|
-
|
233
|
-
path.sub(MarkdownHelper.git_clone_dir_path + '/', '')
|
234
|
-
end
|
238
|
+
class Heading
|
235
239
|
|
236
|
-
|
240
|
+
attr_accessor :level, :title
|
237
241
|
|
238
|
-
|
242
|
+
def initialize(level, title)
|
243
|
+
self.level = level
|
244
|
+
self.title = title
|
245
|
+
end
|
239
246
|
|
240
|
-
def
|
241
|
-
|
247
|
+
def self.parse(line)
|
248
|
+
# Four leading spaces not allowed (but three are allowed).
|
249
|
+
return nil if line.start_with?(' ' * 4)
|
250
|
+
stripped_line = line.sub(/^ */, '')
|
251
|
+
# Now must begin with hash marks and space.
|
252
|
+
return nil unless stripped_line.match(/^#+ /)
|
253
|
+
hash_marks, title = stripped_line.split(' ', 2)
|
254
|
+
level = hash_marks.size
|
255
|
+
# Seventh level heading not allowed.
|
256
|
+
return nil if level > 6
|
257
|
+
self.new(level, title)
|
242
258
|
end
|
243
259
|
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
:markdown
|
254
|
-
when ':verbatim'
|
255
|
-
message = "Treatment ':verbatim' is deprecated; please use treatment ':markdown'."
|
256
|
-
warn(message)
|
257
|
-
:markdown
|
258
|
-
when ':comment'
|
259
|
-
:comment
|
260
|
-
when ':pre'
|
261
|
-
:pre
|
262
|
-
else
|
263
|
-
new_inclusion.treatment
|
264
|
-
end
|
265
|
-
if treatment == :markdown
|
266
|
-
check_circularity(new_inclusion)
|
267
|
-
end
|
268
|
-
includee_path_in_project = MarkdownHelper.path_in_project(new_inclusion.absolute_includee_file_path)
|
269
|
-
output_lines.push(MarkdownHelper.comment(" >>>>>> BEGIN INCLUDED FILE (#{treatment}): SOURCE #{includee_path_in_project} ")) unless markdown_helper.pristine
|
270
|
-
begin
|
271
|
-
include_lines = File.readlines(new_inclusion.absolute_includee_file_path)
|
272
|
-
rescue => e
|
273
|
-
inclusions.push(new_inclusion)
|
274
|
-
message = [
|
275
|
-
MISSING_INCLUDEE_EXCEPTION_LABEL,
|
276
|
-
backtrace_inclusions,
|
277
|
-
].join("\n")
|
278
|
-
e = UnreadableInputError.new(message)
|
279
|
-
e.set_backtrace([])
|
280
|
-
raise e
|
281
|
-
end
|
282
|
-
last_line = include_lines.last
|
283
|
-
unless last_line && last_line.match("\n")
|
284
|
-
message = "Warning: Included file has no trailing newline: #{new_inclusion.cited_includee_file_path}"
|
285
|
-
warn(message)
|
286
|
-
end
|
287
|
-
case treatment
|
288
|
-
when :markdown
|
289
|
-
# Pass through unadorned, but honor any nested includes.
|
290
|
-
inclusions.push(new_inclusion)
|
291
|
-
markdown_helper.send(:include_files, new_inclusion.absolute_includee_file_path, include_lines, output_lines, self)
|
292
|
-
inclusions.pop
|
293
|
-
when :comment
|
294
|
-
output_lines.push(MarkdownHelper.comment(include_lines.join('')))
|
295
|
-
when :pre
|
296
|
-
output_lines.push("<pre>\n")
|
297
|
-
output_lines.push(include_lines.join(''))
|
298
|
-
output_lines.push("</pre>\n")
|
299
|
-
else
|
300
|
-
# Use the file name as a label.
|
301
|
-
file_name_line = format("```%s```:\n", File.basename(new_inclusion.cited_includee_file_path))
|
302
|
-
output_lines.push(file_name_line)
|
303
|
-
# Put into code block.
|
304
|
-
language = treatment == :code_block ? '' : treatment
|
305
|
-
output_lines.push("```#{language}\n")
|
306
|
-
output_lines.push(*include_lines)
|
307
|
-
output_lines.push("```\n")
|
308
|
-
end
|
309
|
-
output_lines.push(MarkdownHelper.comment(" <<<<<< END INCLUDED FILE (#{treatment}): SOURCE #{includee_path_in_project} ")) unless markdown_helper.pristine
|
260
|
+
|
261
|
+
def link
|
262
|
+
remove_regexp = /[\#\(\)\[\]\{\}\.\?\+\*\`\"\']+/
|
263
|
+
to_hyphen_regexp = /\W+/
|
264
|
+
anchor = title.
|
265
|
+
gsub(remove_regexp, '').
|
266
|
+
gsub(to_hyphen_regexp, '-').
|
267
|
+
downcase
|
268
|
+
"[#{title}](##{anchor})"
|
310
269
|
end
|
311
270
|
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
backtrace_inclusions,
|
327
|
-
].join("\n")
|
328
|
-
e = MarkdownHelper::CircularIncludeError.new(message)
|
329
|
-
e.set_backtrace([])
|
330
|
-
raise e
|
331
|
-
end
|
271
|
+
end
|
272
|
+
|
273
|
+
def check_circularity(inclusion)
|
274
|
+
included_file_paths = @inclusions.collect { |x| x.includee_real_file_path}
|
275
|
+
previously_included = included_file_paths.include?(inclusion.includee_real_file_path)
|
276
|
+
if previously_included
|
277
|
+
@inclusions.push(inclusion)
|
278
|
+
message = [
|
279
|
+
'Includes are circular:',
|
280
|
+
MarkdownHelper.backtrace_inclusions(@inclusions),
|
281
|
+
].join("\n")
|
282
|
+
e = MarkdownHelper::CircularIncludeError.new(message)
|
283
|
+
e.set_backtrace([])
|
284
|
+
raise e
|
332
285
|
end
|
286
|
+
end
|
333
287
|
|
334
|
-
|
335
|
-
|
336
|
-
inclusions.
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
288
|
+
def check_includee(inclusion)
|
289
|
+
unless File.readable?(inclusion.includee_absolute_file_path)
|
290
|
+
@inclusions.push(inclusion)
|
291
|
+
message = [
|
292
|
+
'Could not read includee file:',
|
293
|
+
MarkdownHelper.backtrace_inclusions(@inclusions),
|
294
|
+
].join("\n")
|
295
|
+
e = MarkdownHelper::UnreadableIncludeeError.new(message)
|
296
|
+
e.set_backtrace([])
|
297
|
+
raise e
|
342
298
|
end
|
343
299
|
|
344
300
|
end
|
345
301
|
|
346
|
-
|
302
|
+
def self.backtrace_inclusions(inclusions)
|
303
|
+
lines = [' Backtrace (innermost include first):']
|
304
|
+
inclusions.reverse.each_with_index do |inclusion, i|
|
305
|
+
lines.push("#{' Level'} #{i}:")
|
306
|
+
level_lines = inclusion.to_lines(indentation_level = 3)
|
307
|
+
lines.push(*level_lines)
|
308
|
+
end
|
309
|
+
lines.join("\n")
|
310
|
+
end
|
347
311
|
|
348
|
-
|
312
|
+
class Inclusion
|
349
313
|
|
350
314
|
attr_accessor \
|
351
315
|
:includer_file_path,
|
316
|
+
:includer_absolute_file_path,
|
317
|
+
:include_pragma,
|
318
|
+
:treatment,
|
352
319
|
:includer_line_number,
|
353
|
-
:include_description,
|
354
|
-
:absolute_includee_file_path,
|
355
320
|
:cited_includee_file_path,
|
356
|
-
:
|
357
|
-
:page_toc_title,
|
358
|
-
:page_toc_line
|
321
|
+
:includee_absolute_file_path
|
359
322
|
|
360
323
|
def initialize(
|
361
|
-
include_description,
|
362
324
|
includer_file_path,
|
325
|
+
include_pragma,
|
363
326
|
includer_line_number,
|
327
|
+
treatment,
|
364
328
|
cited_includee_file_path,
|
365
|
-
|
366
|
-
|
367
|
-
self.include_description = include_description
|
329
|
+
inclusions
|
330
|
+
)
|
368
331
|
self.includer_file_path = includer_file_path
|
332
|
+
self.include_pragma = include_pragma
|
369
333
|
self.includer_line_number = includer_line_number
|
370
|
-
self.cited_includee_file_path = cited_includee_file_path
|
371
|
-
self.absolute_includee_file_path = absolute_includee_file_path
|
372
334
|
self.treatment = treatment
|
373
|
-
self.
|
335
|
+
self.cited_includee_file_path = cited_includee_file_path
|
336
|
+
|
337
|
+
self.includer_absolute_file_path = File.absolute_path(includer_file_path)
|
338
|
+
unless File.exist?(self.includer_absolute_file_path)
|
339
|
+
fail self.includer_absolute_file_path
|
340
|
+
end
|
341
|
+
|
342
|
+
self.includee_absolute_file_path = File.absolute_path(File.join(
|
374
343
|
File.dirname(includer_file_path),
|
375
344
|
cited_includee_file_path,
|
376
|
-
|
345
|
+
))
|
346
|
+
end
|
347
|
+
|
348
|
+
def includer_real_file_path
|
349
|
+
Pathname.new(includer_absolute_file_path).realpath.to_s
|
377
350
|
end
|
378
351
|
|
379
|
-
def
|
380
|
-
|
381
|
-
return nil unless File.exist?(absolute_includee_file_path)
|
382
|
-
Pathname.new(absolute_includee_file_path).realpath.to_s
|
352
|
+
def includee_real_file_path
|
353
|
+
Pathname.new(includee_absolute_file_path).realpath.to_s
|
383
354
|
end
|
384
355
|
|
385
356
|
def indentation(level)
|
@@ -388,11 +359,11 @@ EOT
|
|
388
359
|
|
389
360
|
def to_lines(indentation_level)
|
390
361
|
relative_inluder_file_path = MarkdownHelper.path_in_project(includer_file_path)
|
391
|
-
relative_inludee_file_path = MarkdownHelper.path_in_project(
|
362
|
+
relative_inludee_file_path = MarkdownHelper.path_in_project(includee_absolute_file_path)
|
392
363
|
text = <<EOT
|
393
364
|
#{indentation(indentation_level)}Includer:
|
394
365
|
#{indentation(indentation_level+1)}Location: #{relative_inluder_file_path}:#{includer_line_number}
|
395
|
-
#{indentation(indentation_level+1)}Include
|
366
|
+
#{indentation(indentation_level+1)}Include pragma: #{include_pragma}
|
396
367
|
#{indentation(indentation_level)}Includee:
|
397
368
|
#{indentation(indentation_level+1)}File path: #{relative_inludee_file_path}
|
398
369
|
EOT
|
@@ -402,4 +373,3 @@ EOT
|
|
402
373
|
end
|
403
374
|
|
404
375
|
end
|
405
|
-
|