markdown_helper 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cee806406f109c72b11a7a4f78c8ad7efc59706f278a0a5b654267e3ae38ddf6
4
- data.tar.gz: 4e49e14011eb429bd5d523a314572aff3693876b07fa50b52d9cfecf693fcd3d
3
+ metadata.gz: '09204d578d4034b5940afc983b9d3989adff2d1b05763b0e6e867e3183b338c8'
4
+ data.tar.gz: a90232dc47c8d901f1fa1a5bed7964e0deee6fb3b3bd9d2713f46ea105b162b2
5
5
  SHA512:
6
- metadata.gz: 5d4c4a25171b3ac8df8cfd84766843ae7c8d599c896d70b1d70854353dc7f0cb06741d1832640f5f24fdc500285bf16684f09d7d08450a48c73680d0033cab9f
7
- data.tar.gz: 5f81f39ad84273fa2367a03e7bc18773190c97398ff7ac3c8834eac464a2a9dbe8bbedbf566fee79489124d2458fc32bfec96534b85f2edd4a7cadbb1e5dd63c
6
+ metadata.gz: ad9d3e8cbf0a1fa17eba25579c02165571e5408ea979747600aa6db74b52122fd2157d61d6f2a65e7302eac52a443e40343d10d0c291eae7912d64ccd099ed6f
7
+ data.tar.gz: 4ee21575e5d049259b9c365ab9842d904127ebe8df9f023304bcb35c34242f3eb81edf37a055aee6cdce61283c635fb4d38bb4ffbfa7cdc54f6b7f8584fb8672
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- markdown_helper (2.1.0)
4
+ markdown_helper (2.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2018 Burdette Lamar
3
+ Copyright (c) 2018-2019 Burdette Lamar
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,16 +1,11 @@
1
- <!-- >>>>>> BEGIN GENERATED FILE (include): SOURCE README.template.md -->
1
+ <!-- >>>>>> BEGIN GENERATED FILE (include): SOURCE markdown/readme/README.template.md -->
2
2
  # Markdown Helper
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
6
  ## What's New?
7
7
 
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.
8
+ Command line creation of page TOC (table of contents), previously deprecated, is removed.
14
9
 
15
10
  ## Contents
16
11
  - [What's a Markdown Helper?](#whats-a-markdown-helper)
@@ -172,7 +167,7 @@ where:
172
167
 
173
168
  <!-- >>>>>> BEGIN INCLUDED FILE (code_block): SOURCE markdown/readme/include.md -->
174
169
  ```include.md```:
175
- ```code_block
170
+ ```
176
171
  @[ruby](my_ruby.rb)
177
172
 
178
173
  @[:code_block](my_language.xyzzy)
@@ -213,4 +208,4 @@ I have opened some enhancement Issues in the GitHub [markdown_helper](https://gi
213
208
  * [Pagination](https://github.com/BurdetteLamar/markdown_helper/issues/40): series of markdown pages connected by prev/next navigation links.
214
209
 
215
210
  Feel free to comment on any of these, or to add more Issues (enhancement or otherwise).
216
- <!-- <<<<<< END GENERATED FILE (include): SOURCE README.template.md -->
211
+ <!-- <<<<<< END GENERATED FILE (include): SOURCE markdown/readme/README.template.md -->
data/Rakefile CHANGED
@@ -26,7 +26,6 @@ namespace :build do
26
26
  desc 'Build usage for executables'
27
27
  task :usages do
28
28
  %w/
29
- create_page_toc
30
29
  include
31
30
  /.each do |executable_name|
32
31
  usage_text = `ruby bin/_#{executable_name} --help`
@@ -1,19 +1,20 @@
1
1
  require 'pathname'
2
+
2
3
  require 'markdown_helper/version'
3
4
 
4
5
  class MarkdownHelper
5
6
 
6
7
  class MarkdownHelperError < RuntimeError; end
7
- class CircularIncludeError < MarkdownHelperError; end
8
- class UnreadableInputError < MarkdownHelperError; end
9
- class TocHeadingsError < MarkdownHelperError; end
10
8
  class OptionError < MarkdownHelperError; end
11
- class EnvironmentError < MarkdownHelperError; end
12
- class InvalidTocTitleError < MarkdownHelperError; end
13
- class MisplacedPageTocError < MarkdownHelperError; end
14
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
15
 
16
16
  INCLUDE_REGEXP = /^@\[([^\[]+)\]\(([^)]+)\)$/
17
+ INCLUDE_MARKDOWN_REGEXP = /^@\[:markdown\]\(([^)]+)\)$/
17
18
 
18
19
  attr_accessor :pristine
19
20
 
@@ -35,187 +36,192 @@ class MarkdownHelper
35
36
  send(setter_method, value)
36
37
  merged_options.delete(method)
37
38
  end
39
+ @inclusions = []
38
40
  end
39
41
 
40
42
  def include(template_file_path, markdown_file_path)
41
- send(:generate_file, template_file_path, markdown_file_path, __method__) do |input_lines, output_lines|
42
- send(:include_files, template_file_path, input_lines, output_lines, Inclusions.new)
43
- end
44
- end
45
-
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)
53
- send(:generate_file, markdown_file_path, toc_file_path, __method__) do |input_lines, output_lines|
54
- send(:_create_page_toc, input_lines, output_lines)
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
55
49
  end
56
50
  end
57
51
 
58
52
  private
59
53
 
60
- class Heading
61
-
62
- attr_accessor :level, :title
63
-
64
- def initialize(level, title)
65
- self.level = level
66
- self.title = title
67
- end
68
-
69
- def self.parse(line)
70
- # Four leading spaces not allowed (but three are allowed).
71
- return nil if line.start_with?(' ' * 4)
72
- stripped_line = line.sub(/^ */, '')
73
- # Now must begin with hash marks and space.
74
- return nil unless stripped_line.match(/^#+ /)
75
- hash_marks, title = stripped_line.split(' ', 2)
76
- level = hash_marks.size
77
- # Seventh level heading not allowed.
78
- return nil if level > 6
79
- self.new(level, title)
80
- end
81
-
82
-
83
- def link
84
- remove_regexp = /[\#\(\)\[\]\{\}\.\?\+\*\`\"\']+/
85
- to_hyphen_regexp = /\W+/
86
- anchor = title.
87
- gsub(remove_regexp, '').
88
- gsub(to_hyphen_regexp, '-').
89
- downcase
90
- "[#{title}](##{anchor})"
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} "))
91
61
  end
92
-
62
+ output_lines.push('')
63
+ output = output_lines.join("\n")
64
+ File.write(markdown_file_path, output)
93
65
  end
94
66
 
95
- def self.comment(text)
96
- "<!--#{text}-->\n"
97
- end
98
-
99
- def generate_file(template_file_path, markdown_file_path, method)
100
- unless File.readable?(template_file_path)
101
- message = [
102
- Inclusions::UNREADABLE_INPUT_EXCEPTION_LABEL,
103
- template_file_path.inspect,
104
- ].join("\n")
105
- raise UnreadableInputError.new(message)
106
- end
107
- output_lines = []
108
- File.open(template_file_path, 'r') do |template_file|
109
- template_path_in_project = MarkdownHelper.path_in_project(template_file_path)
110
- output_lines.push(MarkdownHelper.comment(" >>>>>> BEGIN GENERATED FILE (#{method.to_s}): SOURCE #{template_path_in_project} ")) unless pristine
111
- input_lines = template_file.readlines
112
- yield input_lines, output_lines
113
- output_lines.push(MarkdownHelper.comment(" <<<<<< END GENERATED FILE (#{method.to_s}): SOURCE #{template_path_in_project} ")) unless pristine
114
- end
115
- File.open(markdown_file_path, 'w') do |file|
116
- output_lines.each do |line|
117
- file.write(line)
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
+ message = [
72
+ 'Could not read template file:',
73
+ MarkdownHelper.backtrace_inclusions(@inclusions),
74
+ ].join("\n")
75
+ e = UnreadableTemplateError.new(message)
76
+ e.set_backtrace([])
77
+ raise e
78
+ end
79
+ template_lines = File.readlines(template_file_path)
80
+ template_lines.each_with_index do |template_line, i|
81
+ template_line.chomp!
82
+ treatment, includee_file_path = *parse_include(template_line)
83
+ if treatment.nil?
84
+ markdown_lines.push(template_line)
85
+ next
86
+ end
87
+ if treatment == ':page_toc'
88
+ markdown_lines.push(template_line)
89
+ next
90
+ end
91
+ inclusion = Inclusion.new(
92
+ template_file_path,
93
+ template_line,
94
+ i,
95
+ treatment,
96
+ includee_file_path,
97
+ @inclusions
98
+ )
99
+ treatment.sub!(/^:/, '')
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
+ else
116
+ markdown_lines.push(template_line)
117
+ next
118
+ end
119
+ @inclusions.pop
120
+ add_inclusion_comments(treatment, includee_file_path, markdown_lines)
118
121
  end
122
+ markdown_lines
119
123
  end
120
124
  end
121
125
 
122
- def _create_page_toc(input_lines, output_lines)
126
+ def include_page_toc(template_lines)
127
+ toc_line_index = nil
128
+ toc_title = nil
129
+ template_lines.each_with_index do |template_line, i|
130
+ match_data = template_line.match(INCLUDE_REGEXP)
131
+ next unless match_data
132
+ treatment = match_data[1]
133
+ next unless treatment == ':page_toc'
134
+ unless toc_line_index.nil?
135
+ message = 'Multiple page TOC not allowed'
136
+ raise MultiplePageTocError.new(message)
137
+ end
138
+ toc_line_index = i
139
+ toc_title = match_data[2]
140
+ title_regexp = /^\#{1,6}\s/
141
+ unless toc_title.match(title_regexp)
142
+ message = "TOC title must be a valid markdown header, not #{toc_title}"
143
+ raise InvalidTocTitleError.new(message)
144
+ end
145
+ end
146
+ return template_lines unless toc_line_index
147
+ toc_lines = [toc_title]
123
148
  first_heading_level = nil
124
- input_lines.each do |input_line|
149
+ template_lines.each_with_index do |input_line, i|
150
+ next if i < toc_line_index
125
151
  line = input_line.chomp
126
152
  heading = Heading.parse(line)
127
153
  next unless heading
128
154
  first_heading_level ||= heading.level
129
155
  indentation = ' ' * (heading.level - first_heading_level)
130
- output_line = "#{indentation}- #{heading.link}"
131
- output_lines.push("#{output_line}\n")
156
+ toc_line = "#{indentation}- #{heading.link}"
157
+ toc_lines.push(toc_line)
132
158
  end
159
+ template_lines.delete_at(toc_line_index)
160
+ template_lines.insert(toc_line_index, *toc_lines)
161
+ template_lines
133
162
  end
134
163
 
135
- def include_files(includer_file_path, input_lines, output_lines, inclusions)
136
- markdown_lines = []
137
- page_toc_inclusion = nil
138
- input_lines.each_with_index do |input_line, line_index|
139
- match_data = input_line.match(INCLUDE_REGEXP)
140
- unless match_data
141
- markdown_lines.push(input_line)
164
+ def include_all(template_file_path, template_lines, output_lines)
165
+ template_lines.each_with_index do |template_line, i|
166
+ treatment, includee_file_path = *parse_include(template_line)
167
+ if treatment.nil?
168
+ output_lines.push(template_line)
142
169
  next
143
170
  end
144
- treatment = match_data[1]
145
- cited_includee_file_path = match_data[2]
146
- new_inclusion = Inclusion.new(
147
- input_line.chomp,
148
- includer_file_path,
149
- line_index + 1,
150
- cited_includee_file_path,
151
- treatment
171
+ inclusion = Inclusion.new(
172
+ template_file_path,
173
+ template_line,
174
+ i,
175
+ treatment,
176
+ includee_file_path,
177
+ @inclusions
152
178
  )
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)
179
+ check_includee(inclusion)
180
+ @inclusions.push(inclusion)
181
+ file_marker = format('```%s```:', File.basename(includee_file_path))
182
+ begin_backticks = '```'
183
+ end_backticks = '```'
184
+ begin_backticks += treatment unless treatment.start_with?(':')
185
+ includee_lines = File.read(includee_file_path).split("\n")
186
+ includee_lines.unshift(begin_backticks)
187
+ includee_lines.unshift(file_marker)
188
+ includee_lines.push(end_backticks)
189
+ add_inclusion_comments(treatment.sub(':', ''), includee_file_path, includee_lines)
190
+ output_lines.concat(includee_lines)
194
191
  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,
213
- output_lines,
214
- self
215
- )
192
+ end
193
+
194
+ def add_inclusion_comments(treatment, includee_file_path, lines)
195
+ path_in_project = MarkdownHelper.path_in_project(includee_file_path)
196
+ unless pristine
197
+ comment = format(' >>>>>> BEGIN INCLUDED FILE (%s): SOURCE %s ', treatment, path_in_project)
198
+ lines.unshift(MarkdownHelper.comment(comment))
199
+ comment = format(' <<<<<< END INCLUDED FILE (%s): SOURCE %s ', treatment, path_in_project)
200
+ lines.push(MarkdownHelper.comment(comment))
216
201
  end
217
202
  end
218
203
 
204
+ def parse_include(line)
205
+ match_data = line.match(INCLUDE_REGEXP)
206
+ return [nil, nil] unless match_data
207
+ treatment = match_data[1]
208
+ includee_file_path = match_data[2]
209
+ [treatment, includee_file_path]
210
+ end
211
+
212
+ def self.path_in_project(file_path)
213
+ abs_path = File.absolute_path(file_path)
214
+ abs_path.sub(self.git_clone_dir_path + '/', '')
215
+ end
216
+
217
+ def self.comment(text)
218
+ "<!--#{text}-->"
219
+ end
220
+
221
+ def self.pre(text)
222
+ "<pre>\n#{text}</pre>"
223
+ end
224
+
219
225
  def self.git_clone_dir_path
220
226
  git_dir = `git rev-parse --show-toplevel`.chomp
221
227
  unless $?.success?
@@ -229,157 +235,122 @@ EOT
229
235
  git_dir
230
236
  end
231
237
 
232
- def self.path_in_project(path)
233
- path.sub(MarkdownHelper.git_clone_dir_path + '/', '')
234
- end
238
+ class Heading
235
239
 
236
- class Inclusions
240
+ attr_accessor :level, :title
237
241
 
238
- attr_accessor :inclusions
242
+ def initialize(level, title)
243
+ self.level = level
244
+ self.title = title
245
+ end
239
246
 
240
- def initialize
241
- self.inclusions = []
247
+ def self.parse(line)
248
+ # Four leading spaces not allowed (but three are allowed).
249
+ return nil if line.start_with?(' ' * 4)
250
+ stripped_line = line.sub(/^ */, '')
251
+ # Now must begin with hash marks and space.
252
+ return nil unless stripped_line.match(/^#+ /)
253
+ hash_marks, title = stripped_line.split(' ', 2)
254
+ level = hash_marks.size
255
+ # Seventh level heading not allowed.
256
+ return nil if level > 6
257
+ self.new(level, title)
242
258
  end
243
259
 
244
- def include(
245
- new_inclusion,
246
- output_lines,
247
- markdown_helper
248
- )
249
- treatment = case new_inclusion.treatment
250
- when ':code_block'
251
- :code_block
252
- when ':markdown'
253
- :markdown
254
- when ':verbatim'
255
- message = "Treatment ':verbatim' is deprecated; please use treatment ':markdown'."
256
- warn(message)
257
- :markdown
258
- when ':comment'
259
- :comment
260
- when ':pre'
261
- :pre
262
- else
263
- new_inclusion.treatment
264
- end
265
- if treatment == :markdown
266
- check_circularity(new_inclusion)
267
- end
268
- includee_path_in_project = MarkdownHelper.path_in_project(new_inclusion.absolute_includee_file_path)
269
- output_lines.push(MarkdownHelper.comment(" >>>>>> BEGIN INCLUDED FILE (#{treatment}): SOURCE #{includee_path_in_project} ")) unless markdown_helper.pristine
270
- begin
271
- include_lines = File.readlines(new_inclusion.absolute_includee_file_path)
272
- rescue => e
273
- inclusions.push(new_inclusion)
274
- message = [
275
- MISSING_INCLUDEE_EXCEPTION_LABEL,
276
- backtrace_inclusions,
277
- ].join("\n")
278
- e = UnreadableInputError.new(message)
279
- e.set_backtrace([])
280
- raise e
281
- end
282
- last_line = include_lines.last
283
- unless last_line && last_line.match("\n")
284
- message = "Warning: Included file has no trailing newline: #{new_inclusion.cited_includee_file_path}"
285
- warn(message)
286
- end
287
- case treatment
288
- when :markdown
289
- # Pass through unadorned, but honor any nested includes.
290
- inclusions.push(new_inclusion)
291
- markdown_helper.send(:include_files, new_inclusion.absolute_includee_file_path, include_lines, output_lines, self)
292
- inclusions.pop
293
- when :comment
294
- output_lines.push(MarkdownHelper.comment(include_lines.join('')))
295
- when :pre
296
- output_lines.push("<pre>\n")
297
- output_lines.push(include_lines.join(''))
298
- output_lines.push("</pre>\n")
299
- else
300
- # Use the file name as a label.
301
- file_name_line = format("```%s```:\n", File.basename(new_inclusion.cited_includee_file_path))
302
- output_lines.push(file_name_line)
303
- # Put into code block.
304
- language = treatment == :code_block ? '' : treatment
305
- output_lines.push("```#{language}\n")
306
- output_lines.push(*include_lines)
307
- output_lines.push("```\n")
308
- end
309
- output_lines.push(MarkdownHelper.comment(" <<<<<< END INCLUDED FILE (#{treatment}): SOURCE #{includee_path_in_project} ")) unless markdown_helper.pristine
260
+
261
+ def link
262
+ remove_regexp = /[\#\(\)\[\]\{\}\.\?\+\*\`\"\']+/
263
+ to_hyphen_regexp = /\W+/
264
+ anchor = title.
265
+ gsub(remove_regexp, '').
266
+ gsub(to_hyphen_regexp, '-').
267
+ downcase
268
+ "[#{title}](##{anchor})"
310
269
  end
311
270
 
312
- CIRCULAR_EXCEPTION_LABEL = 'Includes are circular:'
313
- UNREADABLE_INPUT_EXCEPTION_LABEL = 'Could not read input file.'
314
- UNWRITABLE_OUTPUT_EXCEPTION_LABEL = 'Could not write output file.'
315
- MISSING_INCLUDEE_EXCEPTION_LABEL = 'Could not read include file,'
316
- LEVEL_LABEL = ' Level'
317
- BACKTRACE_LABEL = ' Backtrace (innermost include first):'
318
-
319
- def check_circularity(new_inclusion)
320
- previous_inclusions = inclusions.collect {|x| x.real_includee_file_path}
321
- previously_included = previous_inclusions.include?(new_inclusion.real_includee_file_path)
322
- if previously_included
323
- inclusions.push(new_inclusion)
324
- message = [
325
- CIRCULAR_EXCEPTION_LABEL,
326
- backtrace_inclusions,
327
- ].join("\n")
328
- e = MarkdownHelper::CircularIncludeError.new(message)
329
- e.set_backtrace([])
330
- raise e
331
- end
271
+ end
272
+
273
+ def check_circularity(inclusion)
274
+ included_file_paths = @inclusions.collect { |x| x.includee_real_file_path}
275
+ previously_included = included_file_paths.include?(inclusion.includee_real_file_path)
276
+ if previously_included
277
+ @inclusions.push(inclusion)
278
+ message = [
279
+ 'Includes are circular:',
280
+ MarkdownHelper.backtrace_inclusions(@inclusions),
281
+ ].join("\n")
282
+ e = MarkdownHelper::CircularIncludeError.new(message)
283
+ e.set_backtrace([])
284
+ raise e
332
285
  end
286
+ end
333
287
 
334
- def backtrace_inclusions
335
- lines = [BACKTRACE_LABEL]
336
- inclusions.reverse.each_with_index do |inclusion, i|
337
- lines.push("#{LEVEL_LABEL} #{i}:")
338
- level_lines = inclusion.to_lines(indentation_level = 3)
339
- lines.push(*level_lines)
340
- end
341
- lines.join("\n")
288
+ def check_includee(inclusion)
289
+ unless File.readable?(inclusion.includee_absolute_file_path)
290
+ @inclusions.push(inclusion)
291
+ message = [
292
+ 'Could not read includee file:',
293
+ MarkdownHelper.backtrace_inclusions(@inclusions),
294
+ ].join("\n")
295
+ e = MarkdownHelper::UnreadableIncludeeError.new(message)
296
+ e.set_backtrace([])
297
+ raise e
342
298
  end
343
299
 
344
300
  end
345
301
 
346
- class Inclusion
302
+ def self.backtrace_inclusions(inclusions)
303
+ lines = [' Backtrace (innermost include first):']
304
+ inclusions.reverse.each_with_index do |inclusion, i|
305
+ lines.push("#{' Level'} #{i}:")
306
+ level_lines = inclusion.to_lines(indentation_level = 3)
307
+ lines.push(*level_lines)
308
+ end
309
+ lines.join("\n")
310
+ end
347
311
 
348
- LINE_COUNT = 5
312
+ class Inclusion
349
313
 
350
314
  attr_accessor \
351
315
  :includer_file_path,
316
+ :includer_absolute_file_path,
317
+ :include_pragma,
318
+ :treatment,
352
319
  :includer_line_number,
353
- :include_description,
354
- :absolute_includee_file_path,
355
320
  :cited_includee_file_path,
356
- :treatment,
357
- :page_toc_title,
358
- :page_toc_line
321
+ :includee_absolute_file_path
359
322
 
360
323
  def initialize(
361
- include_description,
362
324
  includer_file_path,
325
+ include_pragma,
363
326
  includer_line_number,
327
+ treatment,
364
328
  cited_includee_file_path,
365
- treatment
366
- )
367
- self.include_description = include_description
329
+ inclusions
330
+ )
368
331
  self.includer_file_path = includer_file_path
332
+ self.include_pragma = include_pragma
369
333
  self.includer_line_number = includer_line_number
370
- self.cited_includee_file_path = cited_includee_file_path
371
- self.absolute_includee_file_path = absolute_includee_file_path
372
334
  self.treatment = treatment
373
- self.absolute_includee_file_path = File.absolute_path(File.join(
335
+ self.cited_includee_file_path = cited_includee_file_path
336
+
337
+ self.includer_absolute_file_path = File.absolute_path(includer_file_path)
338
+ unless File.exist?(self.includer_absolute_file_path)
339
+ fail self.includer_absolute_file_path
340
+ end
341
+
342
+ self.includee_absolute_file_path = File.absolute_path(File.join(
374
343
  File.dirname(includer_file_path),
375
344
  cited_includee_file_path,
376
- ))
345
+ ))
346
+ end
347
+
348
+ def includer_real_file_path
349
+ Pathname.new(includer_absolute_file_path).realpath.to_s
377
350
  end
378
351
 
379
- def real_includee_file_path
380
- # Would raise exception unless exists.
381
- return nil unless File.exist?(absolute_includee_file_path)
382
- Pathname.new(absolute_includee_file_path).realpath.to_s
352
+ def includee_real_file_path
353
+ Pathname.new(includee_absolute_file_path).realpath.to_s
383
354
  end
384
355
 
385
356
  def indentation(level)
@@ -388,11 +359,11 @@ EOT
388
359
 
389
360
  def to_lines(indentation_level)
390
361
  relative_inluder_file_path = MarkdownHelper.path_in_project(includer_file_path)
391
- relative_inludee_file_path = MarkdownHelper.path_in_project(absolute_includee_file_path)
362
+ relative_inludee_file_path = MarkdownHelper.path_in_project(includee_absolute_file_path)
392
363
  text = <<EOT
393
364
  #{indentation(indentation_level)}Includer:
394
365
  #{indentation(indentation_level+1)}Location: #{relative_inluder_file_path}:#{includer_line_number}
395
- #{indentation(indentation_level+1)}Include description: #{include_description}
366
+ #{indentation(indentation_level+1)}Include pragma: #{include_pragma}
396
367
  #{indentation(indentation_level)}Includee:
397
368
  #{indentation(indentation_level+1)}File path: #{relative_inludee_file_path}
398
369
  EOT
@@ -402,4 +373,3 @@ EOT
402
373
  end
403
374
 
404
375
  end
405
-