rundoc 4.0.0 → 4.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +4 -0
- data/README.md +62 -0
- data/lib/rundoc/cli.rb +2 -2
- data/lib/rundoc/code_command/file_command/append.rb +3 -1
- data/lib/rundoc/code_command/file_command/remove.rb +4 -1
- data/lib/rundoc/code_command/pre/erb.rb +63 -0
- data/lib/rundoc/code_command/print/erb.rb +5 -5
- data/lib/rundoc/code_command/rundoc/require.rb +1 -1
- data/lib/rundoc/code_command/write.rb +3 -1
- data/lib/rundoc/code_command.rb +1 -0
- data/lib/rundoc/{parser.rb → document.rb} +12 -18
- data/lib/rundoc/fenced_code_block.rb +124 -0
- data/lib/rundoc/version.rb +1 -1
- data/lib/rundoc.rb +2 -2
- data/test/integration/pre_erb_test.rb +56 -0
- data/test/integration/print_test.rb +8 -8
- data/test/integration/require_test.rb +3 -3
- data/test/integration/website_test.rb +1 -1
- data/test/rundoc/code_section_test.rb +48 -40
- data/test/rundoc/parser_test.rb +3 -3
- data/test/rundoc/peg_parser_test.rb +0 -33
- data/test/rundoc/regex_test.rb +19 -69
- data/test/test_helper.rb +5 -6
- metadata +6 -4
- data/lib/rundoc/code_section.rb +0 -155
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8ca738c51da79babb0fba6093b9d2055e6efd6d435d56b3397aed926d002701d
|
4
|
+
data.tar.gz: be7e9bd2c06a3a0e92dd078a3cd66d67f77b7cf1f4490190281fb7e573f8696e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7db578e4f26a9b347ca93d8ae5b4013ae9605feaff56ba937d1b22c1a78316764af8f96274d9f449c5640282df277a3ac06e0530e8f760e8153c029aa2f05a27
|
7
|
+
data.tar.gz: 4b71fb1cfd4851d58759ca443e9d17a365d485621d7c1763b570171557a89c79a52e67080f53c25f1d7c4057a2a4decd43e46df7aa34909dc627b2717668a77b
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
## HEAD
|
2
2
|
|
3
|
+
## 4.1.0
|
4
|
+
|
5
|
+
- Add: Rundoc command `pre.erb` command used for dynamically templating any command using ERB syntax. (https://github.com/zombocom/rundoc/pull/90)
|
6
|
+
|
3
7
|
## 4.0.0
|
4
8
|
|
5
9
|
- Add: Rundoc command `background.stdin_write` to send a string to a backtround process' STDIN. This allows driving REPL interfaces (https://github.com/zombocom/rundoc/pull/79)
|
data/README.md
CHANGED
@@ -73,6 +73,8 @@ This will generate a project folder with your project in it, and a markdown `REA
|
|
73
73
|
- Execute Bash Commands
|
74
74
|
- [$](#shell-commands)
|
75
75
|
- [fail.$](#shell-commands)
|
76
|
+
- Dynamic command templating
|
77
|
+
- [pre.erb](#pre.erb)
|
76
78
|
- Printing
|
77
79
|
- [print.text](#print)
|
78
80
|
- [print.erb](#print)
|
@@ -257,6 +259,66 @@ These custom commands are kept to a minimum, and for the most part behave as you
|
|
257
259
|
|
258
260
|
Running shell commands like this can be very powerful, you'll likely want more control of how you manipulate files in your project. To do this you can use the `file.` namespace:
|
259
261
|
|
262
|
+
## Dynamic command templating
|
263
|
+
|
264
|
+
Meta commands that produce no output but instead allow for generating commands via dynamic templates.
|
265
|
+
|
266
|
+
Current Commands:
|
267
|
+
|
268
|
+
- `pre.erb`
|
269
|
+
|
270
|
+
### pre.erb
|
271
|
+
|
272
|
+
Placing `pre.erb` in-front of another command will allow dynmaic templating via Ruby's [ERB](https://rubyapi.org/3.3/o/erb) syntax.
|
273
|
+
|
274
|
+
For example:
|
275
|
+
|
276
|
+
```
|
277
|
+
:::>> pre.erb $ echo "The answer to everything is <%= 6*7 %>"
|
278
|
+
```
|
279
|
+
|
280
|
+
When this runs, it will first replace the template with the result of the ERB. It would be the same as this:
|
281
|
+
|
282
|
+
```
|
283
|
+
:::>> $ echo "The answer to everything is 42"
|
284
|
+
```
|
285
|
+
|
286
|
+
The binding (variable and method scope) for `pre.erb` is shared across all executions and the default `print.erb` command. That means you can use it to persist data or logic and re-use it:
|
287
|
+
|
288
|
+
```ruby
|
289
|
+
:::-- print.erb <%
|
290
|
+
# Won't be rendered because it's using `--` visibility
|
291
|
+
def lol
|
292
|
+
"haha"
|
293
|
+
end
|
294
|
+
|
295
|
+
user = "Schneems"
|
296
|
+
%>
|
297
|
+
```
|
298
|
+
|
299
|
+
```
|
300
|
+
:::>> pre.erb $ echo <%= user %> said <%= lol() %> | tr '[:lower:]' '[:upper:]'
|
301
|
+
```
|
302
|
+
|
303
|
+
When run, this would produce:
|
304
|
+
|
305
|
+
```
|
306
|
+
$ echo Schneems said haha | tr '[:lower:]' '[:upper:]'
|
307
|
+
SCHNEEMS SAID HAHA
|
308
|
+
```
|
309
|
+
|
310
|
+
Multi-line commands are also supported
|
311
|
+
|
312
|
+
```
|
313
|
+
:::>> pre.erb file.write "lol.txt"
|
314
|
+
Super secret key:
|
315
|
+
<%= "#{key}" %>
|
316
|
+
```
|
317
|
+
|
318
|
+
The only thing to watch out for is if the resulting template contains a `:::>>` (or similar) rundoc marker at the beginning of the line; Rundoc will think it is a new command rather than a part of `pre.erb` template.
|
319
|
+
|
320
|
+
The visibility of the `pre.erb` is forwarded to whatever command is run.
|
321
|
+
|
260
322
|
## Print
|
261
323
|
|
262
324
|
Current commands:
|
data/lib/rundoc/cli.rb
CHANGED
@@ -157,7 +157,7 @@ module Rundoc
|
|
157
157
|
|
158
158
|
io.puts "## Working dir is #{execution_context.output_dir}"
|
159
159
|
Dir.chdir(execution_context.output_dir) do
|
160
|
-
parser = Rundoc::
|
160
|
+
parser = Rundoc::Document.new(
|
161
161
|
source_contents,
|
162
162
|
context: execution_context
|
163
163
|
)
|
@@ -203,7 +203,7 @@ module Rundoc
|
|
203
203
|
to: on_failure_dir
|
204
204
|
)
|
205
205
|
|
206
|
-
on_failure_dir.join("RUNDOC_FAILED.md").write(Rundoc::
|
206
|
+
on_failure_dir.join("RUNDOC_FAILED.md").write(Rundoc::Document.partial_result_to_doc)
|
207
207
|
end
|
208
208
|
|
209
209
|
private def on_success(output)
|
@@ -12,7 +12,9 @@ class Rundoc::CodeCommand::FileCommand
|
|
12
12
|
def to_md(env)
|
13
13
|
return unless render_command?
|
14
14
|
|
15
|
-
|
15
|
+
if env[:commands].any? { |c| c[:object].not_hidden? }
|
16
|
+
raise "Must call append in its own code section"
|
17
|
+
end
|
16
18
|
|
17
19
|
env[:before] << if @line_number
|
18
20
|
"In file `#{filename}`, on line #{@line_number} add:"
|
@@ -7,7 +7,10 @@ class Rundoc::CodeCommand::FileCommand
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def to_md(env)
|
10
|
-
|
10
|
+
if env[:commands].any? { |c| c[:object].not_hidden? }
|
11
|
+
raise "Must call remove in its own code section"
|
12
|
+
end
|
13
|
+
|
11
14
|
env[:before] << "In file `#{filename}` remove:"
|
12
15
|
env[:before] << NEWLINE
|
13
16
|
nil
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require_relative "../print/erb"
|
2
|
+
|
3
|
+
class Rundoc::CodeCommand
|
4
|
+
class PreErb < Rundoc::CodeCommand
|
5
|
+
def initialize(line)
|
6
|
+
@line = line
|
7
|
+
@binding = RUNDOC_ERB_BINDINGS[RUNDOC_DEFAULT_ERB_BINDING]
|
8
|
+
@code = nil
|
9
|
+
@command = nil
|
10
|
+
@template = nil
|
11
|
+
@render_delegate_result = nil
|
12
|
+
@render_delegate_command = nil
|
13
|
+
# Hide self, pass visibility onto delegate
|
14
|
+
@render_result = false
|
15
|
+
@render_command = false
|
16
|
+
end
|
17
|
+
|
18
|
+
# Visibility is injected by the parser, capture it and pass it to the delegate
|
19
|
+
def render_result=(value)
|
20
|
+
@render_delegate_result = value
|
21
|
+
end
|
22
|
+
|
23
|
+
def render_command=(value)
|
24
|
+
@render_delegate_command = value
|
25
|
+
end
|
26
|
+
|
27
|
+
def code
|
28
|
+
@code ||= begin
|
29
|
+
vis = +""
|
30
|
+
vis += @render_delegate_result ? ">" : "-"
|
31
|
+
vis += @render_delegate_command ? ">" : "-"
|
32
|
+
code = [@line, @contents]
|
33
|
+
.compact
|
34
|
+
.reject(&:empty?)
|
35
|
+
.join("\n")
|
36
|
+
@template = ":::#{vis} #{code}"
|
37
|
+
|
38
|
+
puts "pre.erb: Applying ERB, template:\n#{@template}"
|
39
|
+
result = ERB.new(@template).result(@binding)
|
40
|
+
puts "pre.erb: ERB result:\n#{result}"
|
41
|
+
puts "pre.erb: done, ready to delegate"
|
42
|
+
result
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def command
|
47
|
+
@command ||= Rundoc::FencedCodeBlock.parse_code_commands(code).first
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_md(env = {})
|
51
|
+
""
|
52
|
+
end
|
53
|
+
|
54
|
+
def call(env = {})
|
55
|
+
# Defer running ERB until as late as possible
|
56
|
+
delegate = command
|
57
|
+
# Delegate will be executed by the caller working through the stack
|
58
|
+
env[:stack].push(delegate)
|
59
|
+
""
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
Rundoc.register_code_command(:"pre.erb", Rundoc::CodeCommand::PreErb)
|
@@ -10,11 +10,12 @@ class EmptyBinding
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
-
RUNDOC_ERB_BINDINGS = Hash.new { |h, k| h[k] = EmptyBinding.create }
|
14
|
-
|
15
13
|
class Rundoc::CodeCommand
|
14
|
+
RUNDOC_ERB_BINDINGS = Hash.new { |h, k| h[k] = EmptyBinding.create }
|
15
|
+
RUNDOC_DEFAULT_ERB_BINDING = "default"
|
16
|
+
|
16
17
|
class PrintERB < Rundoc::CodeCommand
|
17
|
-
def initialize(line = nil, binding:
|
18
|
+
def initialize(line = nil, binding: RUNDOC_DEFAULT_ERB_BINDING)
|
18
19
|
@line = line
|
19
20
|
@binding = RUNDOC_ERB_BINDINGS[binding]
|
20
21
|
end
|
@@ -31,7 +32,7 @@ class Rundoc::CodeCommand
|
|
31
32
|
@render ||= ERB.new([@line, contents].compact.join("\n")).result(@binding)
|
32
33
|
end
|
33
34
|
|
34
|
-
def call(
|
35
|
+
def call(env = {})
|
35
36
|
if render_before?
|
36
37
|
""
|
37
38
|
else
|
@@ -44,5 +45,4 @@ class Rundoc::CodeCommand
|
|
44
45
|
end
|
45
46
|
end
|
46
47
|
end
|
47
|
-
|
48
48
|
Rundoc.register_code_command(:"print.erb", Rundoc::CodeCommand::PrintERB)
|
@@ -17,7 +17,7 @@ class ::Rundoc::CodeCommand
|
|
17
17
|
execution_context = env[:context]
|
18
18
|
document_path = @path.expand_path(execution_context.source_dir)
|
19
19
|
|
20
|
-
output = Rundoc::
|
20
|
+
output = Rundoc::Document.new(
|
21
21
|
document_path.read,
|
22
22
|
context: Rundoc::Context::Execution.new(
|
23
23
|
source_path: document_path,
|
@@ -24,7 +24,9 @@ module Rundoc
|
|
24
24
|
|
25
25
|
def to_md(env)
|
26
26
|
if render_command?
|
27
|
-
|
27
|
+
if env[:commands].any? { |c| c[:object].not_hidden? }
|
28
|
+
raise "must call write in its own code section"
|
29
|
+
end
|
28
30
|
env[:before] << "In file `#{filename}` write:"
|
29
31
|
env[:before] << NEWLINE
|
30
32
|
end
|
data/lib/rundoc/code_command.rb
CHANGED
@@ -1,25 +1,20 @@
|
|
1
1
|
module Rundoc
|
2
|
-
#
|
2
|
+
# Represents a single rundoc file on disk,
|
3
3
|
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
|
7
|
-
|
8
|
-
INDENT_BLOCK = '(?<before_indent>(^\s*$\n|\A)(^(?:[ ]{4}|\t))(?<indent_contents>.*)(?<after_indent>[^\s].*$\n?(?:(?:^\s*$\n?)*^(?:[ ]{4}|\t).*[^\s].*$\n?)*))'
|
4
|
+
# Each document contains one or more fenced code blocks.
|
5
|
+
# Those are parsed as `FencedCodeBlock` instances and then
|
6
|
+
# executed.
|
7
|
+
class Document
|
9
8
|
GITHUB_BLOCK = '^(?<fence>(?<fence_char>~|`){3,})\s*?(?<lang>\w+)?\s*?\n(?<contents>.*?)^\g<fence>\g<fence_char>*\s*?\n?'
|
10
9
|
CODEBLOCK_REGEX = /(#{GITHUB_BLOCK})/m
|
11
|
-
COMMAND_REGEX = ->(keyword) {
|
12
|
-
/^#{keyword}(?<tag>(\s|=|-|>)?(=|-|>)?)\s*(?<command>(\S)+)\s+(?<statement>.*)$/
|
13
|
-
}
|
14
10
|
PARTIAL_RESULT = []
|
15
11
|
|
16
|
-
attr_reader :contents, :
|
12
|
+
attr_reader :contents, :stack, :context
|
17
13
|
|
18
|
-
def initialize(contents, context
|
14
|
+
def initialize(contents, context:)
|
19
15
|
@context = context
|
20
16
|
@contents = contents
|
21
17
|
@original = contents.dup
|
22
|
-
@keyword = keyword
|
23
18
|
@stack = []
|
24
19
|
partition
|
25
20
|
PARTIAL_RESULT.clear
|
@@ -44,7 +39,7 @@ module Rundoc
|
|
44
39
|
|
45
40
|
def self.partial_result_to_doc
|
46
41
|
out = to_doc(result: PARTIAL_RESULT)
|
47
|
-
unfinished =
|
42
|
+
unfinished = FencedCodeBlock.partial_result_to_doc
|
48
43
|
out << unfinished if unfinished
|
49
44
|
out
|
50
45
|
end
|
@@ -60,9 +55,10 @@ module Rundoc
|
|
60
55
|
@stack << head unless head.empty?
|
61
56
|
unless code.empty?
|
62
57
|
match = code.match(CODEBLOCK_REGEX)
|
63
|
-
@stack <<
|
64
|
-
match,
|
65
|
-
|
58
|
+
@stack << FencedCodeBlock.new(
|
59
|
+
fence: match[:fence],
|
60
|
+
lang: match[:lang],
|
61
|
+
code: match[:contents],
|
66
62
|
context: context
|
67
63
|
)
|
68
64
|
end
|
@@ -71,5 +67,3 @@ module Rundoc
|
|
71
67
|
end
|
72
68
|
end
|
73
69
|
end
|
74
|
-
|
75
|
-
# convert string of markdown to array of strings and code_command
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rundoc
|
4
|
+
# A code secttion respesents a block of fenced code
|
5
|
+
#
|
6
|
+
# A document can have multiple code sections
|
7
|
+
class FencedCodeBlock
|
8
|
+
AUTOGEN_WARNING = "\n<!-- STOP. This document is autogenerated. Do not manually modify. See the top of the doc for more details. -->"
|
9
|
+
attr_accessor :fence, :lang, :code
|
10
|
+
|
11
|
+
PARTIAL_RESULT = []
|
12
|
+
PARTIAL_ENV = {}
|
13
|
+
|
14
|
+
# Used for tests to inspect the command that was executed
|
15
|
+
def executed_commands
|
16
|
+
raise "Nothing executed" unless @env[:commands].any?
|
17
|
+
|
18
|
+
@env[:commands].map { |c| c[:object] }
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param fence [String] the fence used to start the code block like "```".
|
22
|
+
# @param lang [String] any extra string after the fence like for example
|
23
|
+
# a fence of "```ruby" the lang would be "ruby".
|
24
|
+
# @param code [String] the code block contents inside the fence.
|
25
|
+
# @param context [Context::Execution] The details about where
|
26
|
+
# the code block came from.
|
27
|
+
def initialize(fence:, lang:, code:, context:)
|
28
|
+
@fence = fence
|
29
|
+
@lang = lang
|
30
|
+
@code = code
|
31
|
+
@executed = false
|
32
|
+
@env = {}
|
33
|
+
@stack = []
|
34
|
+
@context = context
|
35
|
+
@rendered = ""
|
36
|
+
self.class.parse_code_commands(@code).each do |code_command|
|
37
|
+
@stack.unshift(code_command)
|
38
|
+
end
|
39
|
+
|
40
|
+
PARTIAL_RESULT.clear
|
41
|
+
PARTIAL_ENV.clear
|
42
|
+
end
|
43
|
+
|
44
|
+
def call
|
45
|
+
return self if @executed
|
46
|
+
@executed = true
|
47
|
+
|
48
|
+
result = []
|
49
|
+
env = @env
|
50
|
+
env[:commands] = []
|
51
|
+
env[:fence_start] = "#{fence}#{lang}"
|
52
|
+
env[:fence_end] = "#{fence}#{AUTOGEN_WARNING}"
|
53
|
+
env[:before] = []
|
54
|
+
env[:after] = []
|
55
|
+
env[:context] = @context
|
56
|
+
env[:stack] = @stack
|
57
|
+
|
58
|
+
while (code_command = @stack.pop)
|
59
|
+
code_output = code_command.call(env) || ""
|
60
|
+
code_line = code_command.to_md(env) || ""
|
61
|
+
result << code_line if code_command.render_command?
|
62
|
+
result << code_output if code_command.render_result?
|
63
|
+
|
64
|
+
PARTIAL_RESULT.replace(result)
|
65
|
+
PARTIAL_ENV.replace(env)
|
66
|
+
|
67
|
+
env[:commands] << {
|
68
|
+
object: code_command,
|
69
|
+
output: code_output,
|
70
|
+
command: code_line
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
if env[:commands].any? { |c| c[:object].not_hidden? }
|
75
|
+
@rendered = self.class.to_doc(result: result, env: env)
|
76
|
+
end
|
77
|
+
self
|
78
|
+
end
|
79
|
+
|
80
|
+
def render
|
81
|
+
call
|
82
|
+
@rendered
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.partial_result_to_doc
|
86
|
+
to_doc(result: PARTIAL_RESULT, env: PARTIAL_ENV)
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.to_doc(result:, env:)
|
90
|
+
array = [env[:before]]
|
91
|
+
|
92
|
+
result.flatten!
|
93
|
+
result.compact!
|
94
|
+
result.map! { |s| s.respond_to?(:rstrip) ? s.rstrip : s }
|
95
|
+
result.reject!(&:empty?)
|
96
|
+
result.map!(&:to_s)
|
97
|
+
|
98
|
+
if !result.empty?
|
99
|
+
array << env[:fence_start]
|
100
|
+
array << result
|
101
|
+
array << env[:fence_end]
|
102
|
+
end
|
103
|
+
array << env[:after]
|
104
|
+
|
105
|
+
array.flatten!
|
106
|
+
array.compact!
|
107
|
+
array.map! { |s| s.respond_to?(:rstrip) ? s.rstrip : s }
|
108
|
+
array.reject!(&:empty?)
|
109
|
+
array.map!(&:to_s)
|
110
|
+
|
111
|
+
array.join("\n") << "\n"
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.parse_code_commands(code)
|
115
|
+
parser = Rundoc::PegParser.new.code_block
|
116
|
+
tree = parser.parse(code)
|
117
|
+
commands = Rundoc::PegTransformer.new.apply(tree)
|
118
|
+
commands = [commands] unless commands.is_a?(Array)
|
119
|
+
commands
|
120
|
+
rescue ::Parslet::ParseFailed => e
|
121
|
+
raise "Could not compile code:\n#{code}\nReason: #{e.message}"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
data/lib/rundoc/version.rb
CHANGED
data/lib/rundoc.rb
CHANGED
@@ -87,8 +87,8 @@ module Rundoc
|
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
|
-
require "rundoc/
|
91
|
-
require "rundoc/
|
90
|
+
require "rundoc/document"
|
91
|
+
require "rundoc/fenced_code_block"
|
92
92
|
require "rundoc/code_command"
|
93
93
|
require "rundoc/peg_parser"
|
94
94
|
require "rundoc/cli_argument_parser"
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class IntegrationPreErb < Minitest::Test
|
4
|
+
def test_file_write
|
5
|
+
key = SecureRandom.hex
|
6
|
+
contents = <<~RUBY
|
7
|
+
```
|
8
|
+
:::>> pre.erb file.write "lol.txt"
|
9
|
+
Multi line
|
10
|
+
<%= "#{key}" %>
|
11
|
+
```
|
12
|
+
RUBY
|
13
|
+
|
14
|
+
Dir.mktmpdir do |dir|
|
15
|
+
Dir.chdir(dir) do
|
16
|
+
expected = <<~EOF
|
17
|
+
In file `lol.txt` write:
|
18
|
+
|
19
|
+
```
|
20
|
+
Multi line
|
21
|
+
#{key}
|
22
|
+
```
|
23
|
+
EOF
|
24
|
+
|
25
|
+
parsed = parse_contents(contents)
|
26
|
+
actual = parsed.to_md.gsub(Rundoc::FencedCodeBlock::AUTOGEN_WARNING, "").strip
|
27
|
+
assert_equal expected.strip, actual.strip
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_erb_shared_binding_persists_values
|
33
|
+
key = SecureRandom.hex
|
34
|
+
contents = <<~RUBY
|
35
|
+
```
|
36
|
+
:::-- print.erb <% secret = "#{key}" %>
|
37
|
+
:::>> pre.erb $ echo <%= secret %>
|
38
|
+
```
|
39
|
+
RUBY
|
40
|
+
|
41
|
+
Dir.mktmpdir do |dir|
|
42
|
+
Dir.chdir(dir) do
|
43
|
+
expected = <<~EOF
|
44
|
+
```
|
45
|
+
$ echo #{key}
|
46
|
+
#{key}
|
47
|
+
```
|
48
|
+
EOF
|
49
|
+
|
50
|
+
parsed = parse_contents(contents)
|
51
|
+
actual = parsed.to_md.gsub(Rundoc::FencedCodeBlock::AUTOGEN_WARNING, "").strip
|
52
|
+
assert_equal expected.strip, actual.strip
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -21,7 +21,7 @@ class IntegrationPrintTest < Minitest::Test
|
|
21
21
|
#{key}
|
22
22
|
EOF
|
23
23
|
parsed = parse_contents(contents)
|
24
|
-
actual = parsed.to_md.gsub(Rundoc::
|
24
|
+
actual = parsed.to_md.gsub(Rundoc::FencedCodeBlock::AUTOGEN_WARNING, "")
|
25
25
|
assert_equal expected, actual
|
26
26
|
end
|
27
27
|
end
|
@@ -44,7 +44,7 @@ class IntegrationPrintTest < Minitest::Test
|
|
44
44
|
one
|
45
45
|
EOF
|
46
46
|
parsed = parse_contents(contents)
|
47
|
-
actual = parsed.to_md.gsub(Rundoc::
|
47
|
+
actual = parsed.to_md.gsub(Rundoc::FencedCodeBlock::AUTOGEN_WARNING, "")
|
48
48
|
assert_equal expected, actual
|
49
49
|
end
|
50
50
|
end
|
@@ -70,7 +70,7 @@ class IntegrationPrintTest < Minitest::Test
|
|
70
70
|
```
|
71
71
|
EOF
|
72
72
|
parsed = parse_contents(contents)
|
73
|
-
actual = parsed.to_md.gsub(Rundoc::
|
73
|
+
actual = parsed.to_md.gsub(Rundoc::FencedCodeBlock::AUTOGEN_WARNING, "")
|
74
74
|
assert_equal expected, actual
|
75
75
|
end
|
76
76
|
end
|
@@ -94,7 +94,7 @@ class IntegrationPrintTest < Minitest::Test
|
|
94
94
|
there
|
95
95
|
EOF
|
96
96
|
parsed = parse_contents(contents)
|
97
|
-
actual = parsed.to_md.gsub(Rundoc::
|
97
|
+
actual = parsed.to_md.gsub(Rundoc::FencedCodeBlock::AUTOGEN_WARNING, "")
|
98
98
|
assert_equal expected, actual
|
99
99
|
end
|
100
100
|
end
|
@@ -118,7 +118,7 @@ class IntegrationPrintTest < Minitest::Test
|
|
118
118
|
there
|
119
119
|
EOF
|
120
120
|
parsed = parse_contents(contents)
|
121
|
-
actual = parsed.to_md.gsub(Rundoc::
|
121
|
+
actual = parsed.to_md.gsub(Rundoc::FencedCodeBlock::AUTOGEN_WARNING, "")
|
122
122
|
assert_equal expected, actual
|
123
123
|
end
|
124
124
|
end
|
@@ -142,7 +142,7 @@ class IntegrationPrintTest < Minitest::Test
|
|
142
142
|
there
|
143
143
|
EOF
|
144
144
|
parsed = parse_contents(contents)
|
145
|
-
actual = parsed.to_md.gsub(Rundoc::
|
145
|
+
actual = parsed.to_md.gsub(Rundoc::FencedCodeBlock::AUTOGEN_WARNING, "")
|
146
146
|
assert_equal expected, actual
|
147
147
|
end
|
148
148
|
end
|
@@ -163,7 +163,7 @@ class IntegrationPrintTest < Minitest::Test
|
|
163
163
|
Hello there
|
164
164
|
EOF
|
165
165
|
parsed = parse_contents(contents)
|
166
|
-
actual = parsed.to_md.gsub(Rundoc::
|
166
|
+
actual = parsed.to_md.gsub(Rundoc::FencedCodeBlock::AUTOGEN_WARNING, "")
|
167
167
|
assert_equal expected, actual
|
168
168
|
end
|
169
169
|
end
|
@@ -186,7 +186,7 @@ class IntegrationPrintTest < Minitest::Test
|
|
186
186
|
```
|
187
187
|
EOF
|
188
188
|
parsed = parse_contents(contents)
|
189
|
-
actual = parsed.to_md.gsub(Rundoc::
|
189
|
+
actual = parsed.to_md.gsub(Rundoc::FencedCodeBlock::AUTOGEN_WARNING, "")
|
190
190
|
assert_equal expected, actual
|
191
191
|
end
|
192
192
|
end
|
@@ -22,7 +22,7 @@ class IntegrationRequireTest < Minitest::Test
|
|
22
22
|
source_path.read,
|
23
23
|
source_path: source_path
|
24
24
|
)
|
25
|
-
actual = parsed.to_md.gsub(Rundoc::
|
25
|
+
actual = parsed.to_md.gsub(Rundoc::FencedCodeBlock::AUTOGEN_WARNING, "")
|
26
26
|
assert_equal "Hello World!", actual.strip
|
27
27
|
end
|
28
28
|
end
|
@@ -50,7 +50,7 @@ class IntegrationRequireTest < Minitest::Test
|
|
50
50
|
source_path.read,
|
51
51
|
source_path: source_path
|
52
52
|
)
|
53
|
-
actual = parsed.to_md.gsub(Rundoc::
|
53
|
+
actual = parsed.to_md.gsub(Rundoc::FencedCodeBlock::AUTOGEN_WARNING, "")
|
54
54
|
# Command was run
|
55
55
|
assert dir.join("foo.txt").exist?
|
56
56
|
assert "echo hello world", dir.join("foo.txt").read.strip
|
@@ -89,7 +89,7 @@ class IntegrationRequireTest < Minitest::Test
|
|
89
89
|
source_path.read,
|
90
90
|
source_path: source_path
|
91
91
|
)
|
92
|
-
actual = parsed.to_md.gsub(Rundoc::
|
92
|
+
actual = parsed.to_md.gsub(Rundoc::FencedCodeBlock::AUTOGEN_WARNING, "")
|
93
93
|
assert_equal "Hello World!", actual.strip
|
94
94
|
end
|
95
95
|
end
|
@@ -23,7 +23,7 @@ class IntegrationWebsiteTest < Minitest::Test
|
|
23
23
|
output_dir: screenshots_dir.parent,
|
24
24
|
screenshots_dirname: screenshots_dirname
|
25
25
|
)
|
26
|
-
actual = parsed.to_md.gsub(Rundoc::
|
26
|
+
actual = parsed.to_md.gsub(Rundoc::FencedCodeBlock::AUTOGEN_WARNING, "")
|
27
27
|
|
28
28
|
expected = ""
|
29
29
|
assert_equal expected, actual.strip
|
@@ -14,10 +14,11 @@ class CodeSectionTest < Minitest::Test
|
|
14
14
|
|
15
15
|
Dir.mktmpdir do |dir|
|
16
16
|
Dir.chdir(dir) do
|
17
|
-
match = contents.match(Rundoc::
|
18
|
-
result = Rundoc::
|
19
|
-
match,
|
20
|
-
|
17
|
+
match = contents.match(Rundoc::Document::CODEBLOCK_REGEX)
|
18
|
+
result = Rundoc::FencedCodeBlock.new(
|
19
|
+
fence: match[:fence],
|
20
|
+
lang: match[:lang],
|
21
|
+
code: match[:contents],
|
21
22
|
context: default_context
|
22
23
|
).render
|
23
24
|
assert_equal "", result
|
@@ -33,13 +34,14 @@ class CodeSectionTest < Minitest::Test
|
|
33
34
|
|
34
35
|
RUBY
|
35
36
|
|
36
|
-
match = contents.match(Rundoc::
|
37
|
-
result = Rundoc::
|
38
|
-
match,
|
39
|
-
|
37
|
+
match = contents.match(Rundoc::Document::CODEBLOCK_REGEX)
|
38
|
+
result = Rundoc::FencedCodeBlock.new(
|
39
|
+
fence: match[:fence],
|
40
|
+
lang: match[:lang],
|
41
|
+
code: match[:contents],
|
40
42
|
context: default_context
|
41
43
|
).render
|
42
|
-
assert_equal contents, result.gsub(Rundoc::
|
44
|
+
assert_equal contents, result.gsub(Rundoc::FencedCodeBlock::AUTOGEN_WARNING, "\n")
|
43
45
|
end
|
44
46
|
|
45
47
|
def test_show_command_hide_render
|
@@ -49,15 +51,16 @@ class CodeSectionTest < Minitest::Test
|
|
49
51
|
```
|
50
52
|
RUBY
|
51
53
|
|
52
|
-
match = contents.match(Rundoc::
|
53
|
-
code_section = Rundoc::
|
54
|
-
match,
|
55
|
-
|
54
|
+
match = contents.match(Rundoc::Document::CODEBLOCK_REGEX)
|
55
|
+
code_section = Rundoc::FencedCodeBlock.new(
|
56
|
+
fence: match[:fence],
|
57
|
+
lang: match[:lang],
|
58
|
+
code: match[:contents],
|
56
59
|
context: default_context
|
57
60
|
)
|
58
61
|
code_section.render
|
59
62
|
|
60
|
-
code_command = code_section.
|
63
|
+
code_command = code_section.executed_commands.first
|
61
64
|
assert_equal true, code_command.render_command
|
62
65
|
assert_equal false, code_command.render_result
|
63
66
|
|
@@ -67,15 +70,16 @@ class CodeSectionTest < Minitest::Test
|
|
67
70
|
```
|
68
71
|
RUBY
|
69
72
|
|
70
|
-
match = contents.match(Rundoc::
|
71
|
-
code_section = Rundoc::
|
72
|
-
match,
|
73
|
-
|
73
|
+
match = contents.match(Rundoc::Document::CODEBLOCK_REGEX)
|
74
|
+
code_section = Rundoc::FencedCodeBlock.new(
|
75
|
+
fence: match[:fence],
|
76
|
+
lang: match[:lang],
|
77
|
+
code: match[:contents],
|
74
78
|
context: default_context
|
75
79
|
)
|
76
80
|
code_section.render
|
77
81
|
|
78
|
-
code_command = code_section.
|
82
|
+
code_command = code_section.executed_commands.first
|
79
83
|
assert_equal true, code_command.render_command
|
80
84
|
assert_equal false, code_command.render_result
|
81
85
|
end
|
@@ -87,16 +91,17 @@ class CodeSectionTest < Minitest::Test
|
|
87
91
|
```
|
88
92
|
RUBY
|
89
93
|
|
90
|
-
match = contents.match(Rundoc::
|
91
|
-
code_section = Rundoc::
|
92
|
-
match,
|
93
|
-
|
94
|
+
match = contents.match(Rundoc::Document::CODEBLOCK_REGEX)
|
95
|
+
code_section = Rundoc::FencedCodeBlock.new(
|
96
|
+
fence: match[:fence],
|
97
|
+
lang: match[:lang],
|
98
|
+
code: match[:contents],
|
94
99
|
context: default_context
|
95
100
|
)
|
96
101
|
code_section.render
|
97
102
|
|
98
|
-
puts code_section.
|
99
|
-
code_command = code_section.
|
103
|
+
puts code_section.executed_commands.inspect
|
104
|
+
code_command = code_section.executed_commands.first
|
100
105
|
assert_equal true, code_command.render_command
|
101
106
|
assert_equal true, code_command.render_result
|
102
107
|
end
|
@@ -108,15 +113,16 @@ class CodeSectionTest < Minitest::Test
|
|
108
113
|
```
|
109
114
|
RUBY
|
110
115
|
|
111
|
-
match = contents.match(Rundoc::
|
112
|
-
code_section = Rundoc::
|
113
|
-
match,
|
114
|
-
|
116
|
+
match = contents.match(Rundoc::Document::CODEBLOCK_REGEX)
|
117
|
+
code_section = Rundoc::FencedCodeBlock.new(
|
118
|
+
fence: match[:fence],
|
119
|
+
lang: match[:lang],
|
120
|
+
code: match[:contents],
|
115
121
|
context: default_context
|
116
122
|
)
|
117
123
|
code_section.render
|
118
124
|
|
119
|
-
code_command = code_section.
|
125
|
+
code_command = code_section.executed_commands.first
|
120
126
|
assert_equal false, code_command.render_command
|
121
127
|
assert_equal false, code_command.render_result
|
122
128
|
|
@@ -126,15 +132,16 @@ class CodeSectionTest < Minitest::Test
|
|
126
132
|
```
|
127
133
|
RUBY
|
128
134
|
|
129
|
-
match = contents.match(Rundoc::
|
130
|
-
code_section = Rundoc::
|
131
|
-
match,
|
132
|
-
|
135
|
+
match = contents.match(Rundoc::Document::CODEBLOCK_REGEX)
|
136
|
+
code_section = Rundoc::FencedCodeBlock.new(
|
137
|
+
fence: match[:fence],
|
138
|
+
lang: match[:lang],
|
139
|
+
code: match[:contents],
|
133
140
|
context: default_context
|
134
141
|
)
|
135
142
|
code_section.render
|
136
143
|
|
137
|
-
code_command = code_section.
|
144
|
+
code_command = code_section.executed_commands.first
|
138
145
|
assert_equal false, code_command.render_command
|
139
146
|
assert_equal false, code_command.render_result
|
140
147
|
end
|
@@ -146,15 +153,16 @@ class CodeSectionTest < Minitest::Test
|
|
146
153
|
```
|
147
154
|
RUBY
|
148
155
|
|
149
|
-
match = contents.match(Rundoc::
|
150
|
-
code_section = Rundoc::
|
151
|
-
match,
|
152
|
-
|
156
|
+
match = contents.match(Rundoc::Document::CODEBLOCK_REGEX)
|
157
|
+
code_section = Rundoc::FencedCodeBlock.new(
|
158
|
+
fence: match[:fence],
|
159
|
+
lang: match[:lang],
|
160
|
+
code: match[:contents],
|
153
161
|
context: default_context
|
154
162
|
)
|
155
163
|
code_section.render
|
156
164
|
|
157
|
-
code_command = code_section.
|
165
|
+
code_command = code_section.executed_commands.first
|
158
166
|
assert_equal false, code_command.render_command
|
159
167
|
assert_equal true, code_command.render_result
|
160
168
|
end
|
data/test/rundoc/parser_test.rb
CHANGED
@@ -17,7 +17,7 @@ class ParserTest < Minitest::Test
|
|
17
17
|
Dir.chdir(dir) do
|
18
18
|
expected = "sup\n\n```\n$ mkdir foo\n$ ls\nfoo\n```\n\nyo\n"
|
19
19
|
parsed = parse_contents(contents)
|
20
|
-
actual = parsed.to_md.gsub(Rundoc::
|
20
|
+
actual = parsed.to_md.gsub(Rundoc::FencedCodeBlock::AUTOGEN_WARNING, "")
|
21
21
|
assert_equal expected, actual
|
22
22
|
end
|
23
23
|
end
|
@@ -39,7 +39,7 @@ class ParserTest < Minitest::Test
|
|
39
39
|
Dir.chdir(dir) do
|
40
40
|
expected = "sup\n\nIn file `foo/code.rb` write:\n\n```\na = 1 + 1\nb = a * 2\n```\nyo\n"
|
41
41
|
parsed = parse_contents(contents)
|
42
|
-
actual = parsed.to_md.gsub(Rundoc::
|
42
|
+
actual = parsed.to_md.gsub(Rundoc::FencedCodeBlock::AUTOGEN_WARNING, "")
|
43
43
|
assert_equal expected, actual
|
44
44
|
end
|
45
45
|
end
|
@@ -57,7 +57,7 @@ class ParserTest < Minitest::Test
|
|
57
57
|
Dir.chdir(dir) do
|
58
58
|
expected = "\nIn file `foo/newb.rb` write:\n\n```\nputs 'hello world'\n$ cat foo/newb.rb\nputs 'hello world'\n```\n"
|
59
59
|
parsed = parse_contents(contents)
|
60
|
-
actual = parsed.to_md.gsub(Rundoc::
|
60
|
+
actual = parsed.to_md.gsub(Rundoc::FencedCodeBlock::AUTOGEN_WARNING, "")
|
61
61
|
assert_equal expected, actual
|
62
62
|
end
|
63
63
|
end
|
@@ -240,22 +240,6 @@ class PegParserTest < Minitest::Test
|
|
240
240
|
end
|
241
241
|
|
242
242
|
def test_no_args
|
243
|
-
# input = String.new
|
244
|
-
# input << %Q{rundoc}
|
245
|
-
# parser = Rundoc::PegParser.new.no_args_method
|
246
|
-
# tree = parser.parse_with_debug(input)
|
247
|
-
# actual = @transformer.apply(tree)
|
248
|
-
# assert_equal("rundoc", actual.to_s)
|
249
|
-
|
250
|
-
# input = String.new
|
251
|
-
# input << %Q{:::-- rundoc\n}
|
252
|
-
# parser = Rundoc::PegParser.new.command
|
253
|
-
# tree = parser.parse_with_debug(input)
|
254
|
-
|
255
|
-
# actual = @transformer.apply(tree)
|
256
|
-
# assert_equal :rundoc, actual.keyword
|
257
|
-
# assert_nil(actual.original_args)
|
258
|
-
|
259
243
|
input = +""
|
260
244
|
input << %(:::-- rundoc\n)
|
261
245
|
input << %(email = ENV['HEROKU_EMAIL'] || `heroku auth:whoami`\n)
|
@@ -333,19 +317,7 @@ class PegParserTest < Minitest::Test
|
|
333
317
|
actual = @transformer.apply(tree)
|
334
318
|
assert_equal ["rails server", {name: "server"}], actual.original_args
|
335
319
|
|
336
|
-
# input = +""
|
337
|
-
# input << %Q{background.start("rails server", name: "server")}
|
338
|
-
# parser = Rundoc::PegParser.new.method_call
|
339
|
-
|
340
|
-
# tree = parser.parse_with_debug(input)
|
341
|
-
|
342
|
-
# puts tree.inspect
|
343
|
-
|
344
|
-
# actual = @transformer.apply(tree)
|
345
|
-
# assert_equal :"background.start", actual.keyword
|
346
|
-
|
347
320
|
# ================
|
348
|
-
|
349
321
|
input = +""
|
350
322
|
input << %{call("foo", "bar")}
|
351
323
|
|
@@ -358,7 +330,6 @@ class PegParserTest < Minitest::Test
|
|
358
330
|
assert_equal ["foo", "bar"], actual.original_args
|
359
331
|
|
360
332
|
# ======================
|
361
|
-
|
362
333
|
input = +""
|
363
334
|
input << %{call("foo", "bar", biz: "baz")}
|
364
335
|
|
@@ -372,14 +343,10 @@ class PegParserTest < Minitest::Test
|
|
372
343
|
def test_positional_args_code_block
|
373
344
|
input = +""
|
374
345
|
input << %{:::>> background.start("rails server", name: "server")\n}
|
375
|
-
# input << %Q{:::-- background.stop(name: "server")\n}
|
376
346
|
|
377
347
|
parser = Rundoc::PegParser.new.command
|
378
348
|
|
379
349
|
tree = parser.parse_with_debug(input)
|
380
|
-
|
381
|
-
# puts tree.inspect
|
382
|
-
|
383
350
|
actual = @transformer.apply(tree)
|
384
351
|
assert_equal :"background.start", actual.keyword
|
385
352
|
assert_equal ["rails server", {name: "server"}], actual.original_args
|
data/test/rundoc/regex_test.rb
CHANGED
@@ -4,36 +4,20 @@ class RegexTest < Minitest::Test
|
|
4
4
|
def setup
|
5
5
|
end
|
6
6
|
|
7
|
-
def test_indent_regex
|
8
|
-
contents = <<~RUBY
|
9
|
-
foo
|
10
|
-
|
11
|
-
$ cd
|
12
|
-
yo
|
13
|
-
sup
|
14
|
-
|
15
|
-
bar
|
16
|
-
RUBY
|
17
|
-
|
18
|
-
regex = Rundoc::Parser::INDENT_BLOCK
|
19
|
-
parsed = contents.match(/#{regex}/).to_s
|
20
|
-
assert_equal "\n $ cd\n yo\n sup\n", parsed
|
21
|
-
end
|
22
|
-
|
23
7
|
def test_github_regex
|
24
8
|
contents = <<~RUBY
|
25
9
|
foo
|
26
|
-
|
10
|
+
|
27
11
|
```
|
28
12
|
$ cd
|
29
13
|
yo
|
30
14
|
sup
|
31
15
|
```
|
32
|
-
|
16
|
+
|
33
17
|
bar
|
34
18
|
RUBY
|
35
19
|
|
36
|
-
regex = Rundoc::
|
20
|
+
regex = Rundoc::Document::GITHUB_BLOCK
|
37
21
|
parsed = contents.match(/#{regex}/m).to_s
|
38
22
|
assert_equal "```\n$ cd\nyo\nsup\n```\n", parsed
|
39
23
|
end
|
@@ -41,74 +25,40 @@ class RegexTest < Minitest::Test
|
|
41
25
|
def test_github_tagged_regex
|
42
26
|
contents = <<~RUBY
|
43
27
|
foo
|
44
|
-
|
28
|
+
|
45
29
|
```ruby
|
46
30
|
$ cd
|
47
31
|
yo
|
48
32
|
sup
|
49
33
|
```
|
50
|
-
|
34
|
+
|
51
35
|
bar
|
52
36
|
RUBY
|
53
37
|
|
54
|
-
regex = Rundoc::
|
38
|
+
regex = Rundoc::Document::GITHUB_BLOCK
|
55
39
|
parsed = contents.match(/#{regex}/m).to_s
|
56
40
|
assert_equal "```ruby\n$ cd\nyo\nsup\n```\n", parsed
|
57
41
|
end
|
58
42
|
|
59
|
-
def test_command_regex
|
60
|
-
regex = Rundoc::Parser::COMMAND_REGEX.call(":::")
|
61
|
-
|
62
|
-
contents = ":::$ mkdir schneems"
|
63
|
-
match = contents.match(regex)
|
64
|
-
assert_equal "", match[:tag]
|
65
|
-
assert_equal "$", match[:command]
|
66
|
-
assert_equal "mkdir schneems", match[:statement]
|
67
|
-
|
68
|
-
contents = ":::=$ mkdir schneems"
|
69
|
-
match = contents.match(regex)
|
70
|
-
assert_equal "=", match[:tag]
|
71
|
-
assert_equal "$", match[:command]
|
72
|
-
assert_equal "mkdir schneems", match[:statement]
|
73
|
-
|
74
|
-
contents = ":::= $ mkdir schneems"
|
75
|
-
match = contents.match(regex)
|
76
|
-
assert_equal "=", match[:tag]
|
77
|
-
assert_equal "$", match[:command]
|
78
|
-
assert_equal "mkdir schneems", match[:statement]
|
79
|
-
|
80
|
-
contents = ":::-$ mkdir schneems"
|
81
|
-
match = contents.match(regex)
|
82
|
-
assert_equal "-", match[:tag]
|
83
|
-
assert_equal "$", match[:command]
|
84
|
-
assert_equal "mkdir schneems", match[:statement]
|
85
|
-
|
86
|
-
contents = ":::- $ mkdir schneems"
|
87
|
-
match = contents.match(regex)
|
88
|
-
assert_equal "-", match[:tag]
|
89
|
-
assert_equal "$", match[:command]
|
90
|
-
assert_equal "mkdir schneems", match[:statement]
|
91
|
-
end
|
92
|
-
|
93
43
|
def test_codeblock_regex
|
94
44
|
contents = <<~RUBY
|
95
45
|
foo
|
96
|
-
|
46
|
+
|
97
47
|
```
|
98
48
|
:::>$ mkdir
|
99
49
|
```
|
100
|
-
|
50
|
+
|
101
51
|
zoo
|
102
|
-
|
52
|
+
|
103
53
|
```
|
104
54
|
:::>$ cd ..
|
105
55
|
something
|
106
56
|
```
|
107
|
-
|
57
|
+
|
108
58
|
bar
|
109
59
|
RUBY
|
110
60
|
|
111
|
-
regex = Rundoc::
|
61
|
+
regex = Rundoc::Document::CODEBLOCK_REGEX
|
112
62
|
|
113
63
|
actual = contents.partition(regex)
|
114
64
|
expected = ["foo\n\n",
|
@@ -133,7 +83,7 @@ class RegexTest < Minitest::Test
|
|
133
83
|
```java
|
134
84
|
:::>> write app/controllers/Application.java
|
135
85
|
package controllers;
|
136
|
-
|
86
|
+
|
137
87
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
138
88
|
import models.Pinger;
|
139
89
|
import play.libs.Akka;
|
@@ -146,7 +96,7 @@ class RegexTest < Minitest::Test
|
|
146
96
|
import akka.actor.ActorRef;
|
147
97
|
import akka.actor.Cancellable;
|
148
98
|
import akka.actor.Props;
|
149
|
-
|
99
|
+
|
150
100
|
public class Application extends Controller {
|
151
101
|
public static WebSocket<String> pingWs() {
|
152
102
|
return new WebSocket<String>() {
|
@@ -159,7 +109,7 @@ class RegexTest < Minitest::Test
|
|
159
109
|
Akka.system().dispatcher(),
|
160
110
|
null
|
161
111
|
);
|
162
|
-
|
112
|
+
|
163
113
|
in.onClose(new Callback0() {
|
164
114
|
@Override
|
165
115
|
public void invoke() throws Throwable {
|
@@ -167,14 +117,14 @@ class RegexTest < Minitest::Test
|
|
167
117
|
}
|
168
118
|
});
|
169
119
|
}
|
170
|
-
|
120
|
+
|
171
121
|
};
|
172
122
|
}
|
173
|
-
|
123
|
+
|
174
124
|
public static Result pingJs() {
|
175
125
|
return ok(views.js.ping.render());
|
176
126
|
}
|
177
|
-
|
127
|
+
|
178
128
|
public static Result index() {
|
179
129
|
return ok(index.render());
|
180
130
|
}
|
@@ -182,7 +132,7 @@ class RegexTest < Minitest::Test
|
|
182
132
|
```
|
183
133
|
RUBY
|
184
134
|
|
185
|
-
regex = Rundoc::
|
135
|
+
regex = Rundoc::Document::CODEBLOCK_REGEX
|
186
136
|
match = contents.match(regex)
|
187
137
|
assert_equal "java", match[:lang]
|
188
138
|
assert_equal "```", match[:fence]
|
@@ -205,7 +155,7 @@ class RegexTest < Minitest::Test
|
|
205
155
|
:::>> $ echo "hello"
|
206
156
|
```
|
207
157
|
MD
|
208
|
-
regex = Rundoc::
|
158
|
+
regex = Rundoc::Document::CODEBLOCK_REGEX
|
209
159
|
match = code_block_with_newline.match(regex)
|
210
160
|
assert_equal expected, match.to_s.strip
|
211
161
|
|
data/test/test_helper.rb
CHANGED
@@ -19,12 +19,11 @@ class Minitest::Test
|
|
19
19
|
source_path: nil,
|
20
20
|
screenshots_dirname: nil
|
21
21
|
)
|
22
|
-
|
23
22
|
Rundoc::Context::Execution.new(
|
24
|
-
output_dir: output_dir || Pathname(
|
25
|
-
source_path: source_path || Pathname(
|
23
|
+
output_dir: output_dir || Pathname(File::NULL),
|
24
|
+
source_path: source_path || Pathname(File::NULL),
|
26
25
|
with_contents_dir: nil,
|
27
|
-
screenshots_dirname: screenshots_dirname || Pathname(
|
26
|
+
screenshots_dirname: screenshots_dirname || Pathname(File::NULL)
|
28
27
|
)
|
29
28
|
end
|
30
29
|
|
@@ -39,7 +38,7 @@ class Minitest::Test
|
|
39
38
|
source_path: source_path,
|
40
39
|
screenshots_dirname: screenshots_dirname
|
41
40
|
)
|
42
|
-
Rundoc::
|
41
|
+
Rundoc::Document.new(
|
43
42
|
contents,
|
44
43
|
context: context
|
45
44
|
)
|
@@ -60,7 +59,7 @@ class Minitest::Test
|
|
60
59
|
end
|
61
60
|
|
62
61
|
def strip_autogen_warning(string)
|
63
|
-
string.gsub!(Rundoc::
|
62
|
+
string.gsub!(Rundoc::FencedCodeBlock::AUTOGEN_WARNING, "")
|
64
63
|
string.gsub!(/<!-- STOP.*STOP -->/m, "")
|
65
64
|
string
|
66
65
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rundoc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Schneeman
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-11
|
11
|
+
date: 2024-12-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -215,6 +215,7 @@ files:
|
|
215
215
|
- lib/rundoc/code_command/file_command/remove.rb
|
216
216
|
- lib/rundoc/code_command/no_such_command.rb
|
217
217
|
- lib/rundoc/code_command/pipe.rb
|
218
|
+
- lib/rundoc/code_command/pre/erb.rb
|
218
219
|
- lib/rundoc/code_command/print/erb.rb
|
219
220
|
- lib/rundoc/code_command/print/text.rb
|
220
221
|
- lib/rundoc/code_command/raw.rb
|
@@ -227,10 +228,10 @@ files:
|
|
227
228
|
- lib/rundoc/code_command/website/screenshot.rb
|
228
229
|
- lib/rundoc/code_command/website/visit.rb
|
229
230
|
- lib/rundoc/code_command/write.rb
|
230
|
-
- lib/rundoc/code_section.rb
|
231
231
|
- lib/rundoc/context/after_build.rb
|
232
232
|
- lib/rundoc/context/execution.rb
|
233
|
-
- lib/rundoc/
|
233
|
+
- lib/rundoc/document.rb
|
234
|
+
- lib/rundoc/fenced_code_block.rb
|
234
235
|
- lib/rundoc/peg_parser.rb
|
235
236
|
- lib/rundoc/version.rb
|
236
237
|
- rundoc.gemspec
|
@@ -264,6 +265,7 @@ files:
|
|
264
265
|
- test/integration/after_build_test.rb
|
265
266
|
- test/integration/background_stdin_test.rb
|
266
267
|
- test/integration/failure_test.rb
|
268
|
+
- test/integration/pre_erb_test.rb
|
267
269
|
- test/integration/print_test.rb
|
268
270
|
- test/integration/require_test.rb
|
269
271
|
- test/integration/website_test.rb
|
data/lib/rundoc/code_section.rb
DELETED
@@ -1,155 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Rundoc
|
4
|
-
# A code secttion respesents a block of fenced code
|
5
|
-
#
|
6
|
-
# A document can have multiple code sections
|
7
|
-
class CodeSection
|
8
|
-
class ParseError < StandardError
|
9
|
-
def initialize(options = {})
|
10
|
-
keyword = options[:keyword]
|
11
|
-
command = options[:command]
|
12
|
-
line_number = options[:line_number]
|
13
|
-
block = options[:block].lines.map do |line|
|
14
|
-
if line == command
|
15
|
-
" > #{line}"
|
16
|
-
else
|
17
|
-
" #{line}"
|
18
|
-
end
|
19
|
-
end.join("")
|
20
|
-
|
21
|
-
msg = "Error parsing (line:#{line_number}):\n"
|
22
|
-
msg << "> '#{command.strip}'\n"
|
23
|
-
msg << "No such registered command: '#{keyword}'\n"
|
24
|
-
msg << "registered commands: #{Rundoc.known_commands.inspect}\n\n"
|
25
|
-
msg << block
|
26
|
-
msg << "\n"
|
27
|
-
super(msg)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
COMMAND_REGEX = Rundoc::Parser::COMMAND_REGEX # todo: move whole thing
|
32
|
-
AUTOGEN_WARNING = "\n<!-- STOP. This document is autogenerated. Do not manually modify. See the top of the doc for more details. -->"
|
33
|
-
attr_accessor :original, :fence, :lang, :code, :commands, :keyword
|
34
|
-
|
35
|
-
PARTIAL_RESULT = []
|
36
|
-
PARTIAL_ENV = {}
|
37
|
-
|
38
|
-
def initialize(match, keyword:, context:)
|
39
|
-
@original = match.to_s
|
40
|
-
@commands = []
|
41
|
-
@stack = []
|
42
|
-
@keyword = keyword
|
43
|
-
@context = context
|
44
|
-
@fence = match[:fence]
|
45
|
-
@lang = match[:lang]
|
46
|
-
@code = match[:contents]
|
47
|
-
parse_code_command
|
48
|
-
PARTIAL_RESULT.clear
|
49
|
-
PARTIAL_ENV.clear
|
50
|
-
end
|
51
|
-
|
52
|
-
def render
|
53
|
-
result = []
|
54
|
-
env = {}
|
55
|
-
env[:commands] = []
|
56
|
-
env[:fence_start] = "#{fence}#{lang}"
|
57
|
-
env[:fence_end] = "#{fence}#{AUTOGEN_WARNING}"
|
58
|
-
env[:before] = []
|
59
|
-
env[:after] = []
|
60
|
-
env[:context] = @context
|
61
|
-
|
62
|
-
@stack.each do |s|
|
63
|
-
unless s.respond_to?(:call)
|
64
|
-
result << s
|
65
|
-
next
|
66
|
-
end
|
67
|
-
|
68
|
-
code_command = s
|
69
|
-
code_output = code_command.call(env) || ""
|
70
|
-
code_line = code_command.to_md(env) || ""
|
71
|
-
|
72
|
-
env[:commands] << {object: code_command, output: code_output, command: code_line}
|
73
|
-
|
74
|
-
tmp_result = []
|
75
|
-
tmp_result << code_line if code_command.render_command?
|
76
|
-
tmp_result << code_output if code_command.render_result?
|
77
|
-
|
78
|
-
result << tmp_result unless code_command.hidden?
|
79
|
-
|
80
|
-
PARTIAL_RESULT.replace(result)
|
81
|
-
PARTIAL_ENV.replace(env)
|
82
|
-
end
|
83
|
-
|
84
|
-
return "" if hidden?
|
85
|
-
|
86
|
-
self.class.to_doc(result: result, env: env)
|
87
|
-
end
|
88
|
-
|
89
|
-
def self.partial_result_to_doc
|
90
|
-
to_doc(result: PARTIAL_RESULT, env: PARTIAL_ENV)
|
91
|
-
end
|
92
|
-
|
93
|
-
def self.to_doc(result:, env:)
|
94
|
-
array = [env[:before]]
|
95
|
-
|
96
|
-
result.flatten!
|
97
|
-
result.compact!
|
98
|
-
result.map! { |s| s.respond_to?(:rstrip) ? s.rstrip : s }
|
99
|
-
result.reject!(&:empty?)
|
100
|
-
result.map!(&:to_s)
|
101
|
-
|
102
|
-
if !result.empty?
|
103
|
-
array << env[:fence_start]
|
104
|
-
array << result
|
105
|
-
array << env[:fence_end]
|
106
|
-
end
|
107
|
-
array << env[:after]
|
108
|
-
|
109
|
-
array.flatten!
|
110
|
-
array.compact!
|
111
|
-
array.map! { |s| s.respond_to?(:rstrip) ? s.rstrip : s }
|
112
|
-
array.reject!(&:empty?)
|
113
|
-
array.map!(&:to_s)
|
114
|
-
|
115
|
-
array.join("\n") << "\n"
|
116
|
-
end
|
117
|
-
|
118
|
-
# all of the commands are hidden
|
119
|
-
def hidden?
|
120
|
-
!not_hidden?
|
121
|
-
end
|
122
|
-
|
123
|
-
# one or more of the commands are not hidden
|
124
|
-
def not_hidden?
|
125
|
-
return true if commands.empty?
|
126
|
-
commands.map(&:not_hidden?).detect { |c| c }
|
127
|
-
end
|
128
|
-
|
129
|
-
def parse_code_command
|
130
|
-
parser = Rundoc::PegParser.new.code_block
|
131
|
-
tree = parser.parse(@code)
|
132
|
-
actual = Rundoc::PegTransformer.new.apply(tree)
|
133
|
-
actual = [actual] unless actual.is_a?(Array)
|
134
|
-
actual.each do |code_command|
|
135
|
-
@stack << "\n" if commands.last.is_a?(Rundoc::CodeCommand)
|
136
|
-
@stack << code_command
|
137
|
-
commands << code_command
|
138
|
-
end
|
139
|
-
rescue ::Parslet::ParseFailed => e
|
140
|
-
raise "Could not compile code:\n#{@code}\nReason: #{e.message}"
|
141
|
-
end
|
142
|
-
|
143
|
-
# def check_parse_error(command, code_block)
|
144
|
-
# return unless code_command = @stack.last
|
145
|
-
# return unless code_command.is_a?(Rundoc::CodeCommand::NoSuchCommand)
|
146
|
-
# @original.lines.each_with_index do |line, index|
|
147
|
-
# next unless line == command
|
148
|
-
# raise ParseError.new(keyword: code_command.keyword,
|
149
|
-
# block: code_block,
|
150
|
-
# command: command,
|
151
|
-
# line_number: index.next)
|
152
|
-
# end
|
153
|
-
# end
|
154
|
-
end
|
155
|
-
end
|