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.
- 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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f530c806dbcaa0885c405efa0f663800b9afb5cd758c9b9ab182aa129a588b77
|
|
4
|
+
data.tar.gz: e53416b6a71deebd8c0dc6e11721eeeac8ee8bf18494c6fe66f8afb10a4f7bcc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d052b01dcb0903bfacfb0b5b87b6eb5fc95540796786bf9cc2afbe047413139b9556fe1b5bfd1c1f1548c657f532dcd6a6a609b45d506f0778719266d30591d9
|
|
7
|
+
data.tar.gz: 453e13f39dcd61fab4ac4217695518b972c6aeb7d00fecc826f1200aafad7d55c3f941873c49b45ce8674c23c44fa0e7f622f6a0e84ed069faba0afc33593c35
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -3,11 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
[](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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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)
|
data/lib/markdown_helper.rb
CHANGED
|
@@ -1,384 +1,3 @@
|
|
|
1
|
-
require '
|
|
2
|
-
|
|
3
|
-
require 'markdown_helper/
|
|
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'
|