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.
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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f87e472a6df990e637dacc06c4e6bc7daffd512634c69c4202e3d9d6f96bc43
4
- data.tar.gz: 414fe00be28329fef09722912fffe9bb9a5bb1ba998c69432d68908219a639e3
3
+ metadata.gz: f530c806dbcaa0885c405efa0f663800b9afb5cd758c9b9ab182aa129a588b77
4
+ data.tar.gz: e53416b6a71deebd8c0dc6e11721eeeac8ee8bf18494c6fe66f8afb10a4f7bcc
5
5
  SHA512:
6
- metadata.gz: b8a99c9e3a3b2ffa39abbf36fcf44a21650b19498849ed2d60e78e418792464c8efffe680c758c6f23b65bc95c4fdef67a97e894339a96d6196bc7c7d362851d
7
- data.tar.gz: 861b07f382444226d6fcacf224e16da75e94a3822305592fbf9dba7b1d38f0686a0f890fc1914f33c8640c04f2bf3a3d39ecfd52014c39ae95b47d40ddc008b5
6
+ metadata.gz: d052b01dcb0903bfacfb0b5b87b6eb5fc95540796786bf9cc2afbe047413139b9556fe1b5bfd1c1f1548c657f532dcd6a6a609b45d506f0778719266d30591d9
7
+ data.tar.gz: 453e13f39dcd61fab4ac4217695518b972c6aeb7d00fecc826f1200aafad7d55c3f941873c49b45ce8674c23c44fa0e7f622f6a0e84ed069faba0afc33593c35
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- markdown_helper (2.3.0)
4
+ markdown_helper (2.4.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -3,11 +3,8 @@
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
- ## What's New?
7
-
8
- Inclusion of text as details is added. See the [use case](markdown/use_cases/include_files/include_text_as_details/use_case.md#include-text-as-details).
9
-
10
6
  ## Contents
7
+ - [Installation](#installation)
11
8
  - [What's a Markdown Helper?](#whats-a-markdown-helper)
12
9
  - [How It Works](#how-it-works)
13
10
  - [Restriction: ```git``` Only](#restriction-git-only)
@@ -33,14 +30,20 @@ Inclusion of text as details is added. See the [use case](markdown/use_cases/in
33
30
  - ["Noisy" (Not Pristine)](#noisy-not-pristine)
34
31
  - [Missing Includee File](#missing-includee-file)
35
32
  - [Circular Inclusion](#circular-inclusion)
33
+ - [Run ```irb```](#run-irb)
36
34
  - [What Should Be Next?](#what-should-be-next)
37
35
 
36
+ ## Installation
37
+
38
+ ```gem install markdown_helper```
39
+
38
40
  ## What's a Markdown Helper?
39
41
 
40
42
  Class <code>MarkdownHelper</code> supports:
41
43
 
42
44
  * [File inclusion](#file-inclusion): to include text from other files, as code-block or markdown.
43
45
  * [Page TOC](#page-toc): to create and insert the table of contents for a markdown page.
46
+ * [Run irb](#run-irb): to execute Ruby snippets in the Ruby interactive shell (```irb```) and include the output in markdown.
44
47
 
45
48
  ## How It Works
46
49
 
@@ -73,41 +76,41 @@ See all [use cases](markdown/use_cases/use_cases.md#use-cases).
73
76
 
74
77
  ### Re-use Text
75
78
 
76
- Keep your markdown DRY (Don't Repeat Yourself) by re-using text. See the [use case](markdown/use_cases/include_files/reuse_text/use_case.md#reuse-text).
79
+ Keep your markdown DRY (Don't Repeat Yourself) by re-using text. See the [use case](markdown/use_cases/include/reuse_text/use_case.md#reuse-text).
77
80
 
78
81
  ### Include Generated Text
79
82
 
80
- In particular, you can include text that's built during your "readme build." See the [use case](markdown/use_cases/include_files/include_generated_text/use_case.md#include-generated-text).
83
+ In particular, you can include text that's built during your "readme build." See the [use case](markdown/use_cases/include/include_generated_text/use_case.md#include-generated-text).
81
84
 
82
85
  ### Nest Inclusions
83
86
 
84
- You can nest inclusions. See the [use case](markdown/use_cases/include_files/nest_inclusions/use_case.md#nest-inclusions).
87
+ You can nest inclusions. See the [use case](markdown/use_cases/include/nest_inclusions/use_case.md#nest-inclusions).
85
88
 
86
89
  ### Merged Text Formats
87
90
 
88
91
  #### Markdown
89
92
 
90
- You can include text that is to be treated simply as markdown. See the [use case](markdown/use_cases/include_files/include_markdown/use_case.md#include-markdown).
93
+ You can include text that is to be treated simply as markdown. See the [use case](markdown/use_cases/include/include_markdown/use_case.md#include-markdown).
91
94
 
92
95
  #### Highlighted Code Block
93
96
 
94
- You can include a code block that's to be highlighted. See the [use case](markdown/use_cases/include_files/include_highlighted_code/use_case.md#include-highlighted-code).
97
+ You can include a code block that's to be highlighted. See the [use case](markdown/use_cases/include/include_highlighted_code/use_case.md#include-highlighted-code).
95
98
 
96
99
  #### Plain Code Block
97
100
 
98
- You can also include a code block without highlighting. See the [use case](markdown/use_cases/include_files/include_code_block/use_case.md#include-code-block).
101
+ You can also include a code block without highlighting. See the [use case](markdown/use_cases/include/include_code_block/use_case.md#include-code-block).
99
102
 
100
103
  #### Comment
101
104
 
102
- You can include text that's to become a comment in the markdown. See the [use case](markdown/use_cases/include_files/include_text_as_comment/use_case.md#include-text-as-comment).
105
+ You can include text that's to become a comment in the markdown. See the [use case](markdown/use_cases/include/include_text_as_comment/use_case.md#include-text-as-comment).
103
106
 
104
107
  #### Details
105
108
 
106
- You can include text that's to become details in the markdown. See the [use case](markdown/use_cases/include_files/include_text_as_details/use_case.md#include-text-as-details).
109
+ You can include text that's to become details in the markdown. See the [use case](markdown/use_cases/include/include_text_as_details/use_case.md#include-text-as-details).
107
110
 
108
111
  ### Pre-Formatted Text
109
112
 
110
- You can include text that's pre-formatted. See the [use case](markdown/use_cases/include_files/include_text_as_pre/use_case.md#include-text-as-pre).
113
+ You can include text that's pre-formatted. See the [use case](markdown/use_cases/include/include_text_as_pre/use_case.md#include-text-as-pre).
111
114
 
112
115
  ### Usage
113
116
 
@@ -188,21 +191,25 @@ where:
188
191
 
189
192
  #### Page TOC
190
193
 
191
- You can specify the location for an automatically-generated page TOC (table of cotents). See the [use case](markdown/use_cases/include_files/include_page_toc/use_case.md#include-page-toc).
194
+ You can specify the location for an automatically-generated page TOC (table of cotents). See the [use case](markdown/use_cases/include/include_page_toc/use_case.md#include-page-toc).
192
195
 
193
196
  #### Diagnostics
194
197
 
195
198
  ##### "Noisy" (Not Pristine)
196
199
 
197
- By default, the markdown helper inserts comments indicating inclusions. See the [use case](markdown/use_cases/include_files/include_with_added_comments/use_case.md#include-with-added-comments).
200
+ By default, the markdown helper inserts comments indicating inclusions. See the [use case](markdown/use_cases/include/include_with_added_comments/use_case.md#include-with-added-comments).
198
201
 
199
202
  ##### Missing Includee File
200
203
 
201
- A missing includee file causes an exception that shows an inclusion backtrace. See the [use case](markdown/use_cases/include_files/diagnose_missing_includee/use_case.md#diagnose-missing-includee).
204
+ A missing includee file causes an exception that shows an inclusion backtrace. See the [use case](markdown/use_cases/include/diagnose_missing_includee/use_case.md#diagnose-missing-includee).
202
205
 
203
206
  ##### Circular Inclusion
204
207
 
205
- A circular inclusion causes an exception that shows an inclusion backtrace. See the [use case](markdown/use_cases/include_files/diagnose_circular_includes/use_case.md#diagnose-circular-includes).
208
+ A circular inclusion causes an exception that shows an inclusion backtrace. See the [use case](markdown/use_cases/include/diagnose_circular_includes/use_case.md#diagnose-circular-includes).
209
+
210
+ ## Run ```irb```
211
+
212
+ * Execute Ruby snippets in the Ruby interactive shell (```irb```) and include the output in markdown. See the [use case](markdown/use_cases/run_irb/run_irb/use_case.md#run-irb).
206
213
 
207
214
  ## What Should Be Next?
208
215
 
data/bin/_run_irb ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+
5
+ require 'markdown_helper'
6
+
7
+ options = {:pristine => false}
8
+
9
+ # Save opts for use below.
10
+ opts = nil
11
+ parser = OptionParser.new do |_opts|
12
+ opts = _opts
13
+ _opts.banner = "Usage: markdown_helper run_irb [options] template_file_path markdown_file_path"
14
+ _opts.on('--pristine', 'No comments added') do |_|
15
+ options[:pristine] = true
16
+ end
17
+ _opts.on('--help', 'Display help') do
18
+ usage(_opts)
19
+ end
20
+ end
21
+
22
+ def usage(opts)
23
+ puts ''
24
+ puts opts
25
+ puts <<-EOT
26
+
27
+ where
28
+
29
+ * template_file_path is the path to an existing file.
30
+ * markdown_file_path is the path to a file to be created.
31
+
32
+ Typically:
33
+
34
+ * Both file types are .md.
35
+ * The template file contains code blocks to be run in irb.
36
+ EOT
37
+ exit
38
+ end
39
+
40
+ parser.parse!
41
+
42
+ _, template_file_path, markdown_file_path = ARGV
43
+
44
+ usage(opts) unless ARGV.size == 3
45
+
46
+ MarkdownHelper.new(options).run_irb(template_file_path, markdown_file_path)
@@ -1,384 +1,3 @@
1
- require 'pathname'
2
-
3
- require 'markdown_helper/version'
4
-
5
- class MarkdownHelper
6
-
7
- class MarkdownHelperError < RuntimeError; end
8
- class OptionError < MarkdownHelperError; end
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
-
16
- INCLUDE_REGEXP = /^@\[([^\[]+)\]\(([^)]+)\)$/
17
- INCLUDE_MARKDOWN_REGEXP = /^@\[:markdown\]\(([^)]+)\)$/
18
-
19
- attr_accessor :pristine
20
-
21
- def initialize(options = {})
22
- # Confirm that we're in a git project.
23
- # This is necessary so that we can prune file paths in the tests,
24
- # which otherwise would fail because of differing installation directories.
25
- # It also allows pruned paths to be used in the inserted comments (when not pristine).
26
- MarkdownHelper.git_clone_dir_path
27
- default_options = {
28
- :pristine => false,
29
- }
30
- merged_options = default_options.merge(options)
31
- merged_options.each_pair do |method, value|
32
- unless self.respond_to?(method)
33
- raise OptionError.new("Unknown option: #{method}")
34
- end
35
- setter_method = "#{method}="
36
- send(setter_method, value)
37
- merged_options.delete(method)
38
- end
39
- @inclusions = []
40
- end
41
-
42
- def include(template_file_path, markdown_file_path)
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
49
- end
50
- end
51
-
52
- private
53
-
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} "))
61
- end
62
- output_lines.push('')
63
- output = output_lines.join("\n")
64
- File.write(markdown_file_path, output)
65
- end
66
-
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
- path_in_project = MarkdownHelper.path_in_project(template_file_path )
72
- message = [
73
- "Could not read template file: #{path_in_project}",
74
- MarkdownHelper.backtrace_inclusions(@inclusions),
75
- ].join("\n")
76
- e = UnreadableTemplateError.new(message)
77
- e.set_backtrace([])
78
- raise e
79
- end
80
- template_lines = File.readlines(template_file_path)
81
- template_lines.each_with_index do |template_line, i|
82
- template_line.chomp!
83
- treatment, includee_file_path = *parse_include(template_line)
84
- if treatment.nil?
85
- markdown_lines.push(template_line)
86
- next
87
- end
88
- if treatment == ':page_toc'
89
- markdown_lines.push(template_line)
90
- next
91
- end
92
- inclusion = Inclusion.new(
93
- template_file_path,
94
- template_line,
95
- i,
96
- treatment,
97
- includee_file_path,
98
- @inclusions
99
- )
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
- when ':details'
116
- text = File.read(includee_file_path)
117
- markdown_lines.push(MarkdownHelper.details(text))
118
- @inclusions.push(inclusion)
119
- else
120
- markdown_lines.push(template_line)
121
- next
122
- end
123
- @inclusions.pop
124
- treatment.sub!(/^:/, '')
125
- add_inclusion_comments(treatment, includee_file_path, markdown_lines)
126
- end
127
- markdown_lines
128
- end
129
- end
130
-
131
- def include_page_toc(template_lines)
132
- toc_line_index = nil
133
- toc_title = nil
134
- template_lines.each_with_index do |template_line, i|
135
- match_data = template_line.match(INCLUDE_REGEXP)
136
- next unless match_data
137
- treatment = match_data[1]
138
- next unless treatment == ':page_toc'
139
- unless toc_line_index.nil?
140
- message = 'Multiple page TOC not allowed'
141
- raise MultiplePageTocError.new(message)
142
- end
143
- toc_line_index = i
144
- toc_title = match_data[2]
145
- title_regexp = /^\#{1,6}\s/
146
- unless toc_title.match(title_regexp)
147
- message = "TOC title must be a valid markdown header, not #{toc_title}"
148
- raise InvalidTocTitleError.new(message)
149
- end
150
- end
151
- return template_lines unless toc_line_index
152
- toc_lines = [toc_title]
153
- first_heading_level = nil
154
- template_lines.each_with_index do |input_line, i|
155
- next if i < toc_line_index
156
- line = input_line.chomp
157
- heading = Heading.parse(line)
158
- next unless heading
159
- first_heading_level ||= heading.level
160
- indentation = ' ' * (heading.level - first_heading_level)
161
- toc_line = "#{indentation}- #{heading.link}"
162
- toc_lines.push(toc_line)
163
- end
164
- template_lines.delete_at(toc_line_index)
165
- template_lines.insert(toc_line_index, *toc_lines)
166
- template_lines
167
- end
168
-
169
- def include_all(template_file_path, template_lines, output_lines)
170
- template_lines.each_with_index do |template_line, i|
171
- treatment, includee_file_path = *parse_include(template_line)
172
- if treatment.nil?
173
- output_lines.push(template_line)
174
- next
175
- end
176
- inclusion = Inclusion.new(
177
- template_file_path,
178
- template_line,
179
- i,
180
- treatment,
181
- includee_file_path,
182
- @inclusions
183
- )
184
- check_includee(inclusion)
185
- @inclusions.push(inclusion)
186
- file_marker = format('```%s```:', File.basename(includee_file_path))
187
- begin_backticks = '```'
188
- end_backticks = '```'
189
- begin_backticks += treatment unless treatment.start_with?(':')
190
- includee_lines = File.read(includee_file_path).split("\n")
191
- includee_lines.unshift(begin_backticks)
192
- includee_lines.unshift(file_marker)
193
- includee_lines.push(end_backticks)
194
- add_inclusion_comments(treatment.sub(':', ''), includee_file_path, includee_lines)
195
- output_lines.concat(includee_lines)
196
- end
197
- end
198
-
199
- def add_inclusion_comments(treatment, includee_file_path, lines)
200
- path_in_project = MarkdownHelper.path_in_project(includee_file_path)
201
- unless pristine
202
- comment = format(' >>>>>> BEGIN INCLUDED FILE (%s): SOURCE %s ', treatment, path_in_project)
203
- lines.unshift(MarkdownHelper.comment(comment))
204
- comment = format(' <<<<<< END INCLUDED FILE (%s): SOURCE %s ', treatment, path_in_project)
205
- lines.push(MarkdownHelper.comment(comment))
206
- end
207
- end
208
-
209
- def parse_include(line)
210
- match_data = line.match(INCLUDE_REGEXP)
211
- return [nil, nil] unless match_data
212
- treatment = match_data[1]
213
- includee_file_path = match_data[2]
214
- [treatment, includee_file_path]
215
- end
216
-
217
- def self.path_in_project(file_path)
218
- abs_path = File.absolute_path(file_path)
219
- abs_path.sub(self.git_clone_dir_path + '/', '')
220
- end
221
-
222
- def self.comment(text)
223
- "<!--#{text}-->"
224
- end
225
-
226
- def self.pre(text)
227
- "<pre>\n#{text}</pre>"
228
- end
229
-
230
- def self.details(text)
231
- "<details>\n#{text}</details>"
232
- end
233
-
234
- def self.git_clone_dir_path
235
- git_dir = `git rev-parse --show-toplevel`.chomp
236
- unless $?.success?
237
- message = <<EOT
238
-
239
- Markdown helper must run inside a .git project.
240
- That is, the working directory one of its parents must be a .git directory.
241
- EOT
242
- raise RuntimeError.new(message)
243
- end
244
- git_dir
245
- end
246
-
247
- class Heading
248
-
249
- attr_accessor :level, :title
250
-
251
- def initialize(level, title)
252
- self.level = level
253
- self.title = title
254
- end
255
-
256
- def self.parse(line)
257
- # Four leading spaces not allowed (but three are allowed).
258
- return nil if line.start_with?(' ' * 4)
259
- stripped_line = line.sub(/^ */, '')
260
- # Now must begin with hash marks and space.
261
- return nil unless stripped_line.match(/^#+ /)
262
- hash_marks, title = stripped_line.split(' ', 2)
263
- level = hash_marks.size
264
- # Seventh level heading not allowed.
265
- return nil if level > 6
266
- self.new(level, title)
267
- end
268
-
269
-
270
- def link
271
- remove_regexp = /[\#\(\)\[\]\{\}\.\?\+\*\`\"\']+/
272
- to_hyphen_regexp = /\W+/
273
- anchor = title.
274
- gsub(remove_regexp, '').
275
- gsub(to_hyphen_regexp, '-').
276
- downcase
277
- "[#{title}](##{anchor})"
278
- end
279
-
280
- end
281
-
282
- def check_circularity(inclusion)
283
- included_file_paths = @inclusions.collect { |x| x.includee_real_file_path}
284
- previously_included = included_file_paths.include?(inclusion.includee_real_file_path)
285
- if previously_included
286
- @inclusions.push(inclusion)
287
- message = [
288
- 'Includes are circular:',
289
- MarkdownHelper.backtrace_inclusions(@inclusions),
290
- ].join("\n")
291
- e = MarkdownHelper::CircularIncludeError.new(message)
292
- e.set_backtrace([])
293
- raise e
294
- end
295
- end
296
-
297
- def check_includee(inclusion)
298
- unless File.readable?(inclusion.includee_absolute_file_path)
299
- @inclusions.push(inclusion)
300
- message = [
301
- 'Could not read includee file:',
302
- MarkdownHelper.backtrace_inclusions(@inclusions),
303
- ].join("\n")
304
- e = MarkdownHelper::UnreadableIncludeeError.new(message)
305
- e.set_backtrace([])
306
- raise e
307
- end
308
-
309
- end
310
-
311
- def self.backtrace_inclusions(inclusions)
312
- lines = [' Backtrace (innermost include first):']
313
- inclusions.reverse.each_with_index do |inclusion, i|
314
- lines.push("#{' Level'} #{i}:")
315
- level_lines = inclusion.to_lines(indentation_level = 3)
316
- lines.push(*level_lines)
317
- end
318
- lines.join("\n")
319
- end
320
-
321
- class Inclusion
322
-
323
- attr_accessor \
324
- :includer_file_path,
325
- :includer_absolute_file_path,
326
- :include_pragma,
327
- :treatment,
328
- :includer_line_number,
329
- :cited_includee_file_path,
330
- :includee_absolute_file_path
331
-
332
- def initialize(
333
- includer_file_path,
334
- include_pragma,
335
- includer_line_number,
336
- treatment,
337
- cited_includee_file_path,
338
- inclusions
339
- )
340
- self.includer_file_path = includer_file_path
341
- self.include_pragma = include_pragma
342
- self.includer_line_number = includer_line_number
343
- self.treatment = treatment
344
- self.cited_includee_file_path = cited_includee_file_path
345
-
346
- self.includer_absolute_file_path = File.absolute_path(includer_file_path)
347
- unless File.exist?(self.includer_absolute_file_path)
348
- fail self.includer_absolute_file_path
349
- end
350
-
351
- self.includee_absolute_file_path = File.absolute_path(File.join(
352
- File.dirname(includer_file_path),
353
- cited_includee_file_path,
354
- ))
355
- end
356
-
357
- def includer_real_file_path
358
- Pathname.new(includer_absolute_file_path).realpath.to_s
359
- end
360
-
361
- def includee_real_file_path
362
- Pathname.new(includee_absolute_file_path).realpath.to_s
363
- end
364
-
365
- def indentation(level)
366
- ' ' * level
367
- end
368
-
369
- def to_lines(indentation_level)
370
- relative_inluder_file_path = MarkdownHelper.path_in_project(includer_file_path)
371
- relative_inludee_file_path = MarkdownHelper.path_in_project(includee_absolute_file_path)
372
- text = <<EOT
373
- #{indentation(indentation_level)}Includer:
374
- #{indentation(indentation_level+1)}Location: #{relative_inluder_file_path}:#{includer_line_number}
375
- #{indentation(indentation_level+1)}Include pragma: #{include_pragma}
376
- #{indentation(indentation_level)}Includee:
377
- #{indentation(indentation_level+1)}File path: #{relative_inludee_file_path}
378
- EOT
379
- text.split("\n")
380
- end
381
-
382
- end
383
-
384
- end
1
+ require 'markdown_helper/markdown_helper'
2
+ require 'markdown_helper/markdown_includer'
3
+ require 'markdown_helper/markdown_irb_runner'