nandoc 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README +5 -4
- data/Rakefile +1 -1
- data/bin/nandoc +2 -1
- data/doc/FAQ.md +3 -0
- data/doc/PROVISO.md +39 -0
- data/doc/commands/diff.md +49 -0
- data/doc/svg/less-fonts.svg +2 -2
- data/lib/nandoc/cli/README.md +6 -0
- data/lib/nandoc/cli/command-methods.rb +38 -0
- data/lib/nandoc/cli/option-methods/exclusive-options.rb +56 -0
- data/lib/nandoc/cli/option-methods/option-enum.rb +64 -0
- data/lib/nandoc/cli/option-methods.rb +35 -0
- data/lib/nandoc/cli.rb +3 -0
- data/lib/nandoc/commands/create-nandoc-site.rb +9 -12
- data/lib/nandoc/commands/diff.rb +14 -11
- data/lib/nandoc/commands.rb +9 -0
- data/lib/nandoc/{config.rb → core/config.rb} +18 -9
- data/lib/nandoc/core/project.rb +50 -0
- data/lib/nandoc/doc/hack-free-zone-defined.md +33 -0
- data/lib/nandoc/erb/agent.rb +5 -5
- data/lib/nandoc/{test/minitest-extlib.rb → extlib/minitest.rb} +1 -1
- data/lib/nandoc/filters/builtin-tags/fence/terminal.rb +24 -0
- data/lib/nandoc/filters/builtin-tags/fence-dispatcher.rb +43 -0
- data/lib/nandoc/filters/builtin-tags/fences.rb +4 -0
- data/lib/nandoc/filters/builtin-tags/see-test.rb +67 -0
- data/lib/nandoc/filters/builtin-tags.rb +11 -0
- data/lib/nandoc/filters/custom-tag.rb +43 -0
- data/lib/nandoc/filters/custom-tags.rb +19 -0
- data/lib/nandoc/filters/tag-parse-instance-methods.rb +11 -0
- data/lib/nandoc/filters/tag-parser.rb +206 -0
- data/lib/nandoc/filters.rb +11 -585
- data/lib/nandoc/{cri-hacks.rb → hacks/cri-hacks.rb} +4 -3
- data/lib/nandoc/{data-source.rb → hacks/data-source.rb} +5 -4
- data/lib/nandoc/{item-class-hacks.rb → hacks/item-class-hacks.rb} +3 -1
- data/lib/nandoc/hacks.rb +6 -0
- data/lib/nandoc/helpers/menu-bouncy.rb +1 -1
- data/lib/nandoc/helpers/site-map.rb +3 -0
- data/lib/nandoc/helpers.rb +1 -1
- data/lib/nandoc/html/tags.rb +65 -0
- data/lib/nandoc/html.rb +6 -0
- data/lib/nandoc/parse-readme.rb +4 -0
- data/lib/nandoc/spec-doc/agent-instance-methods.rb +24 -0
- data/lib/nandoc/spec-doc/code-snippet.rb +59 -0
- data/lib/nandoc/spec-doc/generic-agent.rb +40 -0
- data/lib/nandoc/spec-doc/mock-prompt.rb +3 -9
- data/lib/nandoc/spec-doc/parse-trace.rb +25 -0
- data/lib/nandoc/spec-doc/{mini-test/spec-instance-methods.rb → playback/html/foo-bar.rb} +0 -0
- data/lib/nandoc/spec-doc/playback/html.rb +2 -0
- data/lib/nandoc/spec-doc/playback/players/method.rb +64 -0
- data/lib/nandoc/spec-doc/playback/players/ruby.rb +158 -0
- data/lib/nandoc/spec-doc/playback/players/terminal.rb +93 -0
- data/lib/nandoc/spec-doc/playback/players.rb +4 -0
- data/lib/nandoc/spec-doc/playback/support/playback-methods.rb +44 -0
- data/lib/nandoc/spec-doc/playback/support/sexp-scanner.rb +61 -0
- data/lib/nandoc/spec-doc/playback/support.rb +3 -0
- data/lib/nandoc/spec-doc/playback/terminal/color-to-html.rb +100 -0
- data/lib/nandoc/spec-doc/playback.rb +3 -0
- data/lib/nandoc/spec-doc/recordings.rb +55 -0
- data/lib/nandoc/spec-doc/ruby2ruby-standin.rb +37 -0
- data/lib/nandoc/spec-doc/test-case-agent.rb +1 -1
- data/lib/nandoc/spec-doc/{mini-test.rb → test-framework/mini-test/proxy.rb} +9 -31
- data/lib/nandoc/spec-doc/{test-framework-proxy.rb → test-framework/proxy.rb} +27 -50
- data/lib/nandoc/spec-doc.rb +57 -13
- data/lib/nandoc/{test → support}/diff-to-string.rb +0 -0
- data/lib/nandoc/support/regexp-enhance.rb +6 -0
- data/lib/nandoc/support/regexp.rb +12 -0
- data/lib/nandoc/support/secret-parent.rb +21 -0
- data/lib/nandoc/support/shared-attr-reader.rb +32 -0
- data/lib/nandoc/support/site-merge.rb +1 -1
- data/lib/nandoc/support/site-methods.rb +4 -4
- data/lib/nandoc/support/stream-colorizer.rb +1 -1
- data/lib/nandoc/support/string-methods.rb +56 -0
- data/lib/nandoc.rb +12 -35
- data/proto/README.md +4 -2
- data/test/test.rb +1 -0
- metadata +58 -25
- data/doc/bar/baz.md +0 -4
- data/doc/bar/bliff.md +0 -8
- data/doc/foo.md +0 -5
- data/doc/getting-started.rb +0 -13
- data/lib/nandoc/spec-doc/support-modules.rb +0 -158
- data/lib/nandoc/spec-doc/test-framework-dispatcher.rb +0 -15
- data/lib/nandoc/support-modules.rb +0 -273
- data/lib/nandoc/treebis/NOGIT-DOCS/NEWS.md +0 -5
- data/lib/nandoc/treebis/NOGIT-README.md +0 -65
- data/lib/nandoc/treebis/nandoc.persistent.json +0 -3
data/lib/nandoc/filters.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
|
-
|
1
|
+
# registers self at bottom!
|
2
|
+
here = File.dirname(__FILE__)
|
3
|
+
require here+'/filters/custom-tags.rb'
|
4
|
+
require here+'/filters/tag-parse-instance-methods.rb'
|
5
|
+
require here+'/filters/builtin-tags.rb'
|
6
|
+
require here+'/spec-doc.rb'
|
7
|
+
require here+'/spec-doc/playback'
|
2
8
|
|
3
9
|
module NanDoc::Filters
|
4
10
|
class General < ::Nanoc3::Filter
|
5
|
-
include Nanoc3::Helpers::HTMLEscape
|
6
|
-
alias_method :h, :html_escape
|
7
|
-
|
8
|
-
module TerminalColorToHtml; end
|
9
|
-
include TerminalColorToHtml
|
10
|
-
|
11
11
|
# Parses document contents for nanDoc enhancements to
|
12
12
|
# markdown-like markup.
|
13
13
|
|
@@ -73,589 +73,15 @@ module NanDoc::Filters
|
|
73
73
|
# as the fences.
|
74
74
|
#
|
75
75
|
|
76
|
-
|
77
|
-
|
76
|
+
public
|
78
77
|
|
79
78
|
# @param [String] content The content to filter
|
80
79
|
# @param [Hash] params - not used
|
81
80
|
# @return [String] The filtered content
|
82
81
|
def run content, params={}
|
83
|
-
|
84
|
-
content = filter_see_test(content) if ReSeeTest =~ content
|
85
|
-
content
|
86
|
-
end
|
87
|
-
|
88
|
-
def unindent_generic str
|
89
|
-
md = ReUnindent.match(str) or fail("no")
|
90
|
-
reindent_content(md)
|
91
|
-
end
|
92
|
-
private
|
93
|
-
|
94
|
-
RecognizedTags = ['ruby', 'from the command line']
|
95
|
-
ReFenceFind = /^([[:space:]]*)[ a-z]+:[[:space:]]*\n\1~~~[[:space:]]*\n/m
|
96
|
-
ReFenceCap = %r<
|
97
|
-
^((?:[ ]|\t)*)((?:[a-z]|[ ])+):(?:[ ]|\t)*\n
|
98
|
-
\1~~~(?:[ ]|\t)*\n
|
99
|
-
(.*?)\n
|
100
|
-
\1~~~(?:[ ]|\t)*\n
|
101
|
-
>mx
|
102
|
-
NanDoc::RegexpEnhance.names(ReFenceCap, :indent, :tag_name, :content)
|
103
|
-
|
104
|
-
ReSeeTest = /\(see: ((?:spec|test)[^\)]+)\)/
|
105
|
-
NanDoc::RegexpEnhance.names(ReSeeTest, :content)
|
106
|
-
|
107
|
-
ReSeeTestParse =
|
108
|
-
/\A((?:spec|test).*\.rb) ?(?:--?|\/) ?['"]([^'"]+)['"](.+)?\Z/
|
109
|
-
NanDoc::RegexpEnhance.names(ReSeeTestParse, :testfile, :testname, :xtra)
|
110
|
-
|
111
|
-
ReUnindent = /\A([ \t]*)(.*)\Z/m
|
112
|
-
NanDoc::RegexpEnhance.names(ReUnindent, :indent, :content)
|
113
|
-
|
114
|
-
def initialize(*a)
|
115
|
-
super(*a)
|
116
|
-
@prompt_str = prompt_str_default
|
117
|
-
end
|
118
|
-
|
119
|
-
def advance_to_story sexp, md, idx
|
120
|
-
story = md[:xtra] =~ /\A *(?:--?|\/) *['"](.+)['"]\Z/ && $1 or
|
121
|
-
fail("couldn't parse out story name from #{md[:xtra].inspect}"<<
|
122
|
-
"expecting for e.g \" - 'blah blah'\"")
|
123
|
-
idx = sexp.index{|x| x.first == :story && x[1] == story } or
|
124
|
-
fail("couldn't find story #{story.inspect}. Known stories are: ("<<
|
125
|
-
sexp.select{|x| x.first == :story }.map{|x| "'#{x[1]}'"}.join(', ')<<
|
126
|
-
")")
|
127
|
-
idx + 1
|
128
|
-
end
|
129
|
-
|
130
|
-
def converter_ruby
|
131
|
-
@converter_ruby ||= begin
|
132
|
-
require 'syntax/convertors/html'
|
133
|
-
::Syntax::Convertors::HTML.for_syntax 'ruby'
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
def sexp_getter
|
138
|
-
@sexp_getter ||= begin
|
139
|
-
require File.dirname(__FILE__)+'/spec-doc.rb'
|
140
|
-
NanDoc::SpecDoc::
|
141
|
-
TestFrameworkDispatcher.new(current_project_root_hack)
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
#
|
146
|
-
# @todo this sucks. i didn't have time to think about how this should
|
147
|
-
# work when i wrote it. The problem is, given that we are a nanoc
|
148
|
-
# project, how do we know where live the tests we are spec-docing?
|
149
|
-
#
|
150
|
-
# For now we assume that the mysite folder is one level inside the root
|
151
|
-
# of the (gem-like) project folder and we assert that the assumed root
|
152
|
-
# looks right but this will be broken in the likely event that the nanoc
|
153
|
-
# project will live elsewhere relative to the gem-like root.
|
154
|
-
#
|
155
|
-
def current_project_root_hack
|
156
|
-
presumed_root = File.dirname(FileUtils.pwd)
|
157
|
-
thems = %w(spec test)
|
158
|
-
found = thems.detect{ |dir| File.directory?(presumed_root+'/'+dir) }
|
159
|
-
fail("couldn't find " << oxford_comma(thems,' or ', "ed) <<
|
160
|
-
"in #{presumed_root}") unless found
|
161
|
-
presumed_root
|
162
|
-
end
|
163
|
-
|
164
|
-
def ellipsis_default
|
165
|
-
"..."
|
166
|
-
end
|
167
|
-
|
168
|
-
def filter_fence content
|
169
|
-
with_each_tag_in(content, ReFenceCap) do |md|
|
170
|
-
render_block_fence md
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
def filter_see_test content
|
175
|
-
with_each_tag_in(content, ReSeeTest) do |md|
|
176
|
-
render_block_see_test md
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
#
|
181
|
-
# if the string has anything that looks like colors in it,
|
182
|
-
# then just highlite the colors (as html), else
|
183
|
-
# highlight things that look like prompts (as html)
|
184
|
-
#
|
185
|
-
def lines_highlighted content
|
186
|
-
if colored_content = terminal_color_to_html(content)
|
187
|
-
[colored_content]
|
188
|
-
else
|
189
|
-
these = content.split("\n").map do |line|
|
190
|
-
line.sub( %r!\A(~[^>]*>)?(.*)\Z! ) do
|
191
|
-
tags = [];
|
192
|
-
tags.push "<span class='prompt'>#{h($1)}</span>" if $1
|
193
|
-
tags.push "<span class='normal'>#{h($2)}</span>" unless $2.empty?
|
194
|
-
tags.join('')
|
195
|
-
end
|
196
|
-
end
|
197
|
-
these
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
# @return the amount to advance the cursor by
|
202
|
-
def process_sexp_ellipsis lines, sexp, i
|
203
|
-
j = i
|
204
|
-
fail("need :out_begin") unless sexp[j].first == :out_begin
|
205
|
-
lines.push sexp[j][1].strip
|
206
|
-
j += 1
|
207
|
-
if sexp[j] && sexp[j].first == :cosmetic_ellipsis
|
208
|
-
lines.push sexp[j][1]
|
209
|
-
j += 1
|
210
|
-
else
|
211
|
-
lines.push ellipsis_default
|
212
|
-
end
|
213
|
-
fail("need :out_end") unless sexp[j] && sexp[j].first == :out_end
|
214
|
-
lines.push sexp[j][1]
|
215
|
-
ret = j - i
|
216
|
-
ret
|
217
|
-
end
|
218
|
-
|
219
|
-
def prompt_str_cd new_dir
|
220
|
-
/\A(.+) > \Z/ =~ prompt_str or
|
221
|
-
fail("can't determine cwd from #{prmpt_str.inspect}")
|
222
|
-
new_pwd = "#{$1}/#{new_dir}"
|
223
|
-
@old_prompts ||= []
|
224
|
-
@old_prompts.push prompt_str
|
225
|
-
@prompt_str = "#{new_pwd} > "
|
226
|
-
nil
|
227
|
-
end
|
228
|
-
|
229
|
-
def prompt_str_cd_pop
|
230
|
-
@prompt_str = @old_prompts.pop
|
231
|
-
end
|
232
|
-
|
233
|
-
def prompt_str_default
|
234
|
-
'~ > '
|
235
|
-
end
|
236
|
-
|
237
|
-
public # avoid warnings
|
238
|
-
attr_reader :prompt_str
|
239
|
-
private :prompt_str
|
240
|
-
private
|
241
|
-
|
242
|
-
def render_block_fence md
|
243
|
-
if ! RecognizedTags.include?(md[:tag_name])
|
244
|
-
fail("sorry, there has been a mistake. I shouldn't have parsed it "<<
|
245
|
-
"but i went ahead and parsed a #{md[:tag_name].inspect} tag even "<<
|
246
|
-
"though i don't know what to do with it. Known tags are "<<
|
247
|
-
oxford_comma(RecognizedTags,"ed)
|
248
|
-
)
|
249
|
-
end
|
250
|
-
case md[:tag_name]
|
251
|
-
when 'ruby'; render_block_fence_ruby md
|
252
|
-
when 'from the command line'; render_block_fence_terminal md
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
def render_block_see_test md
|
257
|
-
md2 = ReSeeTestParse.match(md[:content]) or
|
258
|
-
fail("couldn't parse see_test string: #{md[:content].inspect} -- "<<
|
259
|
-
'string must look like: \'(see: test_file.rb/"some test name")\''
|
260
|
-
)
|
261
|
-
getter = sexp_getter
|
262
|
-
sexp = getter.get_sexp md2[:testfile], md2[:testname]
|
263
|
-
sexp.first.first == :method or fail("i'm done with this kind of sexp")
|
264
|
-
methname = sexp.first[1]
|
265
|
-
idx = 0
|
266
|
-
last = sexp.length - 1
|
267
|
-
if md2[:xtra]
|
268
|
-
idx = advance_to_story(sexp, md2, idx)
|
269
|
-
end
|
270
|
-
idx += 1 if sexp[0] && sexp[0].first == :method && idx == 0
|
271
|
-
catch(:done) do
|
272
|
-
while idx <= last
|
273
|
-
node = sexp[idx]
|
274
|
-
type = node.first
|
275
|
-
case type
|
276
|
-
when :cd, :command
|
277
|
-
idx += process_sexp_command sexp, idx
|
278
|
-
when :method
|
279
|
-
if node[1] != methname
|
280
|
-
fail("i don't like this kind of sexp anymore -- "<<
|
281
|
-
"#{methname.inspect} != #{node[1].inspect}"
|
282
|
-
)
|
283
|
-
end
|
284
|
-
when :note
|
285
|
-
process_sexp_note sexp, idx
|
286
|
-
when :record_ruby
|
287
|
-
idx += ProcessSnippet.new(self, sexp, idx).process
|
288
|
-
when :story
|
289
|
-
# always stop at next story?
|
290
|
-
throw :done
|
291
|
-
else
|
292
|
-
fail("unexpected sexp node here: #{type.inspect} idx: #{idx}")
|
293
|
-
end
|
294
|
-
idx += 1
|
295
|
-
end
|
296
|
-
end
|
297
|
-
end
|
298
|
-
|
299
|
-
def render_block_fence_terminal md
|
300
|
-
content = reindent_content md
|
301
|
-
render_terminal_div_highlighted content
|
302
|
-
end
|
303
|
-
|
304
|
-
def render_block_fence_ruby md
|
305
|
-
content = reindent_content md
|
306
|
-
content2 = content.strip # i think
|
307
|
-
hilited = converter_ruby.convert(content2, false)
|
308
|
-
pre_block = "\n<pre class='ruby'>\n#{hilited}\n</pre>\n"
|
309
|
-
@chunks.push pre_block
|
310
|
-
end
|
311
|
-
public :render_block_fence_ruby # visitors
|
312
|
-
|
313
|
-
def render_command_div content
|
314
|
-
fake_command = "#{prompt_str}#{content}"
|
315
|
-
render_terminal_div_highlighted fake_command
|
316
|
-
end
|
317
|
-
|
318
|
-
# @return [integer] how much to advance the cursor by
|
319
|
-
# when you either hit the end or hit an unrecognized node
|
320
|
-
# adds to rendered output a div with the command and output
|
321
|
-
def process_sexp_command sexp, i
|
322
|
-
lines = []
|
323
|
-
j = i
|
324
|
-
last = sexp.length - 1
|
325
|
-
catch(:done) do
|
326
|
-
while j <= last
|
327
|
-
type = sexp[j].first
|
328
|
-
case type
|
329
|
-
when :cd; lines.push "#{prompt_str}cd #{sexp[j][1]}"
|
330
|
-
prompt_str_cd sexp[j][1]
|
331
|
-
when :cd_end; prompt_str_cd_pop
|
332
|
-
when :command; lines.push "#{prompt_str}#{sexp[j][1]}"
|
333
|
-
when :out; lines.push sexp[j][1].strip
|
334
|
-
when :out_begin
|
335
|
-
j += process_sexp_ellipsis lines, sexp, j
|
336
|
-
else;
|
337
|
-
j -= 1 unless j == i
|
338
|
-
throw :done
|
339
|
-
end
|
340
|
-
j += 1
|
341
|
-
end
|
342
|
-
end
|
343
|
-
raw_content = lines.join("\n")
|
344
|
-
render_terminal_div_highlighted raw_content
|
345
|
-
ret = j-i
|
346
|
-
ret
|
347
|
-
end
|
348
|
-
|
349
|
-
# @return [nil] adds the output raw to the blickle blackle
|
350
|
-
def process_sexp_note sexp, idx
|
351
|
-
chunk = sexp[idx][1].call
|
352
|
-
@chunks.push chunk
|
353
|
-
end
|
354
|
-
|
355
|
-
def render_terminal_div_highlighted content
|
356
|
-
lines = ['<pre class="terminal">']
|
357
|
-
lines.concat lines_highlighted(content)
|
358
|
-
lines.push '</pre>'
|
359
|
-
html = lines * "\n" + "\n"
|
360
|
-
@chunks.push html
|
361
|
-
end
|
362
|
-
|
363
|
-
def render_unparsed start, last
|
364
|
-
chunk = @content[start..last]
|
365
|
-
@chunks.push chunk
|
366
|
-
end
|
367
|
-
|
368
|
-
def reindent_content md
|
369
|
-
raw_content = md[:content]
|
370
|
-
indent = md[:indent]
|
371
|
-
return raw_content if indent == ''
|
372
|
-
# of all non-blank lines find the minimum indent.
|
373
|
-
x = raw_content.scan(/^[[:space:]]+(?=[^[:space:]])/).map(&:length).min
|
374
|
-
# if for some reason the content has less indent than the fences,
|
375
|
-
# don't alter any of it.
|
376
|
-
return raw_content if x < indent.length
|
377
|
-
re = /^#{Regexp.new(indent)}/
|
378
|
-
unindented_content = raw_content.gsub(re, '')
|
379
|
-
unindented_content
|
380
|
-
end
|
381
|
-
|
382
|
-
# ignoring multiline crap for now
|
383
|
-
def ruby_snippet_inspect inspect
|
384
|
-
"\n#=> #{inspect}"
|
385
|
-
end
|
386
|
-
|
387
|
-
def with_each_tag_in content, regexp, &block
|
388
|
-
@content = content
|
389
|
-
@chunks = []
|
390
|
-
unparsed_start = 0
|
391
|
-
offset = 0
|
392
|
-
last = content.length - 1
|
393
|
-
while offset <= last && md = regexp.match(content[offset..-1])
|
394
|
-
unparsed_end = md.offset(0)[0] - 1 + offset
|
395
|
-
offset += md.offset(0)[1]+1
|
396
|
-
render_unparsed(unparsed_start, unparsed_end)
|
397
|
-
unparsed_start = offset # offset is where we start searching next
|
398
|
-
block.call(md)
|
399
|
-
end
|
400
|
-
render_unparsed(unparsed_start, -1)
|
401
|
-
@chunks.join('')
|
402
|
-
end
|
403
|
-
|
404
|
-
require 'strscan'
|
405
|
-
module TerminalColorToHtml
|
406
|
-
# this sucks.
|
407
|
-
#
|
408
|
-
def terminal_color_to_html str
|
409
|
-
return nil unless str.index("\e[") # save a whale
|
410
|
-
scn = StringScanner.new(str)
|
411
|
-
sexp = []
|
412
|
-
while true
|
413
|
-
foo = scn.scan(/(.*?)(?=\e\[)/m)
|
414
|
-
if ! foo
|
415
|
-
blork = scn.scan_until(/\Z/m) or fail("worglebezoik")
|
416
|
-
sexp.push([:content, blork]) unless blork.empty?
|
417
|
-
break;
|
418
|
-
end
|
419
|
-
foo or fail("oopfsh")
|
420
|
-
sexp.push([:content, foo]) unless foo.empty?
|
421
|
-
bar = scn.scan(/\e\[/) or fail("goff")
|
422
|
-
baz = scn.scan(/\d+(?:;\d+)*/)
|
423
|
-
baz or fail("narghh")
|
424
|
-
if '0'==baz
|
425
|
-
sexp.push([:pop])
|
426
|
-
else
|
427
|
-
sexp.push([:push, *baz.split(';')])
|
428
|
-
end
|
429
|
-
biff = scn.scan(/m/) or fail("noiflphh")
|
430
|
-
end
|
431
|
-
html = terminal_colorized_sexp_to_html sexp
|
432
|
-
html
|
433
|
-
end
|
434
|
-
private
|
435
|
-
# the other side of these associations lives in trollop-subset.css
|
436
|
-
Code2CssClass = {
|
437
|
-
'1' => 'bright', '30' => 'black', '31' => 'red', '32' => 'green',
|
438
|
-
'33' => 'yellow', '34' => 'blue', '35' => 'magenta', '36' => 'cyan',
|
439
|
-
'37' => 'white'
|
440
|
-
}
|
441
|
-
def terminal_code_to_css_class code
|
442
|
-
Code2CssClass[code] or
|
443
|
-
fail("sorry, no known code for #{code.inspect}. "<<
|
444
|
-
"(maybe you should make one?)")
|
445
|
-
end
|
446
|
-
def terminal_colorized_sexp_to_html sexp
|
447
|
-
i = -1;
|
448
|
-
last = sexp.length - 1;
|
449
|
-
parts = []
|
450
|
-
catch(:done) do
|
451
|
-
while (i+=1) <= last
|
452
|
-
codes = nil
|
453
|
-
while i <= last && sexp[i].first == :push
|
454
|
-
codes ||= []
|
455
|
-
codes.concat sexp[i][1..-1]
|
456
|
-
i += 1
|
457
|
-
end
|
458
|
-
if codes
|
459
|
-
classes = codes.map{|c| terminal_code_to_css_class(c) }*' '
|
460
|
-
parts.push "<span class='#{classes}'>"
|
461
|
-
end
|
462
|
-
throw :done if i > last
|
463
|
-
case sexp[i].first
|
464
|
-
when :content; parts.push(sexp[i][1])
|
465
|
-
when :pop; parts.push('</span>')
|
466
|
-
else; fail('fook');
|
467
|
-
end
|
468
|
-
end
|
469
|
-
end
|
470
|
-
html = parts*''
|
471
|
-
html
|
472
|
-
end
|
473
|
-
end
|
474
|
-
|
475
|
-
module HackHelpers
|
476
|
-
# stand-in for ruby-2-ruby
|
477
|
-
#
|
478
|
-
|
479
|
-
def leading_indent str
|
480
|
-
/\A([ \t]*)/ =~ str && $1
|
481
|
-
end
|
482
|
-
def re_for_line_with_same_indent_as str
|
483
|
-
ind = leading_indent(str)
|
484
|
-
re = /\A#{Regexp.escape(ind)}(?=[^ \t])/
|
485
|
-
re
|
486
|
-
end
|
487
|
-
def re_for_here here
|
488
|
-
/\A[ \t]*#{Regexp.escape(here)}[ \t]*\n?\Z/
|
489
|
-
end
|
490
|
-
def re_for_unindent_gsub indent
|
491
|
-
re = /\A#{Regexp.escape(indent)}/
|
492
|
-
re
|
493
|
-
end
|
494
|
-
def string_diff_assert long, short
|
495
|
-
idx = long.index(short) or fail("short not found in long -- "<<
|
496
|
-
"#{short.inspect} in #{long.inspect}")
|
497
|
-
head = long[0,idx] # usu. ''
|
498
|
-
tail = long[idx + short.length..-1]
|
499
|
-
head + tail
|
500
|
-
end
|
501
|
-
end
|
502
|
-
|
503
|
-
class ProcessSnippet
|
504
|
-
include HackHelpers
|
505
|
-
|
506
|
-
def initialize filter, sexp, idx
|
507
|
-
@prefix = '# => '
|
508
|
-
sexp[idx].first == :record_ruby or fail("must be record_ruby")
|
509
|
-
@filter, @sexp, @idx = filter, sexp, idx
|
510
|
-
end
|
511
|
-
ReInspect = /\A([ \t]*)(?:nandoc\.inspect[ \t]*)(.+)\Z/
|
512
|
-
NanDoc::RegexpEnhance.names(ReInspect, :indent, :tail)
|
513
|
-
ReOut = /\A[ \t]*nandoc\.out\([ \t]*<<-'?([A-Z]+)/
|
514
|
-
ReUntilDo = /\A[ \t]*\)[ \t]*do[ \t]*\Z/
|
515
|
-
|
516
|
-
ReHere = /\A(.*)(?:, ?<<-'?([A-Z]+))/
|
517
|
-
NanDoc::RegexpEnhance.names(ReHere, :keep, :here)
|
518
|
-
|
519
|
-
ConsumeThese = [:inspect, :out]
|
520
|
-
|
521
|
-
def process
|
522
|
-
j = @idx
|
523
|
-
snip = @sexp[j][1]
|
524
|
-
@lines = snip.file_lines.dup # we will be changing values
|
525
|
-
@inspects = []
|
526
|
-
while @sexp[j+1] && ConsumeThese.include?(@sexp[j+1].first)
|
527
|
-
j += 1
|
528
|
-
@inspects.push @sexp[j]
|
529
|
-
end
|
530
|
-
inspects_interpolate if @inspects.any?
|
531
|
-
unindented_lines = @lines[snip.line_start..snip.line_stop-2]
|
532
|
-
fake_unindented_ruby = unindented_lines.compact.join('')
|
533
|
-
indent = /\A([ \t]*)/ =~ fake_unindented_ruby && $1
|
534
|
-
fake_md = {:indent => indent, :content => fake_unindented_ruby}
|
535
|
-
@filter.render_block_fence_ruby(fake_md)
|
536
|
-
advance_by = j - @idx
|
537
|
-
advance_by
|
538
|
-
end
|
539
|
-
private
|
540
|
-
def erase_to_here offset, here
|
541
|
-
re = /\A[ \t]*#{Regexp.escape(here)}\Z/
|
542
|
-
found = (offset+1..@lines.length-1).detect{|idx| @lines[idx] =~ re }
|
543
|
-
found or fail("heredoc hack failed. no #{re} found.")
|
544
|
-
(offset+1..found).each{ |idx| @lines[idx] = nil }
|
545
|
-
nil
|
546
|
-
end
|
547
|
-
|
548
|
-
# whether with a nandoc.out or nandoc.inspect, keeping the indentation
|
549
|
-
# that's in the sourcefile, substitute real code for pretty code,
|
550
|
-
# without changing the offsets of the lines. fragile hack.
|
551
|
-
# @todo ruby2ruby?
|
552
|
-
#
|
553
|
-
def inspects_interpolate
|
554
|
-
@inspects.each do |ins|
|
555
|
-
# each call below will alter @lines (without shifting them)
|
556
|
-
# accordingly, replacing actual code with pretty code (and comments)
|
557
|
-
case ins[0]
|
558
|
-
when :inspect; process_inspect(ins)
|
559
|
-
when :out; process_out(ins)
|
560
|
-
else fail("no: #{ins[0].inspect}")
|
561
|
-
end
|
562
|
-
end
|
563
|
-
end
|
564
|
-
|
565
|
-
# the block content gets output as if it's bare ruby,
|
566
|
-
# the output (whether it was expected or actual we don't care)
|
567
|
-
# gets output with leading comment markers. All of this nonsense is
|
568
|
-
# bs proof of concept that needs to get blown away by ruby2ruby or
|
569
|
-
# something
|
570
|
-
#
|
571
|
-
def process_out sexp
|
572
|
-
call_offset = sexp[2][:line] - 1
|
573
|
-
first = @lines[call_offset]
|
574
|
-
ReOut =~ first or fail("DocSpec hack fail: Didn't look like "<<
|
575
|
-
"nandoc.out line: #{first.inspect}\nExpecting line to match "<<
|
576
|
-
" #{reOut}")
|
577
|
-
j = call_offset + 1
|
578
|
-
last = @lines.length - 1
|
579
|
-
j += 1 until j > last || ReUntilDo =~ @lines[j]
|
580
|
-
j <= last or fail("DocSpec hack fail: Couldn't find do block "<<
|
581
|
-
"anywhere before EOF with #{ReUntilDo}")
|
582
|
-
do_line = @lines[j]
|
583
|
-
re = re_for_line_with_same_indent_as(do_line)
|
584
|
-
repl_lines = []
|
585
|
-
j += 1
|
586
|
-
repl_from_here = j
|
587
|
-
j += 1 until j > last || re =~ @lines[j]
|
588
|
-
j <= last or fail("DocSpec hack fail: Couldn't find end of do "<<
|
589
|
-
"block anywhere before EOF with #{re}")
|
590
|
-
offset_of_line_with_end = j
|
591
|
-
repl_lines = @lines[repl_from_here..offset_of_line_with_end-1]
|
592
|
-
repl_lines.any? or fail("DocSpec hack fail -- no lines")
|
593
|
-
ind_short = leading_indent(do_line)
|
594
|
-
ind_long = leading_indent(repl_lines.first)
|
595
|
-
ind_diff = string_diff_assert(ind_long, ind_short)
|
596
|
-
unindent = re_for_unindent_gsub(ind_diff)
|
597
|
-
repl_lines.map{ |x| x.sub!(unindent, '') } # this changes @lines val
|
598
|
-
(0..repl_lines.length-1).each do |l|
|
599
|
-
actual_offset = call_offset + l
|
600
|
-
@lines[actual_offset] = repl_lines[l]
|
601
|
-
end
|
602
|
-
erase_from_here = call_offset + repl_lines.length
|
603
|
-
(erase_from_here..offset_of_line_with_end).each do |l|
|
604
|
-
@lines[l] = nil
|
605
|
-
end
|
606
|
-
# this is so fragile, it requires multiline blah blah
|
607
|
-
commented_content = sexp[1].gsub(/^/m, "#{ind_short}# ")
|
608
|
-
@lines[erase_from_here] = commented_content
|
609
|
-
nil
|
610
|
-
end
|
611
|
-
|
612
|
-
#
|
613
|
-
# comments at process_out apply to this too
|
614
|
-
#
|
615
|
-
def process_inspect sexp
|
616
|
-
offset = sexp[2][:line] - 1
|
617
|
-
act = @lines[offset]
|
618
|
-
md = ReInspect.match(act) or
|
619
|
-
fail("hack fail of nandoc.inspect near #{act.inspect}")
|
620
|
-
md = md.to_hash
|
621
|
-
tail = md[:tail]
|
622
|
-
my_lines = []
|
623
|
-
md2 = ReHere.match(tail)
|
624
|
-
return process_inspect_oneline(sexp) unless md2
|
625
|
-
md2 = md2.to_hash
|
626
|
-
ind = leading_indent(@lines[offset])
|
627
|
-
my_lines.push "#{ind}#{md2[:keep]}\n"
|
628
|
-
re = re_for_here(md2[:here])
|
629
|
-
j = offset + 1
|
630
|
-
last = @lines.length - 1
|
631
|
-
until re =~ @lines[j] || j > last
|
632
|
-
back_one = @lines[j].sub(/\A(?: |\t)/,'')
|
633
|
-
my_lines.push back_one.sub(/\A([\t ]*)/){ "#{$1}#{@prefix}" }
|
634
|
-
j += 1
|
635
|
-
end
|
636
|
-
j > last && fail("DocSpec hack fail: #{md2[:here]} not found "<<
|
637
|
-
"anywhere before EOF")
|
638
|
-
(offset..j).each do |k|
|
639
|
-
@lines[k] = nil
|
640
|
-
end
|
641
|
-
(0..my_lines.length-1).each do |k|
|
642
|
-
l = offset+k
|
643
|
-
@lines[l] = my_lines[k]
|
644
|
-
end
|
645
|
-
end
|
646
|
-
|
647
|
-
def process_inspect_oneline sexp
|
648
|
-
offset = sexp[2][:line] - 1
|
649
|
-
line = @lines[offset]
|
650
|
-
/\A([ \t]*)nandoc.inspect *([^,]+), *([^,]+)\n\Z/ =~ line or fail(
|
651
|
-
"DocSpec hack fail: Why can't we parse this inspect "<<
|
652
|
-
" line?\n#{line.inspect}")
|
653
|
-
ind, keep, val = $1, $2, $3 # actually we don't want $3
|
654
|
-
replace_with = "#{ind}#{keep}\n#{ind}#{@prefix}#{sexp[1]}\n"
|
655
|
-
# assume no newlines in value when the whole thing was oneline
|
656
|
-
@lines[offset] = replace_with
|
657
|
-
nil
|
658
|
-
end
|
82
|
+
CustomTags.change_item_content content
|
659
83
|
end
|
660
84
|
end
|
661
85
|
end
|
86
|
+
|
87
|
+
Nanoc3::Filter.register ::NanDoc::Filters::General, :nandoc
|
@@ -1,12 +1,13 @@
|
|
1
|
+
require 'nandoc/cli'
|
2
|
+
|
1
3
|
module Cri
|
2
4
|
class Base
|
3
|
-
|
4
|
-
include NanDoc::TaskCommon
|
5
|
+
include NanDoc::Cli::CommandMethods
|
5
6
|
def remove_command command_class
|
6
7
|
if idx = @commands.index{|x| x.kind_of?(command_class) }
|
7
8
|
@commands.delete_at(idx)
|
8
9
|
else
|
9
|
-
|
10
|
+
command_abort("command not found of class #{command_class}")
|
10
11
|
end
|
11
12
|
end
|
12
13
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'nandoc/cli'
|
2
|
+
|
1
3
|
module NanDoc
|
2
4
|
|
3
5
|
class DataSource < ::Nanoc3::DataSources::FilesystemUnified
|
@@ -12,8 +14,7 @@ module NanDoc
|
|
12
14
|
# Some of the hacks in this file are the worst in the whole project. @todo
|
13
15
|
#
|
14
16
|
|
15
|
-
|
16
|
-
include NanDoc::TaskCommon # task_abort()
|
17
|
+
include Cli::CommandMethods # command_abort
|
17
18
|
|
18
19
|
def initialize *a
|
19
20
|
super(*a)
|
@@ -110,7 +111,7 @@ module NanDoc
|
|
110
111
|
# this is NanDoc.
|
111
112
|
#
|
112
113
|
def error_for_no_files files
|
113
|
-
|
114
|
+
command_abort <<-HERE.gsub(/\n +/,"\n").strip
|
114
115
|
No matching content file(s) found at or under (#{files.join(', ')})
|
115
116
|
from here. (This corresponds to the 'source_file_basenames' setting in
|
116
117
|
config.yaml.) Did you generate the NanDoc site in the right directory?
|
@@ -189,7 +190,7 @@ module NanDoc
|
|
189
190
|
# (undefined on name collision)
|
190
191
|
#
|
191
192
|
def orphan_rescue items
|
192
|
-
require
|
193
|
+
require 'nandoc/support/orphanage.rb'
|
193
194
|
Orphanage.rescue_orphans(@config, items)
|
194
195
|
end
|
195
196
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'nandoc/support/string-methods.rb'
|
2
|
+
|
1
3
|
class Nanoc3::Item
|
2
4
|
#
|
3
5
|
# hacks we use for stuff like sitemap and topnav generation
|
@@ -13,7 +15,7 @@ class Nanoc3::Item
|
|
13
15
|
end
|
14
16
|
|
15
17
|
|
16
|
-
include NanDoc::
|
18
|
+
include NanDoc::StringMethods # basename_no_extension()
|
17
19
|
|
18
20
|
attr_accessor :identifier # know what you are doing if you set it
|
19
21
|
|
data/lib/nandoc/hacks.rb
ADDED