markdown_helper 2.1.0 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Gem](https://img.shields.io/gem/v/markdown_helper.svg?style=flat)](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
|
-
|