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
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'