markdown_helper 2.0.0 → 2.1.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 (55) hide show
  1. checksums.yaml +5 -5
  2. data/Gemfile.lock +1 -1
  3. data/README.md +74 -208
  4. data/Rakefile +0 -1
  5. data/lib/markdown_helper.rb +115 -248
  6. data/lib/markdown_helper/version.rb +1 -1
  7. data/markdown/readme/README.template.md +43 -101
  8. data/markdown/readme/include.md +4 -0
  9. data/markdown/readme/include_usage.rb +1 -2
  10. data/markdown/use_cases/Rakefile +28 -31
  11. data/markdown/use_cases/include_files/diagnose_circular_includes/diagnose_circular_includes.err +1 -1
  12. data/markdown/use_cases/include_files/diagnose_circular_includes/use_case.md +1 -1
  13. data/markdown/use_cases/include_files/diagnose_circular_includes/{diagnose_circular_includes.rb → use_case_builder.rb} +1 -2
  14. data/markdown/use_cases/include_files/diagnose_missing_includee/diagnose_missing_includee.err +1 -1
  15. data/markdown/use_cases/include_files/diagnose_missing_includee/use_case.md +1 -1
  16. data/markdown/use_cases/include_files/diagnose_missing_includee/{diagnose_missing_includee.rb → use_case_builder.rb} +1 -2
  17. data/markdown/use_cases/include_files/include_code_block/{include_code_block.rb → use_case_builder.rb} +1 -2
  18. data/markdown/use_cases/include_files/include_generated_text/{include_generated_text.rb → use_case_builder.rb} +1 -2
  19. data/markdown/use_cases/include_files/include_highlighted_code/{include_highlighted_code.rb → use_case_builder.rb} +1 -2
  20. data/markdown/use_cases/include_files/include_markdown/{include_markdown.rb → use_case_builder.rb} +1 -2
  21. data/markdown/use_cases/include_files/include_page_toc/included.md +48 -0
  22. data/markdown/use_cases/include_files/include_page_toc/includer.md +16 -0
  23. data/markdown/use_cases/include_files/include_page_toc/markdown_0.md +8 -0
  24. data/markdown/use_cases/include_files/include_page_toc/markdown_1.md +8 -0
  25. data/markdown/use_cases/include_files/include_page_toc/use_case.md +212 -0
  26. data/markdown/use_cases/include_files/include_page_toc/use_case_builder.rb +121 -0
  27. data/markdown/use_cases/include_files/include_page_toc/use_case_template.md +46 -0
  28. data/markdown/use_cases/include_files/include_text_as_comment/{include_text_as_comment.rb → use_case_builder.rb} +1 -2
  29. data/markdown/use_cases/include_files/include_text_as_pre/{include_text_as_pre.rb → use_case_builder.rb} +1 -2
  30. data/markdown/use_cases/include_files/include_use_case.rb +2 -8
  31. data/markdown/use_cases/include_files/include_with_added_comments/{include_with_added_comments.rb → use_case_builder.rb} +2 -3
  32. data/markdown/use_cases/include_files/nest_inclusions/{nest_inclusions.rb → use_case_builder.rb} +1 -2
  33. data/markdown/use_cases/include_files/reuse_text/{reuse_text.rb → use_case_builder.rb} +3 -2
  34. data/markdown/use_cases/structure.md +10 -0
  35. data/markdown/use_cases/tables_of_contents/create_and_include_page_toc/included.md +44 -0
  36. data/markdown/use_cases/tables_of_contents/create_and_include_page_toc/page.md +7 -7
  37. data/markdown/use_cases/tables_of_contents/create_and_include_page_toc/toc.md +7 -7
  38. data/markdown/use_cases/tables_of_contents/create_and_include_page_toc/{create_and_include_page_toc.rb → use_case_builder.rb} +1 -2
  39. data/markdown/use_cases/tables_of_contents/create_page_toc_use_case.rb +1 -1
  40. data/markdown/use_cases/use_case.rb +14 -15
  41. data/markdown/use_cases/use_cases.md +2 -4
  42. data/markdown_helper.gemspec +0 -2
  43. metadata +24 -29
  44. data/bin/_resolve +0 -46
  45. data/bin/resolve +0 -49
  46. data/bin/usage/resolve.txt +0 -14
  47. data/images/html.png +0 -0
  48. data/markdown/readme/resolve_usage.rb +0 -12
  49. data/markdown/use_cases/include_files/diagnose_missing_includee/included.md +0 -1
  50. data/markdown/use_cases/resolve/gemify_images/gemify_images.md +0 -11
  51. data/markdown/use_cases/resolve/gemify_images/gemify_images.rb +0 -68
  52. data/markdown/use_cases/resolve/gemify_images/relative_image.md +0 -1
  53. data/markdown/use_cases/resolve/gemify_images/resolved_image.md +0 -1
  54. data/markdown/use_cases/resolve/gemify_images/template.md +0 -15
  55. data/markdown/use_cases/resolve/resize_images/template.md +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: bd8b799693304f32aad8780f7d4ce734ae46614d
4
- data.tar.gz: 703df7ba48954272c6bfe0e794b9150564f4d3cd
2
+ SHA256:
3
+ metadata.gz: cee806406f109c72b11a7a4f78c8ad7efc59706f278a0a5b654267e3ae38ddf6
4
+ data.tar.gz: 4e49e14011eb429bd5d523a314572aff3693876b07fa50b52d9cfecf693fcd3d
5
5
  SHA512:
6
- metadata.gz: efc921a959dd8f3c0cd39d0da08e13dcb6c51f7b82ab405d37e1faf6f4ff81218ae6264e8963e8aa8de67ebad4521145e9bd044c5b7eb4ced8e9003a6461919a
7
- data.tar.gz: a91f66a74094c2bab6e87bbf98403ed168df5d817a4155f7440b9c7cca8c181171c02bea25d6fc6b882794bc617519f127e3a0da15b576ea3cb6e411bada3194
6
+ metadata.gz: 5d4c4a25171b3ac8df8cfd84766843ae7c8d599c896d70b1d70854353dc7f0cb06741d1832640f5f24fdc500285bf16684f09d7d08450a48c73680d0033cab9f
7
+ data.tar.gz: 5f81f39ad84273fa2367a03e7bc18773190c97398ff7ac3c8834eac464a2a9dbe8bbedbf566fee79489124d2458fc32bfec96534b85f2edd4a7cadbb1e5dd63c
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- markdown_helper (2.0.0)
4
+ markdown_helper (2.1.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -1,38 +1,58 @@
1
1
  <!-- >>>>>> BEGIN GENERATED FILE (include): SOURCE README.template.md -->
2
2
  # Markdown Helper
3
3
 
4
- ![Gem Version](https://badge.fury.io/rb/markdown_helper.svg) [Visit gem markdown_helper](https://rubygems.org/gems/markdown_helper)
5
-
6
- ## Deprecated
7
-
8
- - Method ```:resolve```.
9
- - Command ```markdown_helper resolve```.
4
+ [![Gem](https://img.shields.io/gem/v/markdown_helper.svg?style=flat)](http://rubygems.org/gems/markdown_helper "View this project in Rubygems")
10
5
 
11
6
  ## What's New?
12
7
 
13
- Treatments for included file:
14
-
15
- - Support is added for including a file as a comment. See the [use case](markdown/use_cases/include_files/include_text_as_comment/use_case.md#include-text-as-comment).
16
- - Support is added for including a file as pre-formatted. See the [use case](markdown/use_cases/include_files/include_text_as_pre/use_case.md#include-text-as-pre).
17
-
18
- (The new version, 2.0.0, is not a major increment over version 1.9.9. Numbers just ran out.)
8
+ Page TOC (table of contents) is improved:
9
+
10
+ - **Old**: You would first run the markdown helper to generate a page TOC, then run the helper a second time to include the page TOC where you want it.
11
+ - **New**: You specify the site for the page TOC in the page itself, and the page TOC is automatically generated and inserted there. See the [use case](markdown/use_cases/include_files/include_page_toc/use_case.md#include-page-toc)
12
+
13
+ The old way is now deprecated.
14
+
15
+ ## Contents
16
+ - [What's a Markdown Helper?](#whats-a-markdown-helper)
17
+ - [How It Works](#how-it-works)
18
+ - [Restriction: ```git``` Only](#restriction-git-only)
19
+ - [Commented or Pristine?](#commented-or-pristine)
20
+ - [File Inclusion](#file-inclusion)
21
+ - [Re-use Text](#re-use-text)
22
+ - [Include Generated Text](#include-generated-text)
23
+ - [Nest Inclusions](#nest-inclusions)
24
+ - [Merged Text Formats](#merged-text-formats)
25
+ - [Markdown](#markdown)
26
+ - [Highlighted Code Block](#highlighted-code-block)
27
+ - [Plain Code Block](#plain-code-block)
28
+ - [Comment](#comment)
29
+ - [Pre-Formattted Text](#pre-formattted-text)
30
+ - [Usage](#usage)
31
+ - [CLI](#cli)
32
+ - [API](#api)
33
+ - [Include Descriptions](#include-descriptions)
34
+ - [Example Include Descriptions](#example-include-descriptions)
35
+ - [Page TOC](#page-toc)
36
+ - [Diagnostics](#diagnostics)
37
+ - ["Noisy" (Not Pristine)](#noisy-not-pristine)
38
+ - [Missing Includee File](#missing-includee-file)
39
+ - [Circular Inclusion](#circular-inclusion)
40
+ - [What Should Be Next?](#what-should-be-next)
19
41
 
20
42
  ## What's a Markdown Helper?
21
43
 
22
44
  Class <code>MarkdownHelper</code> supports:
23
45
 
24
46
  * [File inclusion](#file-inclusion): to include text from other files, as code-block or markdown.
25
- * [Page TOC](#page-toc): to create the table of contents for a markdown page.
26
- * [Image path resolution](#image-path-resolution): to resolve relative image paths to absolute URL paths (so they work even in gem documentation). [Deprecated]**
27
- * [Image attributes](#image-attributes): image attributes are passed through to an HTML <code>img</code> tag. [Deprecated]**
47
+ * [Page TOC](#page-toc): to create and insert the table of contents for a markdown page.
28
48
 
29
49
  ## How It Works
30
50
 
31
51
  The markdown helper is a preprocessor that reads a markdown document (template) and writes another markdown document.
32
52
 
33
- The template can contain certain instructions that call for file inclusions and image resolutions.
53
+ The template can contain certain instructions that call for file inclusions.
34
54
 
35
- ### Restriction: ```git``` Only
55
+ ### Restriction: ```git``` Only
36
56
 
37
57
  The helper works only in a ```git``` project: the working directory or one of ita parents must be a git directory -- one in which command ```git rev-parse --git-dir``` succeeds.
38
58
 
@@ -42,11 +62,10 @@ By default, the output markdown has added comments that show:
42
62
 
43
63
  * The path to the template file.
44
64
  * The path to each included file.
45
- * The image description (original) for each resolved image file path. [Deprecated]**
46
65
 
47
66
  You can suppress those comments using the <code>pristine</code> option.
48
67
 
49
- ## File Inclusion
68
+ ## File Inclusion
50
69
 
51
70
  <img src="images/include.png" alt="include_icon" width="50">
52
71
 
@@ -54,49 +73,41 @@ This markdown helper enables file inclusion in GitHub markdown.
54
73
 
55
74
  (Actually, this README file itself is built using file inclusion.)
56
75
 
57
- Use the markdown helper to merge external files into a markdown (</code>.md</code>) file.
76
+ See all [use cases](markdown/use_cases/use_cases.md#use-cases).
77
+
78
+ ### Re-use Text
79
+
80
+ 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).
81
+
82
+ ### Include Generated Text
83
+
84
+ 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).
58
85
 
59
- See the [use cases](markdown/use_cases/use_cases.md#use-cases).
86
+ ### Nest Inclusions
87
+
88
+ You can nest inclusions. See the [use case](markdown/use_cases/include_files/nest_inclusions/use_case.md#nest-inclusions).
60
89
 
61
90
  ### Merged Text Formats
62
91
 
92
+ #### Markdown
93
+
94
+ 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).
95
+
63
96
  #### Highlighted Code Block
64
97
 
65
- <!-- >>>>>> BEGIN INCLUDED FILE (ruby): SOURCE markdown/readme/include.rb -->
66
- ```include.rb```:
67
- ```ruby
68
- class RubyCode
69
- def initialize
70
- raise RuntimeError.new('I am only an example!')
71
- end
72
- end
73
- ```
74
- <!-- <<<<<< END INCLUDED FILE (ruby): SOURCE markdown/readme/include.rb -->
98
+ 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).
75
99
 
76
100
  #### Plain Code Block
77
101
 
78
- <!-- >>>>>> BEGIN INCLUDED FILE (code_block): SOURCE markdown/readme/include.rb -->
79
- ```include.rb```:
80
- ```
81
- class RubyCode
82
- def initialize
83
- raise RuntimeError.new('I am only an example!')
84
- end
85
- end
86
- ```
87
- <!-- <<<<<< END INCLUDED FILE (code_block): SOURCE markdown/readme/include.rb -->
88
-
89
- [Note: In the gem documentation, RubyDoc.info chooses to highlight this code block regardless. Go figure.]
102
+ 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).
90
103
 
91
104
  #### Comment
92
105
 
93
- Comment text is written into the output between the comment delimiters <code>\<!--</code> and <code>--></code>
94
-
95
- #### Markdown
106
+ 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).
96
107
 
97
- Markdown text is included unadorned, and will be processed on GitHub as markdown.
108
+ ### Pre-Formattted Text
98
109
 
99
- The markdown text is itself scanned for nested includes.
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).
100
111
 
101
112
  ### Usage
102
113
 
@@ -131,9 +142,8 @@ require 'markdown_helper'
131
142
 
132
143
  template_file_path = 'highlight_ruby_template.md'
133
144
  markdown_file_path = 'highlighted_ruby.md'
134
- markdown_helper = MarkdownHelper.new
135
- markdown_helper.include(template_file_path, markdown_file_path)
136
145
  # Pristine.
146
+ markdown_helper = MarkdownHelper.new
137
147
  markdown_helper.pristine = true
138
148
  markdown_helper.include(template_file_path, markdown_file_path)
139
149
  # Also pristine.
@@ -154,6 +164,8 @@ where:
154
164
  * Highlighting mode such as <code>[ruby]</code>, to include a highlighted code block. This can be any Ace mode mentioned in [GitHub Languages](https://github.com/github/linguist/blob/master/lib/linguist/languages.yml).
155
165
  * <code>[:code_block]</code>, to include a plain code block.
156
166
  * <code>[:markdown]</code>, to include text markdown (to be rendered as markdown).
167
+ * <code>[:comment]</code>, to insert text as a markdown comment.
168
+ * <code>[:pre]</code>, to include pre-formatted text.
157
169
  * *relative_file_path* points to the file to be included.
158
170
 
159
171
  ##### Example Include Descriptions
@@ -166,176 +178,30 @@ where:
166
178
  @[:code_block](my_language.xyzzy)
167
179
 
168
180
  @[:markdown](my_markdown.md)
169
- ```
170
- <!-- <<<<<< END INCLUDED FILE (code_block): SOURCE markdown/readme/include.md -->
171
-
172
- ## Page TOC
173
-
174
- The markdown helper can create the table of contents for a markdown page.
175
- - The TOC is a tree of links to the headers on the page, suitable for inclusion with the page itself.
176
- - See the [use case](markdown/use_cases/tables_of_contents/create_and_include_page_toc/use_case.md#create-and-include-page-toc).
177
-
178
-
179
-
180
- ## Image Path Resolution **[Deprecated]**
181
-
182
- <img src="images/image.png" alt="image_icon" width="50">
183
-
184
- This markdown helper enables image path resolution in GitHub markdown.
185
-
186
- (Actually, this README file itself is built using image path resolution.)
187
-
188
- Use the markdown helper to resolve image relative paths in a markdown (</code>.md</code>) file.
189
-
190
- This matters because when markdown becomes part of a Ruby gem, its images will have been relocated in the documentation at RubyDoc.info, breaking the relative paths. The resolved (absolute) urls, however, will still be valid.
191
-
192
- ### Usage
193
-
194
- #### CLI
195
-
196
- <!-- >>>>>> BEGIN INCLUDED FILE (code_block): SOURCE bin/usage/resolve.txt -->
197
- ```resolve.txt```:
198
- ```
199
-
200
- Usage: markdown_helper resolve [options] template_file_path markdown_file_path
201
- --pristine No comments added
202
- --help Display help
203
-
204
- where
205
-
206
- * template_file_path is the path to an existing file.
207
- * markdown_file_path is the path to a file to be created.
208
-
209
- Typically:
210
-
211
- * Both file types are .md.
212
- * The template file contains image descriptions.
213
- ```
214
- <!-- <<<<<< END INCLUDED FILE (code_block): SOURCE bin/usage/resolve.txt -->
215
-
216
- #### API
217
-
218
- <!-- >>>>>> BEGIN INCLUDED FILE (ruby): SOURCE markdown/readme/resolve_usage.rb -->
219
- ```resolve_usage.rb```:
220
- ```ruby
221
- require 'markdown_helper'
222
181
 
223
- template_file_path = 'template.md'
224
- markdown_file_path = 'markdown.md'
225
- markdown_helper = MarkdownHelper.new
226
- markdown_helper.resolve(template_file_path, markdown_file_path)
227
- # Pristine.
228
- markdown_helper.pristine = true
229
- markdown_helper.resolve(template_file_path, markdown_file_path)
230
- # Also pristine.
231
- markdown_helper = MarkdownHelper.new(:pristine => true)
232
- markdown_helper.resolve(template_file_path, markdown_file_path)
233
- ```
234
- <!-- <<<<<< END INCLUDED FILE (ruby): SOURCE markdown/readme/resolve_usage.rb -->
235
-
236
- #### Image Descriptions
237
-
238
- Specify each image at the beginning of a line via an *image description*, which has the form:
239
-
240
- <code>![*alt_text*]\(</code>*relative_file_path* <code>|</code> *attributes*<code>)</code>
241
-
242
- where:
243
-
244
- * *alt_text* is the usual alt text for an HTML image.
245
- * *relative_file_path* points to the file to be included.
246
- * *attributes* specify image attributes. See [Image Attributes](#image-attributes) below.
247
-
248
- ##### Example Image Descriptions
249
-
250
- <!-- >>>>>> BEGIN INCLUDED FILE (code_block): SOURCE markdown/readme/resolve.md -->
251
- ```resolve.md```:
252
- ```code_block
253
- ![my_alt](image/image.png)
254
-
255
- ![my_alt](image/image.png | width=50)
256
-
257
- ![my_alt](image/image.png| width=50 height=50)
258
- ```
259
- <!-- <<<<<< END INCLUDED FILE (code_block): SOURCE markdown/readme/resolve.md -->
260
-
261
- ## Image Attributes
262
-
263
- <img src="images/html.png" alt="html_icon" width="50">
264
-
265
- This markdown helper enables HTML image attributes in GitHub markdown [image descriptions](https://github.github.com/gfm/#image-description).
266
-
267
- (Actually, this README file itself is built using image attributes.)
268
-
269
- Use the markdown helper to add image attributes in a markdown (</code>.md</code>) file.
270
-
271
- ### Usage
272
-
273
- #### CLI
274
-
275
- <!-- >>>>>> BEGIN INCLUDED FILE (code_block): SOURCE bin/usage/resolve.txt -->
276
- ```resolve.txt```:
277
- ```
278
-
279
- Usage: markdown_helper resolve [options] template_file_path markdown_file_path
280
- --pristine No comments added
281
- --help Display help
282
-
283
- where
182
+ @[:comment](my_comment.txt)
284
183
 
285
- * template_file_path is the path to an existing file.
286
- * markdown_file_path is the path to a file to be created.
287
-
288
- Typically:
289
-
290
- * Both file types are .md.
291
- * The template file contains image descriptions.
184
+ @[:pre](my_preformatted.txt)
292
185
  ```
293
- <!-- <<<<<< END INCLUDED FILE (code_block): SOURCE bin/usage/resolve.txt -->
294
-
295
- #### API
296
-
297
- <!-- >>>>>> BEGIN INCLUDED FILE (ruby): SOURCE markdown/readme/resolve_usage.rb -->
298
- ```resolve_usage.rb```:
299
- ```ruby
300
- require 'markdown_helper'
301
-
302
- template_file_path = 'template.md'
303
- markdown_file_path = 'markdown.md'
304
- markdown_helper = MarkdownHelper.new
305
- markdown_helper.resolve(template_file_path, markdown_file_path)
306
- # Pristine.
307
- markdown_helper.pristine = true
308
- markdown_helper.resolve(template_file_path, markdown_file_path)
309
- # Also pristine.
310
- markdown_helper = MarkdownHelper.new(:pristine => true)
311
- markdown_helper.resolve(template_file_path, markdown_file_path)
312
- ```
313
- <!-- <<<<<< END INCLUDED FILE (ruby): SOURCE markdown/readme/resolve_usage.rb -->
186
+ <!-- <<<<<< END INCLUDED FILE (code_block): SOURCE markdown/readme/include.md -->
314
187
 
315
- #### Image Descriptions
188
+ #### Page TOC
316
189
 
317
- Specify each image at the beginning of a line via an *image description*, which has the form:
190
+ 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).
318
191
 
319
- <code>![*alt_text*]\(</code>*relative_file_path* <code>|</code> *attributes*<code>)</code>
192
+ #### Diagnostics
320
193
 
321
- where:
194
+ ##### "Noisy" (Not Pristine)
322
195
 
323
- * *alt_text* is the usual alt text for an HTML image.
324
- * *relative_file_path* points to the file to be included.
325
- * *attributes* are whitespace-separated name-value pairs in the form *name*<code>=</code>*value*. These are passed through to the generated <code>img</code> HTML element.
196
+ 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).
326
197
 
327
- ##### Example Image Descriptions
198
+ ##### Missing Includee File
328
199
 
329
- <!-- >>>>>> BEGIN INCLUDED FILE (code_block): SOURCE markdown/readme/resolve.md -->
330
- ```resolve.md```:
331
- ```code_block
332
- ![my_alt](image/image.png)
200
+ 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).
333
201
 
334
- ![my_alt](image/image.png | width=50)
202
+ ##### Circular Inclusion
335
203
 
336
- ![my_alt](image/image.png| width=50 height=50)
337
- ```
338
- <!-- <<<<<< END INCLUDED FILE (code_block): SOURCE markdown/readme/resolve.md -->
204
+ 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).
339
205
 
340
206
  ## What Should Be Next?
341
207
 
data/Rakefile CHANGED
@@ -28,7 +28,6 @@ namespace :build do
28
28
  %w/
29
29
  create_page_toc
30
30
  include
31
- resolve
32
31
  /.each do |executable_name|
33
32
  usage_text = `ruby bin/_#{executable_name} --help`
34
33
  usage_file_path = "bin/usage/#{executable_name}.txt"
@@ -1,10 +1,6 @@
1
1
  require 'pathname'
2
2
  require 'markdown_helper/version'
3
3
 
4
- # Helper class for working with GitHub markdown.
5
- # Supports file inclusion.
6
- #
7
- # @author Burdette Lamar
8
4
  class MarkdownHelper
9
5
 
10
6
  class MarkdownHelperError < RuntimeError; end
@@ -13,14 +9,19 @@ class MarkdownHelper
13
9
  class TocHeadingsError < MarkdownHelperError; end
14
10
  class OptionError < MarkdownHelperError; end
15
11
  class EnvironmentError < MarkdownHelperError; end
12
+ class InvalidTocTitleError < MarkdownHelperError; end
13
+ class MisplacedPageTocError < MarkdownHelperError; end
14
+ class MultiplePageTocError < MarkdownHelperError; end
16
15
 
17
- IMAGE_REGEXP = /!\[([^\[]+)\]\(([^)]+)\)/
18
16
  INCLUDE_REGEXP = /^@\[([^\[]+)\]\(([^)]+)\)$/
19
17
 
20
18
  attr_accessor :pristine
21
19
 
22
20
  def initialize(options = {})
23
21
  # Confirm that we're in a git project.
22
+ # This is necessary so that we can prune file paths in the tests,
23
+ # which otherwise would fail because of differing installation directories.
24
+ # It also allows pruned paths to be used in the inserted comments (when not pristine).
24
25
  MarkdownHelper.git_clone_dir_path
25
26
  default_options = {
26
27
  :pristine => false,
@@ -36,19 +37,6 @@ class MarkdownHelper
36
37
  end
37
38
  end
38
39
 
39
- # Merges external files into markdown text.
40
- # @param template_file_path [String] the path to the input template markdown file, usually containing include pragmas.
41
- # @param markdown_file_path [String] the path to the output merged markdown file.
42
- # @return [String] the resulting markdown text.
43
- #
44
- # @example pragma to include text as a highlighted code block.
45
- # @[ruby](foo.rb)
46
- #
47
- # @example pragma to include text as a plain code block.
48
- # @[:code_block](foo.xyz)
49
- #
50
- # @example pragma to include text markdown, to be rendered as markdown.
51
- # @[:markdown](foo.md)
52
40
  def include(template_file_path, markdown_file_path)
53
41
  send(:generate_file, template_file_path, markdown_file_path, __method__) do |input_lines, output_lines|
54
42
  send(:include_files, template_file_path, input_lines, output_lines, Inclusions.new)
@@ -56,41 +44,17 @@ class MarkdownHelper
56
44
  end
57
45
 
58
46
  def create_page_toc(markdown_file_path, toc_file_path)
47
+ message = <<EOT
48
+ Method create_page_toc is deprecated.
49
+ Please use method include with embedded :page_toc treatment.
50
+ See https://github.com/BurdetteLamar/markdown_helper/blob/master/markdown/use_cases/include_files/include_page_toc/use_case.md#include-page-toc.
51
+ EOT
52
+ warn(message)
59
53
  send(:generate_file, markdown_file_path, toc_file_path, __method__) do |input_lines, output_lines|
60
54
  send(:_create_page_toc, input_lines, output_lines)
61
55
  end
62
56
  end
63
57
 
64
- # Resolves relative image paths to absolute urls in markdown text.
65
- # @param template_file_path [String] the path to the input template markdown file, usually containing image pragmas.
66
- # @param markdown_file_path [String] the path to the output resolved markdown file.
67
- # @return [String] the resulting markdown text.
68
- #
69
- # This matters because when markdown becomes part of a Ruby gem,
70
- # its images will have been relocated in the documentation at RubyDoc.info, breaking the paths.
71
- # The resolved (absolute) urls, however, will still be valid.
72
- #
73
- # ENV['REPO_USER'] and ENV['REPO_NAME'] must give the user name and repository name of the relevant GitHub repository.
74
- # must give the repo name of the relevant GitHub repository.
75
- #
76
- # @example pragma for an image:
77
- # ![image_icon](images/image.png)
78
- #
79
- # The path resolves to:
80
- #
81
- # image_path = File.join(
82
- # "https://raw.githubusercontent.com/#{repo_user}/#{repo_name}/master",
83
- # relative_file_path,
84
- # )
85
- def resolve(template_file_path, markdown_file_path)
86
- # Method :generate_file does the first things, yields the block, does the last things.
87
- warn("Method :resolve is deprecated")
88
- send(:generate_file, template_file_path, markdown_file_path, __method__) do |input_lines, output_lines|
89
- send(:resolve_images, template_file_path, input_lines, output_lines)
90
- end
91
- end
92
- alias resolve_image_urls resolve
93
-
94
58
  private
95
59
 
96
60
  class Heading
@@ -115,8 +79,14 @@ class MarkdownHelper
115
79
  self.new(level, title)
116
80
  end
117
81
 
82
+
118
83
  def link
119
- anchor = title.gsub(/\W+/, '-').downcase
84
+ remove_regexp = /[\#\(\)\[\]\{\}\.\?\+\*\`\"\']+/
85
+ to_hyphen_regexp = /\W+/
86
+ anchor = title.
87
+ gsub(remove_regexp, '').
88
+ gsub(to_hyphen_regexp, '-').
89
+ downcase
120
90
  "[#{title}](##{anchor})"
121
91
  end
122
92
 
@@ -126,16 +96,6 @@ class MarkdownHelper
126
96
  "<!--#{text}-->\n"
127
97
  end
128
98
 
129
- def repo_user_and_name
130
- repo_user = ENV['REPO_USER']
131
- repo_name = ENV['REPO_NAME']
132
- unless repo_user and repo_name
133
- message = 'ENV values for both REPO_USER and REPO_NAME must be defined.'
134
- raise EnvironmentError.new(message)
135
- end
136
- [repo_user, repo_name]
137
- end
138
-
139
99
  def generate_file(template_file_path, markdown_file_path, method)
140
100
  unless File.readable?(template_file_path)
141
101
  message = [
@@ -152,44 +112,104 @@ class MarkdownHelper
152
112
  yield input_lines, output_lines
153
113
  output_lines.push(MarkdownHelper.comment(" <<<<<< END GENERATED FILE (#{method.to_s}): SOURCE #{template_path_in_project} ")) unless pristine
154
114
  end
155
- output = output_lines.join('')
156
- File.write(markdown_file_path, output)
157
- output
115
+ File.open(markdown_file_path, 'w') do |file|
116
+ output_lines.each do |line|
117
+ file.write(line)
118
+ end
119
+ end
158
120
  end
159
121
 
160
122
  def _create_page_toc(input_lines, output_lines)
161
- level_one_seen = false
123
+ first_heading_level = nil
162
124
  input_lines.each do |input_line|
163
- input_line.chomp!
164
- heading = Heading.parse(input_line)
125
+ line = input_line.chomp
126
+ heading = Heading.parse(line)
165
127
  next unless heading
166
- unless level_one_seen || heading.level == 1
167
- message = "First heading must be level 1, not '#{input_line}'"
168
- raise TocHeadingsError.new(message)
169
- end
170
- level_one_seen = true
171
- indentation = ' ' * heading.level
128
+ first_heading_level ||= heading.level
129
+ indentation = ' ' * (heading.level - first_heading_level)
172
130
  output_line = "#{indentation}- #{heading.link}"
173
131
  output_lines.push("#{output_line}\n")
174
132
  end
175
133
  end
176
134
 
177
135
  def include_files(includer_file_path, input_lines, output_lines, inclusions)
178
-
136
+ markdown_lines = []
137
+ page_toc_inclusion = nil
179
138
  input_lines.each_with_index do |input_line, line_index|
180
139
  match_data = input_line.match(INCLUDE_REGEXP)
181
140
  unless match_data
182
- output_lines.push(input_line)
141
+ markdown_lines.push(input_line)
183
142
  next
184
143
  end
185
144
  treatment = match_data[1]
186
145
  cited_includee_file_path = match_data[2]
187
- inclusions.include(
146
+ new_inclusion = Inclusion.new(
188
147
  input_line.chomp,
189
148
  includer_file_path,
190
149
  line_index + 1,
191
150
  cited_includee_file_path,
192
- treatment,
151
+ treatment
152
+ )
153
+ case treatment
154
+ when ':markdown'
155
+ inclusions.include(
156
+ new_inclusion,
157
+ markdown_lines,
158
+ self
159
+ )
160
+ when ':page_toc'
161
+ unless inclusions.inclusions.size == 0
162
+ message = 'Page TOC must be in outermost markdown file.'
163
+ raise MisplacedPageTocError.new(message)
164
+ end
165
+ unless page_toc_inclusion.nil?
166
+ message = 'Only one page TOC allowed.'
167
+ raise MultiplePageTocError.new(message)
168
+ end
169
+ page_toc_inclusion = new_inclusion
170
+ toc_title = match_data[2]
171
+ title_regexp = /^\#{1,6}\s/
172
+ unless toc_title.match(title_regexp)
173
+ message = "TOC title must be a valid markdown header, not #{toc_title}"
174
+ raise InvalidTocTitleError.new(message)
175
+ end
176
+ page_toc_inclusion.page_toc_title = toc_title
177
+ page_toc_inclusion.page_toc_line = input_line
178
+ markdown_lines.push(input_line)
179
+ else
180
+ markdown_lines.push(input_line)
181
+ end
182
+ end
183
+ # If needed, create page TOC and insert into markdown_lines.
184
+ unless page_toc_inclusion.nil?
185
+ toc_lines = [
186
+ page_toc_inclusion.page_toc_title + "\n",
187
+ '',
188
+ ]
189
+ page_toc_index = markdown_lines.index(page_toc_inclusion.page_toc_line)
190
+ lines_to_scan = markdown_lines[page_toc_index + 1..-1]
191
+ _create_page_toc(lines_to_scan, toc_lines)
192
+ markdown_lines.delete_at(page_toc_index)
193
+ markdown_lines.insert(page_toc_index, *toc_lines)
194
+ end
195
+ # Now review the markdown and include everything.
196
+ markdown_lines.each_with_index do |markdown_line, line_index|
197
+ match_data = markdown_line.match(INCLUDE_REGEXP)
198
+ unless match_data
199
+ output_lines.push(markdown_line)
200
+ next
201
+ end
202
+ treatment = match_data[1]
203
+ cited_includee_file_path = match_data[2]
204
+ new_inclusion = Inclusion.new(
205
+ markdown_line.chomp,
206
+ includer_file_path,
207
+ line_index + 1,
208
+ cited_includee_file_path,
209
+ treatment
210
+ )
211
+ inclusions.include(
212
+ new_inclusion,
193
213
  output_lines,
194
214
  self
195
215
  )
@@ -197,7 +217,7 @@ class MarkdownHelper
197
217
  end
198
218
 
199
219
  def self.git_clone_dir_path
200
- git_dir = `git rev-parse --git-dir`.chomp
220
+ git_dir = `git rev-parse --show-toplevel`.chomp
201
221
  unless $?.success?
202
222
  message = <<EOT
203
223
 
@@ -206,71 +226,13 @@ That is, the working directory one of its parents must be a .git directory.
206
226
  EOT
207
227
  raise RuntimeError.new(message)
208
228
  end
209
- if git_dir == '.git'
210
- path = `pwd`.chomp
211
- else
212
- path = File.dirname(git_dir).chomp
213
- end
214
- realpath = Pathname.new(path.sub(%r|/c/|, 'C:/')).realpath
215
- realpath.to_s
229
+ git_dir
216
230
  end
217
231
 
218
232
  def self.path_in_project(path)
219
233
  path.sub(MarkdownHelper.git_clone_dir_path + '/', '')
220
234
  end
221
235
 
222
- def resolve_images(template_file_path, input_lines, output_lines)
223
- input_lines.each do |input_line|
224
- scan_data = input_line.scan(IMAGE_REGEXP)
225
- if scan_data.empty?
226
- output_lines.push(input_line)
227
- next
228
- end
229
- output_lines.push(MarkdownHelper.comment(" >>>>>> BEGIN RESOLVED IMAGES: INPUT-LINE '#{input_line}' ")) unless pristine
230
- output_line = input_line
231
- scan_data.each do |alt_text, path_and_attributes|
232
- original_image_file_path, attributes_s = path_and_attributes.split(/\s?\|\s?/, 2)
233
-
234
- # Attributes.
235
- attributes = attributes_s ? attributes_s.split(/\s+/) : []
236
- formatted_attributes = ['']
237
- attributes.each do |attribute|
238
- name, value = attribute.split('=', 2)
239
- formatted_attributes.push(format('%s="%s"', name, value))
240
- end
241
- formatted_attributes_s = formatted_attributes.join(' ')
242
-
243
- if original_image_file_path.start_with?('http')
244
- image_path = original_image_file_path
245
- else
246
- absolute_template_file_path = File.absolute_path(template_file_path)
247
- template_dir_path = File.dirname(absolute_template_file_path)
248
- absolute_file_path = File.join(
249
- template_dir_path,
250
- original_image_file_path,
251
- )
252
- absolute_file_path = Pathname.new(absolute_file_path).cleanpath.to_s
253
- relative_image_file_path = MarkdownHelper.path_in_project(absolute_file_path)
254
- repo_user, repo_name = repo_user_and_name
255
- image_path = File.join(
256
- "https://raw.githubusercontent.com/#{repo_user}/#{repo_name}/master",
257
- relative_image_file_path,
258
- )
259
- end
260
- img_element = format(
261
- '<img src="%s" alt="%s"%s>',
262
- image_path,
263
- alt_text,
264
- formatted_attributes_s,
265
- )
266
- output_line = output_line.sub(IMAGE_REGEXP, img_element)
267
- end
268
- output_lines.push(output_line)
269
- output_lines.push(MarkdownHelper.comment(" <<<<<< END RESOLVED IMAGES: INPUT-LINE '#{input_line}' ")) unless pristine
270
- end
271
-
272
- end
273
-
274
236
  class Inclusions
275
237
 
276
238
  attr_accessor :inclusions
@@ -280,15 +242,11 @@ EOT
280
242
  end
281
243
 
282
244
  def include(
283
- include_description,
284
- includer_file_path,
285
- includer_line_number,
286
- cited_includee_file_path,
287
- treatment,
288
- output_lines,
289
- markdown_helper
245
+ new_inclusion,
246
+ output_lines,
247
+ markdown_helper
290
248
  )
291
- treatment = case treatment
249
+ treatment = case new_inclusion.treatment
292
250
  when ':code_block'
293
251
  :code_block
294
252
  when ':markdown'
@@ -302,18 +260,12 @@ EOT
302
260
  when ':pre'
303
261
  :pre
304
262
  else
305
- treatment
263
+ new_inclusion.treatment
306
264
  end
307
- new_inclusion = Inclusion.new(
308
- include_description,
309
- includer_file_path,
310
- includer_line_number,
311
- cited_includee_file_path
312
- )
313
265
  if treatment == :markdown
314
266
  check_circularity(new_inclusion)
315
267
  end
316
- includee_path_in_project = MarkdownHelper.path_in_project(new_inclusion.absolute_includee_file_path)
268
+ includee_path_in_project = MarkdownHelper.path_in_project(new_inclusion.absolute_includee_file_path)
317
269
  output_lines.push(MarkdownHelper.comment(" >>>>>> BEGIN INCLUDED FILE (#{treatment}): SOURCE #{includee_path_in_project} ")) unless markdown_helper.pristine
318
270
  begin
319
271
  include_lines = File.readlines(new_inclusion.absolute_includee_file_path)
@@ -329,7 +281,7 @@ EOT
329
281
  end
330
282
  last_line = include_lines.last
331
283
  unless last_line && last_line.match("\n")
332
- message = "Warning: Included file has no trailing newline: #{cited_includee_file_path}"
284
+ message = "Warning: Included file has no trailing newline: #{new_inclusion.cited_includee_file_path}"
333
285
  warn(message)
334
286
  end
335
287
  case treatment
@@ -346,7 +298,7 @@ EOT
346
298
  output_lines.push("</pre>\n")
347
299
  else
348
300
  # Use the file name as a label.
349
- file_name_line = format("```%s```:\n", File.basename(cited_includee_file_path))
301
+ file_name_line = format("```%s```:\n", File.basename(new_inclusion.cited_includee_file_path))
350
302
  output_lines.push(file_name_line)
351
303
  # Put into code block.
352
304
  language = treatment == :code_block ? '' : treatment
@@ -389,65 +341,6 @@ EOT
389
341
  lines.join("\n")
390
342
  end
391
343
 
392
- def self.assert_io_exception(test, expected_exception_class, expected_label, expected_file_path, e)
393
- test.assert_kind_of(expected_exception_class, e)
394
- lines = e.message.split("\n")
395
- actual_label = lines.shift
396
- test.assert_equal(expected_label, actual_label)
397
- actual_file_path = lines.shift
398
- test.assert_equal(expected_file_path.inspect, actual_file_path)
399
- end
400
-
401
- def self.assert_inclusion_exception(test, expected_exception_class, exception_label, expected_inclusions, e)
402
- test.assert_kind_of(expected_exception_class, e)
403
- lines = e.message.split("\n")
404
- label_line = lines.shift
405
- test.assert_equal(exception_label, label_line)
406
- backtrace_line = lines.shift
407
- test.assert_equal(BACKTRACE_LABEL, backtrace_line)
408
- level_line_count = 1 + Inclusion::LINE_COUNT
409
- level_count = lines.size / level_line_count
410
- # Backtrace levels are innermost first, opposite of inclusions.
411
- reversed_inclusions = expected_inclusions.inclusions.reverse
412
- (0...level_count).each do |level_index|
413
- level_line = lines.shift
414
- inclusion_lines = lines.shift(Inclusion::LINE_COUNT)
415
- test.assert_equal("#{LEVEL_LABEL} #{level_index}:", level_line)
416
- expected_inclusion = reversed_inclusions[level_index]
417
- expected_inclusion.assert_lines(test, level_index, inclusion_lines)
418
- end
419
- end
420
-
421
- def self.assert_circular_exception(test, expected_inclusions, e)
422
- self.assert_inclusion_exception(
423
- test,
424
- CircularIncludeError,
425
- CIRCULAR_EXCEPTION_LABEL,
426
- expected_inclusions,
427
- e
428
- )
429
- end
430
-
431
- def self.assert_includee_missing_exception(test, expected_inclusions, e)
432
- self.assert_inclusion_exception(
433
- test,
434
- Exception,
435
- MISSING_INCLUDEE_EXCEPTION_LABEL,
436
- expected_inclusions,
437
- e
438
- )
439
- end
440
-
441
- def self.assert_template_exception(test, expected_file_path, e)
442
- self.assert_io_exception(
443
- test,
444
- Exception,
445
- UNREADABLE_INPUT_EXCEPTION_LABEL,
446
- expected_file_path,
447
- e
448
- )
449
- end
450
-
451
344
  end
452
345
 
453
346
  class Inclusion
@@ -460,19 +353,23 @@ EOT
460
353
  :include_description,
461
354
  :absolute_includee_file_path,
462
355
  :cited_includee_file_path,
463
- :include_description
356
+ :treatment,
357
+ :page_toc_title,
358
+ :page_toc_line
464
359
 
465
360
  def initialize(
466
361
  include_description,
467
362
  includer_file_path,
468
363
  includer_line_number,
469
- cited_includee_file_path
364
+ cited_includee_file_path,
365
+ treatment
470
366
  )
471
367
  self.include_description = include_description
472
368
  self.includer_file_path = includer_file_path
473
369
  self.includer_line_number = includer_line_number
474
370
  self.cited_includee_file_path = cited_includee_file_path
475
371
  self.absolute_includee_file_path = absolute_includee_file_path
372
+ self.treatment = treatment
476
373
  self.absolute_includee_file_path = File.absolute_path(File.join(
477
374
  File.dirname(includer_file_path),
478
375
  cited_includee_file_path,
@@ -485,10 +382,11 @@ EOT
485
382
  Pathname.new(absolute_includee_file_path).realpath.to_s
486
383
  end
487
384
 
385
+ def indentation(level)
386
+ ' ' * level
387
+ end
388
+
488
389
  def to_lines(indentation_level)
489
- def indentation(level)
490
- ' ' * level
491
- end
492
390
  relative_inluder_file_path = MarkdownHelper.path_in_project(includer_file_path)
493
391
  relative_inludee_file_path = MarkdownHelper.path_in_project(absolute_includee_file_path)
494
392
  text = <<EOT
@@ -501,37 +399,6 @@ EOT
501
399
  text.split("\n")
502
400
  end
503
401
 
504
- def assert_lines(test, level_index, actual_lines)
505
- level_label = "Level #{level_index}:"
506
- # Includer label.
507
- includee_label = actual_lines.shift
508
- test.assert_match(/^\s*Includer:$/, includee_label, level_label)
509
- # Includer locatioin.
510
- location = actual_lines.shift
511
- message = "#{level_label} includer location"
512
- test.assert_match(/^\s*Location:/, location, message)
513
- includer_realpath = Pathname.new(includer_file_path).realpath.to_s
514
- relative_path = MarkdownHelper.path_in_project(includer_realpath)
515
- r = Regexp.new(Regexp.escape("#{relative_path}:#{includer_line_number}") + '$')
516
- test.assert_match(r, location, message)
517
- # Include description.
518
- description = actual_lines.shift
519
- message = "#{level_label} include description"
520
- test.assert_match(/^\s*Include description:/, description, message)
521
- r = Regexp.new(Regexp.escape("#{include_description}") + '$')
522
- test.assert_match(r, description, message)
523
- # Includee label.
524
- includee_label = actual_lines.shift
525
- test.assert_match(/^\s*Includee:$/, includee_label, level_label)
526
- # Includee file path.
527
- includee_file_path = actual_lines.shift
528
- message = "#{level_label} includee cited file path"
529
- test.assert_match(/^\s*File path:/, includee_file_path, message)
530
- relative_path = MarkdownHelper.path_in_project(absolute_includee_file_path)
531
- r = Regexp.new(Regexp.escape("#{relative_path}") + '$')
532
- test.assert_match(r, includee_file_path, message)
533
- end
534
-
535
402
  end
536
403
 
537
404
  end