markdown_helper 2.3.0 → 2.4.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/README.md +24 -17
- data/bin/_run_irb +46 -0
- data/lib/markdown_helper.rb +3 -384
- data/lib/markdown_helper/markdown_helper.rb +79 -0
- data/lib/markdown_helper/markdown_includer.rb +315 -0
- data/lib/markdown_helper/markdown_irb_runner.rb +65 -0
- data/lib/markdown_helper/version.rb +1 -1
- data/markdown/readme/README.template.md +21 -16
- data/markdown/use_cases/Rakefile +9 -2
- data/markdown/use_cases/include/diagnose_circular_includes/diagnose_circular_includes.err +26 -0
- data/markdown/use_cases/{include_files → include}/diagnose_circular_includes/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/diagnose_circular_includes/includer_0.md +0 -0
- data/markdown/use_cases/{include_files → include}/diagnose_circular_includes/includer_1.md +0 -0
- data/markdown/use_cases/{include_files → include}/diagnose_circular_includes/includer_2.md +0 -0
- data/markdown/use_cases/{include_files → include}/diagnose_circular_includes/use_case.md +8 -8
- data/markdown/use_cases/{include_files → include}/diagnose_circular_includes/use_case_template.md +0 -0
- data/markdown/use_cases/include/diagnose_missing_includee/diagnose_missing_includee.err +26 -0
- data/markdown/use_cases/{include_files → include}/diagnose_missing_includee/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/diagnose_missing_includee/includer_0.md +0 -0
- data/markdown/use_cases/{include_files → include}/diagnose_missing_includee/includer_1.md +0 -0
- data/markdown/use_cases/{include_files → include}/diagnose_missing_includee/includer_2.md +0 -0
- data/markdown/use_cases/{include_files → include}/diagnose_missing_includee/use_case.md +8 -8
- data/markdown/use_cases/{include_files → include}/diagnose_missing_includee/use_case_template.md +0 -0
- data/markdown/use_cases/{include_files → include}/include.rb +0 -0
- data/markdown/use_cases/{include_files → include}/include_code_block/hello.rb +0 -0
- data/markdown/use_cases/{include_files → include}/include_code_block/included.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_code_block/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_code_block/use_case.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_code_block/use_case_template.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_generated_text/use_case.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_generated_text/use_case_template.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_highlighted_code/hello.rb +0 -0
- data/markdown/use_cases/{include_files → include}/include_highlighted_code/included.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_highlighted_code/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_highlighted_code/use_case.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_highlighted_code/use_case_template.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_markdown/included.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_markdown/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_markdown/markdown.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_markdown/use_case.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_markdown/use_case_template.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_page_toc/included.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_page_toc/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_page_toc/markdown_0.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_page_toc/markdown_1.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_page_toc/use_case.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_page_toc/use_case_template.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_comment/hello.rb +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_comment/included.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_comment/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_comment/use_case.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_comment/use_case_template.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_details/details.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_details/included.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_details/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_details/use_case.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_details/use_case_template.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_pre/included.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_pre/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_pre/triple_backtick.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_pre/use_case.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_pre/use_case_template.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_with_added_comments/included.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_with_added_comments/includee.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_with_added_comments/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_with_added_comments/use_case.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_with_added_comments/use_case_template.md +0 -0
- data/markdown/use_cases/{include_files → include}/interface.md +0 -0
- data/markdown/use_cases/{include_files → include}/nest_inclusions/included.md +0 -0
- data/markdown/use_cases/{include_files → include}/nest_inclusions/includee.md +0 -0
- data/markdown/use_cases/{include_files → include}/nest_inclusions/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/nest_inclusions/nested_includee.md +0 -0
- data/markdown/use_cases/{include_files → include}/nest_inclusions/use_case.md +0 -0
- data/markdown/use_cases/{include_files → include}/nest_inclusions/use_case_template.md +0 -0
- data/markdown/use_cases/{include_files → include}/reuse_text/included.md +0 -0
- data/markdown/use_cases/{include_files → include}/reuse_text/includee.md +0 -0
- data/markdown/use_cases/{include_files → include}/reuse_text/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/reuse_text/use_case.md +0 -0
- data/markdown/use_cases/{include_files → include}/reuse_text/use_case_template.md +0 -0
- data/markdown/use_cases/run_irb/interface.md +16 -0
- data/markdown/use_cases/run_irb/run_irb.rb +5 -0
- data/markdown/use_cases/run_irb/run_irb/markdown.md +43 -0
- data/markdown/use_cases/run_irb/run_irb/template.md +37 -0
- data/markdown/use_cases/run_irb/run_irb/use_case.md +178 -0
- data/markdown/use_cases/run_irb/run_irb/use_case_template.md +33 -0
- data/markdown/use_cases/use_cases.md +17 -14
- metadata +82 -72
- data/markdown/use_cases/include_files/diagnose_circular_includes/diagnose_circular_includes.err +0 -26
- data/markdown/use_cases/include_files/diagnose_missing_includee/diagnose_missing_includee.err +0 -26
@@ -0,0 +1,79 @@
|
|
1
|
+
class MarkdownHelper
|
2
|
+
|
3
|
+
attr_accessor :pristine
|
4
|
+
|
5
|
+
class MarkdownHelperError < RuntimeError; end
|
6
|
+
class OptionError < MarkdownHelperError; end
|
7
|
+
class MultiplePageTocError < MarkdownHelperError; end
|
8
|
+
class UnreadableTemplateError < MarkdownHelperError; end
|
9
|
+
class UnwritableMarkdownError < MarkdownHelperError; end
|
10
|
+
class InvalidTocTitleError < MarkdownHelperError; end
|
11
|
+
class CircularIncludeError < MarkdownHelperError; end
|
12
|
+
class UnreadableIncludeeError < MarkdownHelperError; end
|
13
|
+
|
14
|
+
def MarkdownHelper.git_clone_dir_path
|
15
|
+
git_dir = `git rev-parse --show-toplevel`.chomp
|
16
|
+
unless $?.success?
|
17
|
+
message = <<EOT
|
18
|
+
|
19
|
+
Markdown helper must run inside a .git project.
|
20
|
+
That is, the working directory one of its parents must be a .git directory.
|
21
|
+
EOT
|
22
|
+
raise RuntimeError.new(message)
|
23
|
+
end
|
24
|
+
git_dir
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(options = {})
|
28
|
+
# Confirm that we're in a git project.
|
29
|
+
# This is necessary so that we can prune file paths in the tests,
|
30
|
+
# which otherwise would fail because of differing installation directories.
|
31
|
+
# It also allows pruned paths to be used in the inserted comments (when not pristine).
|
32
|
+
MarkdownHelper.git_clone_dir_path
|
33
|
+
default_options = {
|
34
|
+
:pristine => false,
|
35
|
+
}
|
36
|
+
merged_options = default_options.merge(options)
|
37
|
+
merged_options.each_pair do |method, value|
|
38
|
+
unless self.respond_to?(method)
|
39
|
+
raise OptionError.new("Unknown option: #{method}")
|
40
|
+
end
|
41
|
+
setter_method = "#{method}="
|
42
|
+
send(setter_method, value)
|
43
|
+
merged_options.delete(method)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def generate_file(method, template_file_path, markdown_file_path)
|
48
|
+
template_path_in_project = MarkdownHelper.path_in_project(template_file_path)
|
49
|
+
output_lines = []
|
50
|
+
yield output_lines
|
51
|
+
unless pristine
|
52
|
+
output_lines.unshift(MarkdownHelper.comment(" >>>>>> BEGIN GENERATED FILE (#{method}): SOURCE #{template_path_in_project} "))
|
53
|
+
output_lines.push(MarkdownHelper.comment(" <<<<<< END GENERATED FILE (#{method}): SOURCE #{template_path_in_project} "))
|
54
|
+
end
|
55
|
+
output_lines.push('')
|
56
|
+
output = output_lines.join("\n")
|
57
|
+
File.write(markdown_file_path, output)
|
58
|
+
end
|
59
|
+
|
60
|
+
def run_irb(template_file_path, markdown_file_path)
|
61
|
+
irb_runner = MarkdownIrbRunner.new(:pristine => pristine)
|
62
|
+
irb_runner.run_irb(template_file_path, markdown_file_path)
|
63
|
+
end
|
64
|
+
|
65
|
+
def include(template_file_path, markdown_file_path)
|
66
|
+
includer = MarkdownIncluder.new(:pristine => pristine)
|
67
|
+
includer.include(template_file_path, markdown_file_path)
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.comment(text)
|
71
|
+
"<!--#{text}-->"
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.path_in_project(file_path)
|
75
|
+
abs_path = File.absolute_path(file_path)
|
76
|
+
abs_path.sub(MarkdownHelper.git_clone_dir_path + '/', '')
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,315 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
class MarkdownIncluder < MarkdownHelper
|
4
|
+
|
5
|
+
INCLUDE_REGEXP = /^@\[([^\[]+)\]\(([^)]+)\)$/
|
6
|
+
INCLUDE_MARKDOWN_REGEXP = /^@\[:markdown\]\(([^)]+)\)$/
|
7
|
+
|
8
|
+
def include(template_file_path, markdown_file_path)
|
9
|
+
@inclusions = []
|
10
|
+
generate_file(:include, template_file_path, markdown_file_path) do |output_lines|
|
11
|
+
Dir.chdir(File.dirname(template_file_path)) do
|
12
|
+
markdown_lines = include_markdown(template_file_path)
|
13
|
+
markdown_lines = include_page_toc(markdown_lines)
|
14
|
+
include_all(template_file_path, markdown_lines, output_lines)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
def MarkdownIncluder.pre(text)
|
21
|
+
"<pre>\n#{text}</pre>"
|
22
|
+
end
|
23
|
+
|
24
|
+
def MarkdownIncluder.details(text)
|
25
|
+
"<details>\n#{text}</details>"
|
26
|
+
end
|
27
|
+
|
28
|
+
def include_markdown(template_file_path)
|
29
|
+
Dir.chdir(File.dirname(template_file_path)) do
|
30
|
+
markdown_lines = []
|
31
|
+
unless File.readable?(template_file_path)
|
32
|
+
path_in_project = MarkdownHelper.path_in_project(template_file_path )
|
33
|
+
message = [
|
34
|
+
"Could not read template file: #{path_in_project}",
|
35
|
+
MarkdownIncluder.backtrace_inclusions(@inclusions),
|
36
|
+
].join("\n")
|
37
|
+
e = UnreadableTemplateError.new(message)
|
38
|
+
e.set_backtrace([])
|
39
|
+
raise e
|
40
|
+
end
|
41
|
+
template_lines = File.readlines(template_file_path)
|
42
|
+
template_lines.each_with_index do |template_line, i|
|
43
|
+
template_line.chomp!
|
44
|
+
treatment, includee_file_path = *parse_include(template_line)
|
45
|
+
if treatment.nil?
|
46
|
+
markdown_lines.push(template_line)
|
47
|
+
next
|
48
|
+
end
|
49
|
+
if treatment == ':page_toc'
|
50
|
+
markdown_lines.push(template_line)
|
51
|
+
next
|
52
|
+
end
|
53
|
+
inclusion = Inclusion.new(
|
54
|
+
template_file_path,
|
55
|
+
template_line,
|
56
|
+
i,
|
57
|
+
treatment,
|
58
|
+
includee_file_path,
|
59
|
+
@inclusions
|
60
|
+
)
|
61
|
+
case treatment
|
62
|
+
when ':markdown'
|
63
|
+
check_includee(inclusion)
|
64
|
+
check_circularity(inclusion)
|
65
|
+
@inclusions.push(inclusion)
|
66
|
+
includee_lines = include_markdown(File.absolute_path(includee_file_path))
|
67
|
+
markdown_lines.concat(includee_lines)
|
68
|
+
when ':comment'
|
69
|
+
text = File.read(includee_file_path)
|
70
|
+
markdown_lines.push(MarkdownHelper.comment(text))
|
71
|
+
@inclusions.push(inclusion)
|
72
|
+
when ':pre'
|
73
|
+
text = File.read(includee_file_path)
|
74
|
+
markdown_lines.push(MarkdownIncluder.pre(text))
|
75
|
+
@inclusions.push(inclusion)
|
76
|
+
when ':details'
|
77
|
+
text = File.read(includee_file_path)
|
78
|
+
markdown_lines.push(MarkdownIncluder.details(text))
|
79
|
+
@inclusions.push(inclusion)
|
80
|
+
else
|
81
|
+
markdown_lines.push(template_line)
|
82
|
+
next
|
83
|
+
end
|
84
|
+
@inclusions.pop
|
85
|
+
treatment.sub!(/^:/, '')
|
86
|
+
add_inclusion_comments(treatment, includee_file_path, markdown_lines)
|
87
|
+
end
|
88
|
+
markdown_lines
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def include_page_toc(template_lines)
|
93
|
+
toc_line_index = nil
|
94
|
+
toc_title = nil
|
95
|
+
template_lines.each_with_index do |template_line, i|
|
96
|
+
match_data = template_line.match(INCLUDE_REGEXP)
|
97
|
+
next unless match_data
|
98
|
+
treatment = match_data[1]
|
99
|
+
next unless treatment == ':page_toc'
|
100
|
+
unless toc_line_index.nil?
|
101
|
+
message = 'Multiple page TOC not allowed'
|
102
|
+
raise MultiplePageTocError.new(message)
|
103
|
+
end
|
104
|
+
toc_line_index = i
|
105
|
+
toc_title = match_data[2]
|
106
|
+
title_regexp = /^\#{1,6}\s/
|
107
|
+
unless toc_title.match(title_regexp)
|
108
|
+
message = "TOC title must be a valid markdown header, not #{toc_title}"
|
109
|
+
raise InvalidTocTitleError.new(message)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
return template_lines unless toc_line_index
|
113
|
+
toc_lines = [toc_title]
|
114
|
+
first_heading_level = nil
|
115
|
+
template_lines.each_with_index do |input_line, i|
|
116
|
+
next if i < toc_line_index
|
117
|
+
line = input_line.chomp
|
118
|
+
heading = Heading.parse(line)
|
119
|
+
next unless heading
|
120
|
+
first_heading_level ||= heading.level
|
121
|
+
indentation = ' ' * (heading.level - first_heading_level)
|
122
|
+
toc_line = "#{indentation}- #{heading.link}"
|
123
|
+
toc_lines.push(toc_line)
|
124
|
+
end
|
125
|
+
template_lines.delete_at(toc_line_index)
|
126
|
+
template_lines.insert(toc_line_index, *toc_lines)
|
127
|
+
template_lines
|
128
|
+
end
|
129
|
+
|
130
|
+
def include_all(template_file_path, template_lines, output_lines)
|
131
|
+
template_lines.each_with_index do |template_line, i|
|
132
|
+
treatment, includee_file_path = *parse_include(template_line)
|
133
|
+
if treatment.nil?
|
134
|
+
output_lines.push(template_line)
|
135
|
+
next
|
136
|
+
end
|
137
|
+
inclusion = Inclusion.new(
|
138
|
+
template_file_path,
|
139
|
+
template_line,
|
140
|
+
i,
|
141
|
+
treatment,
|
142
|
+
includee_file_path,
|
143
|
+
@inclusions
|
144
|
+
)
|
145
|
+
check_includee(inclusion)
|
146
|
+
@inclusions.push(inclusion)
|
147
|
+
file_marker = format('```%s```:', File.basename(includee_file_path))
|
148
|
+
begin_backticks = '```'
|
149
|
+
end_backticks = '```'
|
150
|
+
begin_backticks += treatment unless treatment.start_with?(':')
|
151
|
+
includee_lines = File.read(includee_file_path).split("\n")
|
152
|
+
includee_lines.unshift(begin_backticks)
|
153
|
+
includee_lines.unshift(file_marker)
|
154
|
+
includee_lines.push(end_backticks)
|
155
|
+
add_inclusion_comments(treatment.sub(':', ''), includee_file_path, includee_lines)
|
156
|
+
output_lines.concat(includee_lines)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def add_inclusion_comments(treatment, includee_file_path, lines)
|
161
|
+
path_in_project = MarkdownHelper.path_in_project(includee_file_path)
|
162
|
+
unless pristine
|
163
|
+
comment = format(' >>>>>> BEGIN INCLUDED FILE (%s): SOURCE %s ', treatment, path_in_project)
|
164
|
+
lines.unshift(MarkdownHelper.comment(comment))
|
165
|
+
comment = format(' <<<<<< END INCLUDED FILE (%s): SOURCE %s ', treatment, path_in_project)
|
166
|
+
lines.push(MarkdownHelper.comment(comment))
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def parse_include(line)
|
171
|
+
match_data = line.match(INCLUDE_REGEXP)
|
172
|
+
return [nil, nil] unless match_data
|
173
|
+
treatment = match_data[1]
|
174
|
+
includee_file_path = match_data[2]
|
175
|
+
[treatment, includee_file_path]
|
176
|
+
end
|
177
|
+
|
178
|
+
class Heading
|
179
|
+
|
180
|
+
attr_accessor :level, :title
|
181
|
+
|
182
|
+
def initialize(level, title)
|
183
|
+
self.level = level
|
184
|
+
self.title = title
|
185
|
+
end
|
186
|
+
|
187
|
+
def self.parse(line)
|
188
|
+
# Four leading spaces not allowed (but three are allowed).
|
189
|
+
return nil if line.start_with?(' ' * 4)
|
190
|
+
stripped_line = line.sub(/^ */, '')
|
191
|
+
# Now must begin with hash marks and space.
|
192
|
+
return nil unless stripped_line.match(/^#+ /)
|
193
|
+
hash_marks, title = stripped_line.split(' ', 2)
|
194
|
+
level = hash_marks.size
|
195
|
+
# Seventh level heading not allowed.
|
196
|
+
return nil if level > 6
|
197
|
+
self.new(level, title)
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
def link
|
202
|
+
remove_regexp = /[\#\(\)\[\]\{\}\.\?\+\*\`\"\']+/
|
203
|
+
to_hyphen_regexp = /\W+/
|
204
|
+
anchor = title.
|
205
|
+
gsub(remove_regexp, '').
|
206
|
+
gsub(to_hyphen_regexp, '-').
|
207
|
+
downcase
|
208
|
+
"[#{title}](##{anchor})"
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
212
|
+
|
213
|
+
def check_circularity(inclusion)
|
214
|
+
included_file_paths = @inclusions.collect { |x| x.includee_real_file_path}
|
215
|
+
previously_included = included_file_paths.include?(inclusion.includee_real_file_path)
|
216
|
+
if previously_included
|
217
|
+
@inclusions.push(inclusion)
|
218
|
+
message = [
|
219
|
+
'Includes are circular:',
|
220
|
+
MarkdownIncluder.backtrace_inclusions(@inclusions),
|
221
|
+
].join("\n")
|
222
|
+
e = CircularIncludeError.new(message)
|
223
|
+
e.set_backtrace([])
|
224
|
+
raise e
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def check_includee(inclusion)
|
229
|
+
unless File.readable?(inclusion.includee_absolute_file_path)
|
230
|
+
@inclusions.push(inclusion)
|
231
|
+
message = [
|
232
|
+
'Could not read includee file:',
|
233
|
+
MarkdownIncluder.backtrace_inclusions(@inclusions),
|
234
|
+
].join("\n")
|
235
|
+
e = UnreadableIncludeeError.new(message)
|
236
|
+
e.set_backtrace([])
|
237
|
+
raise e
|
238
|
+
end
|
239
|
+
|
240
|
+
end
|
241
|
+
|
242
|
+
def self.backtrace_inclusions(inclusions)
|
243
|
+
lines = [' Backtrace (innermost include first):']
|
244
|
+
inclusions.reverse.each_with_index do |inclusion, i|
|
245
|
+
lines.push("#{' Level'} #{i}:")
|
246
|
+
level_lines = inclusion.to_lines(indentation_level = 3)
|
247
|
+
lines.push(*level_lines)
|
248
|
+
end
|
249
|
+
lines.join("\n")
|
250
|
+
end
|
251
|
+
|
252
|
+
class Inclusion
|
253
|
+
|
254
|
+
attr_accessor \
|
255
|
+
:includer_file_path,
|
256
|
+
:includer_absolute_file_path,
|
257
|
+
:include_pragma,
|
258
|
+
:treatment,
|
259
|
+
:includer_line_number,
|
260
|
+
:cited_includee_file_path,
|
261
|
+
:includee_absolute_file_path
|
262
|
+
|
263
|
+
def initialize(
|
264
|
+
includer_file_path,
|
265
|
+
include_pragma,
|
266
|
+
includer_line_number,
|
267
|
+
treatment,
|
268
|
+
cited_includee_file_path,
|
269
|
+
inclusions
|
270
|
+
)
|
271
|
+
self.includer_file_path = includer_file_path
|
272
|
+
self.include_pragma = include_pragma
|
273
|
+
self.includer_line_number = includer_line_number
|
274
|
+
self.treatment = treatment
|
275
|
+
self.cited_includee_file_path = cited_includee_file_path
|
276
|
+
|
277
|
+
self.includer_absolute_file_path = File.absolute_path(includer_file_path)
|
278
|
+
unless File.exist?(self.includer_absolute_file_path)
|
279
|
+
fail self.includer_absolute_file_path
|
280
|
+
end
|
281
|
+
|
282
|
+
self.includee_absolute_file_path = File.absolute_path(File.join(
|
283
|
+
File.dirname(includer_file_path),
|
284
|
+
cited_includee_file_path,
|
285
|
+
))
|
286
|
+
end
|
287
|
+
|
288
|
+
def includer_real_file_path
|
289
|
+
Pathname.new(includer_absolute_file_path).realpath.to_s
|
290
|
+
end
|
291
|
+
|
292
|
+
def includee_real_file_path
|
293
|
+
Pathname.new(includee_absolute_file_path).realpath.to_s
|
294
|
+
end
|
295
|
+
|
296
|
+
def indentation(level)
|
297
|
+
' ' * level
|
298
|
+
end
|
299
|
+
|
300
|
+
def to_lines(indentation_level)
|
301
|
+
relative_inluder_file_path = MarkdownHelper.path_in_project(includer_file_path)
|
302
|
+
relative_inludee_file_path = MarkdownHelper.path_in_project(includee_absolute_file_path)
|
303
|
+
text = <<EOT
|
304
|
+
#{indentation(indentation_level)}Includer:
|
305
|
+
#{indentation(indentation_level+1)}Location: #{relative_inluder_file_path}:#{includer_line_number}
|
306
|
+
#{indentation(indentation_level+1)}Include pragma: #{include_pragma}
|
307
|
+
#{indentation(indentation_level)}Includee:
|
308
|
+
#{indentation(indentation_level+1)}File path: #{relative_inludee_file_path}
|
309
|
+
EOT
|
310
|
+
text.split("\n")
|
311
|
+
end
|
312
|
+
|
313
|
+
end
|
314
|
+
|
315
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
|
3
|
+
class MarkdownIrbRunner < MarkdownHelper
|
4
|
+
|
5
|
+
IrbFilterPragma = '```#run_irb'
|
6
|
+
BeginTextDirective = "=begin #{IrbFilterPragma}"
|
7
|
+
EndTextDirective = "=end #{IrbFilterPragma}"
|
8
|
+
|
9
|
+
def run_irb(template_file_path, markdown_file_path)
|
10
|
+
irb_input = make_irb_input(template_file_path)
|
11
|
+
irb_output = make_irb_output(irb_input)
|
12
|
+
markdown = make_markdown(irb_output)
|
13
|
+
File.write(markdown_file_path, markdown)
|
14
|
+
end
|
15
|
+
|
16
|
+
def make_irb_input(template_file_path)
|
17
|
+
irb_lines = []
|
18
|
+
irb_lines.push(BeginTextDirective)
|
19
|
+
source_lines = File.readlines(template_file_path)
|
20
|
+
source_lines.each do |source_line|
|
21
|
+
source_line.chomp!
|
22
|
+
if source_line == IrbFilterPragma
|
23
|
+
irb_lines.push(EndTextDirective)
|
24
|
+
elsif source_line == '```'
|
25
|
+
irb_lines.push(BeginTextDirective)
|
26
|
+
else
|
27
|
+
irb_lines.push(source_line)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
irb_lines.push(EndTextDirective)
|
31
|
+
irb_lines.push('') unless irb_lines.last.empty?
|
32
|
+
irb_lines.join("\n")
|
33
|
+
end
|
34
|
+
|
35
|
+
def make_irb_output(irb_input)
|
36
|
+
Dir.mktmpdir do |dir|
|
37
|
+
Dir.chdir(dir) do
|
38
|
+
File.write('irb_input', irb_input)
|
39
|
+
command = 'irb --noecho irb_input | tail +2 | head --lines=-2 > irb_output'
|
40
|
+
system(command )
|
41
|
+
File.read('irb_output')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def make_markdown(irb_output)
|
47
|
+
output_lines = []
|
48
|
+
irb_lines = irb_output.split("\n")
|
49
|
+
irb_lines.each_with_index do |irb_line, i|
|
50
|
+
irb_line.chomp!
|
51
|
+
if irb_line == BeginTextDirective
|
52
|
+
output_lines.push('```') unless i == 0
|
53
|
+
next
|
54
|
+
end
|
55
|
+
if irb_line == EndTextDirective
|
56
|
+
output_lines.push('```ruby') unless i == irb_lines.size - 1
|
57
|
+
next
|
58
|
+
end
|
59
|
+
output_lines.push(irb_line)
|
60
|
+
end
|
61
|
+
output_lines.push('') unless output_lines.last.nil? || output_lines.last.empty?
|
62
|
+
output_lines.join("\n")
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|