markdown_helper 2.3.0 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +24 -17
- data/bin/_run_irb +46 -0
- data/lib/markdown_helper.rb +3 -384
- data/lib/markdown_helper/markdown_helper.rb +79 -0
- data/lib/markdown_helper/markdown_includer.rb +315 -0
- data/lib/markdown_helper/markdown_irb_runner.rb +65 -0
- data/lib/markdown_helper/version.rb +1 -1
- data/markdown/readme/README.template.md +21 -16
- data/markdown/use_cases/Rakefile +9 -2
- data/markdown/use_cases/include/diagnose_circular_includes/diagnose_circular_includes.err +26 -0
- data/markdown/use_cases/{include_files → include}/diagnose_circular_includes/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/diagnose_circular_includes/includer_0.md +0 -0
- data/markdown/use_cases/{include_files → include}/diagnose_circular_includes/includer_1.md +0 -0
- data/markdown/use_cases/{include_files → include}/diagnose_circular_includes/includer_2.md +0 -0
- data/markdown/use_cases/{include_files → include}/diagnose_circular_includes/use_case.md +8 -8
- data/markdown/use_cases/{include_files → include}/diagnose_circular_includes/use_case_template.md +0 -0
- data/markdown/use_cases/include/diagnose_missing_includee/diagnose_missing_includee.err +26 -0
- data/markdown/use_cases/{include_files → include}/diagnose_missing_includee/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/diagnose_missing_includee/includer_0.md +0 -0
- data/markdown/use_cases/{include_files → include}/diagnose_missing_includee/includer_1.md +0 -0
- data/markdown/use_cases/{include_files → include}/diagnose_missing_includee/includer_2.md +0 -0
- data/markdown/use_cases/{include_files → include}/diagnose_missing_includee/use_case.md +8 -8
- data/markdown/use_cases/{include_files → include}/diagnose_missing_includee/use_case_template.md +0 -0
- data/markdown/use_cases/{include_files → include}/include.rb +0 -0
- data/markdown/use_cases/{include_files → include}/include_code_block/hello.rb +0 -0
- data/markdown/use_cases/{include_files → include}/include_code_block/included.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_code_block/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_code_block/use_case.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_code_block/use_case_template.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_generated_text/use_case.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_generated_text/use_case_template.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_highlighted_code/hello.rb +0 -0
- data/markdown/use_cases/{include_files → include}/include_highlighted_code/included.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_highlighted_code/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_highlighted_code/use_case.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_highlighted_code/use_case_template.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_markdown/included.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_markdown/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_markdown/markdown.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_markdown/use_case.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_markdown/use_case_template.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_page_toc/included.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_page_toc/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_page_toc/markdown_0.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_page_toc/markdown_1.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_page_toc/use_case.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_page_toc/use_case_template.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_comment/hello.rb +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_comment/included.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_comment/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_comment/use_case.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_comment/use_case_template.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_details/details.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_details/included.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_details/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_details/use_case.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_details/use_case_template.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_pre/included.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_pre/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_pre/triple_backtick.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_pre/use_case.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_text_as_pre/use_case_template.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_with_added_comments/included.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_with_added_comments/includee.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_with_added_comments/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_with_added_comments/use_case.md +0 -0
- data/markdown/use_cases/{include_files → include}/include_with_added_comments/use_case_template.md +0 -0
- data/markdown/use_cases/{include_files → include}/interface.md +0 -0
- data/markdown/use_cases/{include_files → include}/nest_inclusions/included.md +0 -0
- data/markdown/use_cases/{include_files → include}/nest_inclusions/includee.md +0 -0
- data/markdown/use_cases/{include_files → include}/nest_inclusions/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/nest_inclusions/nested_includee.md +0 -0
- data/markdown/use_cases/{include_files → include}/nest_inclusions/use_case.md +0 -0
- data/markdown/use_cases/{include_files → include}/nest_inclusions/use_case_template.md +0 -0
- data/markdown/use_cases/{include_files → include}/reuse_text/included.md +0 -0
- data/markdown/use_cases/{include_files → include}/reuse_text/includee.md +0 -0
- data/markdown/use_cases/{include_files → include}/reuse_text/includer.md +0 -0
- data/markdown/use_cases/{include_files → include}/reuse_text/use_case.md +0 -0
- data/markdown/use_cases/{include_files → include}/reuse_text/use_case_template.md +0 -0
- data/markdown/use_cases/run_irb/interface.md +16 -0
- data/markdown/use_cases/run_irb/run_irb.rb +5 -0
- data/markdown/use_cases/run_irb/run_irb/markdown.md +43 -0
- data/markdown/use_cases/run_irb/run_irb/template.md +37 -0
- data/markdown/use_cases/run_irb/run_irb/use_case.md +178 -0
- data/markdown/use_cases/run_irb/run_irb/use_case_template.md +33 -0
- data/markdown/use_cases/use_cases.md +17 -14
- metadata +82 -72
- data/markdown/use_cases/include_files/diagnose_circular_includes/diagnose_circular_includes.err +0 -26
- data/markdown/use_cases/include_files/diagnose_missing_includee/diagnose_missing_includee.err +0 -26
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
|
[![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/
|
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'
|