markdown_helper 2.3.0 → 2.4.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.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/README.md +24 -17
  4. data/bin/_run_irb +46 -0
  5. data/lib/markdown_helper.rb +3 -384
  6. data/lib/markdown_helper/markdown_helper.rb +79 -0
  7. data/lib/markdown_helper/markdown_includer.rb +315 -0
  8. data/lib/markdown_helper/markdown_irb_runner.rb +65 -0
  9. data/lib/markdown_helper/version.rb +1 -1
  10. data/markdown/readme/README.template.md +21 -16
  11. data/markdown/use_cases/Rakefile +9 -2
  12. data/markdown/use_cases/include/diagnose_circular_includes/diagnose_circular_includes.err +26 -0
  13. data/markdown/use_cases/{include_files → include}/diagnose_circular_includes/includer.md +0 -0
  14. data/markdown/use_cases/{include_files → include}/diagnose_circular_includes/includer_0.md +0 -0
  15. data/markdown/use_cases/{include_files → include}/diagnose_circular_includes/includer_1.md +0 -0
  16. data/markdown/use_cases/{include_files → include}/diagnose_circular_includes/includer_2.md +0 -0
  17. data/markdown/use_cases/{include_files → include}/diagnose_circular_includes/use_case.md +8 -8
  18. data/markdown/use_cases/{include_files → include}/diagnose_circular_includes/use_case_template.md +0 -0
  19. data/markdown/use_cases/include/diagnose_missing_includee/diagnose_missing_includee.err +26 -0
  20. data/markdown/use_cases/{include_files → include}/diagnose_missing_includee/includer.md +0 -0
  21. data/markdown/use_cases/{include_files → include}/diagnose_missing_includee/includer_0.md +0 -0
  22. data/markdown/use_cases/{include_files → include}/diagnose_missing_includee/includer_1.md +0 -0
  23. data/markdown/use_cases/{include_files → include}/diagnose_missing_includee/includer_2.md +0 -0
  24. data/markdown/use_cases/{include_files → include}/diagnose_missing_includee/use_case.md +8 -8
  25. data/markdown/use_cases/{include_files → include}/diagnose_missing_includee/use_case_template.md +0 -0
  26. data/markdown/use_cases/{include_files → include}/include.rb +0 -0
  27. data/markdown/use_cases/{include_files → include}/include_code_block/hello.rb +0 -0
  28. data/markdown/use_cases/{include_files → include}/include_code_block/included.md +0 -0
  29. data/markdown/use_cases/{include_files → include}/include_code_block/includer.md +0 -0
  30. data/markdown/use_cases/{include_files → include}/include_code_block/use_case.md +0 -0
  31. data/markdown/use_cases/{include_files → include}/include_code_block/use_case_template.md +0 -0
  32. data/markdown/use_cases/{include_files → include}/include_generated_text/use_case.md +0 -0
  33. data/markdown/use_cases/{include_files → include}/include_generated_text/use_case_template.md +0 -0
  34. data/markdown/use_cases/{include_files → include}/include_highlighted_code/hello.rb +0 -0
  35. data/markdown/use_cases/{include_files → include}/include_highlighted_code/included.md +0 -0
  36. data/markdown/use_cases/{include_files → include}/include_highlighted_code/includer.md +0 -0
  37. data/markdown/use_cases/{include_files → include}/include_highlighted_code/use_case.md +0 -0
  38. data/markdown/use_cases/{include_files → include}/include_highlighted_code/use_case_template.md +0 -0
  39. data/markdown/use_cases/{include_files → include}/include_markdown/included.md +0 -0
  40. data/markdown/use_cases/{include_files → include}/include_markdown/includer.md +0 -0
  41. data/markdown/use_cases/{include_files → include}/include_markdown/markdown.md +0 -0
  42. data/markdown/use_cases/{include_files → include}/include_markdown/use_case.md +0 -0
  43. data/markdown/use_cases/{include_files → include}/include_markdown/use_case_template.md +0 -0
  44. data/markdown/use_cases/{include_files → include}/include_page_toc/included.md +0 -0
  45. data/markdown/use_cases/{include_files → include}/include_page_toc/includer.md +0 -0
  46. data/markdown/use_cases/{include_files → include}/include_page_toc/markdown_0.md +0 -0
  47. data/markdown/use_cases/{include_files → include}/include_page_toc/markdown_1.md +0 -0
  48. data/markdown/use_cases/{include_files → include}/include_page_toc/use_case.md +0 -0
  49. data/markdown/use_cases/{include_files → include}/include_page_toc/use_case_template.md +0 -0
  50. data/markdown/use_cases/{include_files → include}/include_text_as_comment/hello.rb +0 -0
  51. data/markdown/use_cases/{include_files → include}/include_text_as_comment/included.md +0 -0
  52. data/markdown/use_cases/{include_files → include}/include_text_as_comment/includer.md +0 -0
  53. data/markdown/use_cases/{include_files → include}/include_text_as_comment/use_case.md +0 -0
  54. data/markdown/use_cases/{include_files → include}/include_text_as_comment/use_case_template.md +0 -0
  55. data/markdown/use_cases/{include_files → include}/include_text_as_details/details.md +0 -0
  56. data/markdown/use_cases/{include_files → include}/include_text_as_details/included.md +0 -0
  57. data/markdown/use_cases/{include_files → include}/include_text_as_details/includer.md +0 -0
  58. data/markdown/use_cases/{include_files → include}/include_text_as_details/use_case.md +0 -0
  59. data/markdown/use_cases/{include_files → include}/include_text_as_details/use_case_template.md +0 -0
  60. data/markdown/use_cases/{include_files → include}/include_text_as_pre/included.md +0 -0
  61. data/markdown/use_cases/{include_files → include}/include_text_as_pre/includer.md +0 -0
  62. data/markdown/use_cases/{include_files → include}/include_text_as_pre/triple_backtick.md +0 -0
  63. data/markdown/use_cases/{include_files → include}/include_text_as_pre/use_case.md +0 -0
  64. data/markdown/use_cases/{include_files → include}/include_text_as_pre/use_case_template.md +0 -0
  65. data/markdown/use_cases/{include_files → include}/include_with_added_comments/included.md +0 -0
  66. data/markdown/use_cases/{include_files → include}/include_with_added_comments/includee.md +0 -0
  67. data/markdown/use_cases/{include_files → include}/include_with_added_comments/includer.md +0 -0
  68. data/markdown/use_cases/{include_files → include}/include_with_added_comments/use_case.md +0 -0
  69. data/markdown/use_cases/{include_files → include}/include_with_added_comments/use_case_template.md +0 -0
  70. data/markdown/use_cases/{include_files → include}/interface.md +0 -0
  71. data/markdown/use_cases/{include_files → include}/nest_inclusions/included.md +0 -0
  72. data/markdown/use_cases/{include_files → include}/nest_inclusions/includee.md +0 -0
  73. data/markdown/use_cases/{include_files → include}/nest_inclusions/includer.md +0 -0
  74. data/markdown/use_cases/{include_files → include}/nest_inclusions/nested_includee.md +0 -0
  75. data/markdown/use_cases/{include_files → include}/nest_inclusions/use_case.md +0 -0
  76. data/markdown/use_cases/{include_files → include}/nest_inclusions/use_case_template.md +0 -0
  77. data/markdown/use_cases/{include_files → include}/reuse_text/included.md +0 -0
  78. data/markdown/use_cases/{include_files → include}/reuse_text/includee.md +0 -0
  79. data/markdown/use_cases/{include_files → include}/reuse_text/includer.md +0 -0
  80. data/markdown/use_cases/{include_files → include}/reuse_text/use_case.md +0 -0
  81. data/markdown/use_cases/{include_files → include}/reuse_text/use_case_template.md +0 -0
  82. data/markdown/use_cases/run_irb/interface.md +16 -0
  83. data/markdown/use_cases/run_irb/run_irb.rb +5 -0
  84. data/markdown/use_cases/run_irb/run_irb/markdown.md +43 -0
  85. data/markdown/use_cases/run_irb/run_irb/template.md +37 -0
  86. data/markdown/use_cases/run_irb/run_irb/use_case.md +178 -0
  87. data/markdown/use_cases/run_irb/run_irb/use_case_template.md +33 -0
  88. data/markdown/use_cases/use_cases.md +17 -14
  89. metadata +82 -72
  90. data/markdown/use_cases/include_files/diagnose_circular_includes/diagnose_circular_includes.err +0 -26
  91. 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