rundoc 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +38 -0
- data/README.md +309 -0
- data/Rakefile +16 -0
- data/bin/rundoc +82 -0
- data/lib/rundoc.rb +76 -0
- data/lib/rundoc/code_command.rb +32 -0
- data/lib/rundoc/code_command/bash.rb +57 -0
- data/lib/rundoc/code_command/bash/cd.rb +18 -0
- data/lib/rundoc/code_command/file_command/append.rb +74 -0
- data/lib/rundoc/code_command/file_command/remove.rb +32 -0
- data/lib/rundoc/code_command/no_such_command.rb +6 -0
- data/lib/rundoc/code_command/pipe.rb +37 -0
- data/lib/rundoc/code_command/repl.rb +37 -0
- data/lib/rundoc/code_command/rundoc_command.rb +22 -0
- data/lib/rundoc/code_command/write.rb +34 -0
- data/lib/rundoc/code_section.rb +145 -0
- data/lib/rundoc/parser.rb +53 -0
- data/lib/rundoc/version.rb +3 -0
- data/rundoc.gemspec +28 -0
- data/test/fixtures/play/source.md +231 -0
- data/test/fixtures/rails_4/rundoc.md +504 -0
- data/test/rundoc/code_commands/append_file_test.rb +55 -0
- data/test/rundoc/code_commands/bash_test.rb +29 -0
- data/test/rundoc/code_commands/pipe_test.rb +15 -0
- data/test/rundoc/code_commands/remove_contents_test.rb +42 -0
- data/test/rundoc/code_section_test.rb +42 -0
- data/test/rundoc/parser_test.rb +104 -0
- data/test/rundoc/regex_test.rb +200 -0
- data/test/rundoc/test_parse_java.rb +8 -0
- data/test/test_helper.rb +15 -0
- metadata +144 -0
data/lib/rundoc.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'pathname'
|
3
|
+
require 'rundoc/version'
|
4
|
+
|
5
|
+
module Rundoc
|
6
|
+
extend self
|
7
|
+
|
8
|
+
def code_command_from_keyword(keyword, args)
|
9
|
+
klass = code_command(keyword.to_sym) || Rundoc::CodeCommand::NoSuchCommand
|
10
|
+
cc = klass.new(args)
|
11
|
+
cc.keyword = keyword
|
12
|
+
cc
|
13
|
+
end
|
14
|
+
|
15
|
+
def parser_options
|
16
|
+
@parser_options ||= {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def code_lookup
|
20
|
+
@code_lookup ||= {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def code_command(keyword)
|
24
|
+
code_lookup[:"#{keyword}"]
|
25
|
+
end
|
26
|
+
|
27
|
+
def known_commands
|
28
|
+
code_lookup.keys
|
29
|
+
end
|
30
|
+
|
31
|
+
def register_code_command(keyword, klass)
|
32
|
+
code_lookup[keyword] = klass
|
33
|
+
end
|
34
|
+
|
35
|
+
def configure(&block)
|
36
|
+
yield self
|
37
|
+
end
|
38
|
+
|
39
|
+
def run_after_build
|
40
|
+
@after_build_block ||= []
|
41
|
+
@after_build_block.each(&:call)
|
42
|
+
end
|
43
|
+
|
44
|
+
def after_build(&block)
|
45
|
+
@after_build_block ||= []
|
46
|
+
@after_build_block << block
|
47
|
+
end
|
48
|
+
|
49
|
+
def config
|
50
|
+
yield self
|
51
|
+
end
|
52
|
+
|
53
|
+
def register_repl(*args, &block)
|
54
|
+
ReplRunner.register_commands(*args, &block)
|
55
|
+
end
|
56
|
+
|
57
|
+
def filter_sensitive(sensitive)
|
58
|
+
raise "Expecting #{sensitive} to be a hash" unless sensitive.is_a?(Hash)
|
59
|
+
@sensitive ||= {}
|
60
|
+
@sensitive.merge!(sensitive)
|
61
|
+
end
|
62
|
+
|
63
|
+
def sanitize(doc)
|
64
|
+
return doc if @sensitive.nil?
|
65
|
+
@sensitive.each do |sensitive, replace|
|
66
|
+
doc.gsub!(sensitive.to_s, replace)
|
67
|
+
end
|
68
|
+
return doc
|
69
|
+
end
|
70
|
+
|
71
|
+
attr_accessor :project_root
|
72
|
+
end
|
73
|
+
|
74
|
+
require 'rundoc/parser'
|
75
|
+
require 'rundoc/code_section'
|
76
|
+
require 'rundoc/code_command'
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Rundoc
|
2
|
+
class CodeCommand
|
3
|
+
attr_accessor :hidden, :render_result, :command, :contents, :keyword
|
4
|
+
alias :hidden? :hidden
|
5
|
+
alias :render_result? :render_result
|
6
|
+
|
7
|
+
def initialize(arg)
|
8
|
+
end
|
9
|
+
|
10
|
+
def not_hidden?
|
11
|
+
!hidden?
|
12
|
+
end
|
13
|
+
|
14
|
+
def push(contents)
|
15
|
+
@contents ||= ""
|
16
|
+
@contents << contents
|
17
|
+
end
|
18
|
+
alias :<< :push
|
19
|
+
|
20
|
+
# executes command to build project
|
21
|
+
def call(env = {})
|
22
|
+
raise "not implemented"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'rundoc/code_command/bash'
|
28
|
+
require 'rundoc/code_command/pipe'
|
29
|
+
require 'rundoc/code_command/write'
|
30
|
+
require 'rundoc/code_command/repl'
|
31
|
+
require 'rundoc/code_command/rundoc_command'
|
32
|
+
require 'rundoc/code_command/no_such_command'
|
@@ -0,0 +1,57 @@
|
|
1
|
+
class Rundoc::CodeCommand::Bash < Rundoc::CodeCommand
|
2
|
+
|
3
|
+
# line = "cd ..""
|
4
|
+
# line = "pwd"
|
5
|
+
# line = "ls"
|
6
|
+
def initialize(line)
|
7
|
+
@line = line
|
8
|
+
@contents = ""
|
9
|
+
@delegate = case @line.split(' ').first.downcase
|
10
|
+
when 'cd'
|
11
|
+
Cd.new(@line)
|
12
|
+
else
|
13
|
+
false
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_md(env = {})
|
18
|
+
return @delegate.to_md(env) if @delegate
|
19
|
+
|
20
|
+
"$ #{@line}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def call(env = {})
|
24
|
+
return @delegate.call(env) if @delegate
|
25
|
+
|
26
|
+
shell(@line, @contents)
|
27
|
+
end
|
28
|
+
|
29
|
+
# markdown doesn't understand bash color codes
|
30
|
+
def sanitize_escape_chars(input)
|
31
|
+
input.gsub(/\e\[(\d+)m/, '')
|
32
|
+
end
|
33
|
+
|
34
|
+
def shell(cmd, stdin = nil)
|
35
|
+
msg = "Running: $ '#{cmd}'"
|
36
|
+
msg << " with stdin: '#{stdin.inspect}'" if stdin && !stdin.empty?
|
37
|
+
puts msg
|
38
|
+
|
39
|
+
result = ""
|
40
|
+
IO.popen("#{cmd} 2>&1", "w+") do |io|
|
41
|
+
io << stdin if stdin
|
42
|
+
io.close_write
|
43
|
+
result = sanitize_escape_chars io.read
|
44
|
+
end
|
45
|
+
unless $?.success?
|
46
|
+
raise "Command `#{@line}` exited with non zero status: #{result}" unless keyword.include?("fail")
|
47
|
+
end
|
48
|
+
return result
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
Rundoc.register_code_command(:bash, Rundoc::CodeCommand::Bash)
|
54
|
+
Rundoc.register_code_command(:'$', Rundoc::CodeCommand::Bash)
|
55
|
+
Rundoc.register_code_command(:'fail.$', Rundoc::CodeCommand::Bash)
|
56
|
+
|
57
|
+
require 'rundoc/code_command/bash/cd'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Rundoc::CodeCommand::Bash
|
2
|
+
# special purpose class to persist cd behavior across the entire program
|
3
|
+
# we change the directory of the parent program (rundoc) rather than
|
4
|
+
# changing the directory of a spawned child (via exec, ``, system, etc.)
|
5
|
+
class Cd < Rundoc::CodeCommand::Bash
|
6
|
+
|
7
|
+
def initialize(line)
|
8
|
+
@line = line
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
line = @line.sub('cd', '').strip
|
13
|
+
puts "running $ cd #{line}"
|
14
|
+
Dir.chdir(line)
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
class Rundoc::CodeCommand::FileCommand
|
2
|
+
class Append < Rundoc::CodeCommand
|
3
|
+
|
4
|
+
def initialize(filename)
|
5
|
+
@filename, line = filename.split('#')
|
6
|
+
@line_number = Integer(line) if line
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_md(env)
|
10
|
+
raise "must call write in its own code section" unless env[:commands].empty?
|
11
|
+
before = env[:before]
|
12
|
+
if @line_number
|
13
|
+
env[:before] = "In file `#{@filename}`, on line #{@line_number} add:\n\n#{before}"
|
14
|
+
else
|
15
|
+
env[:before] = "At the end of `#{@filename}` add:\n\n#{before}"
|
16
|
+
end
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def last_char_of(string)
|
21
|
+
string[-1,1]
|
22
|
+
end
|
23
|
+
|
24
|
+
def ends_in_newline?(string)
|
25
|
+
last_char_of(string) == "\n"
|
26
|
+
end
|
27
|
+
|
28
|
+
def concat_with_newline(str1, str2)
|
29
|
+
result = ""
|
30
|
+
result << str1
|
31
|
+
result << "\n" unless ends_in_newline?(result)
|
32
|
+
result << str2
|
33
|
+
result << "\n" unless ends_in_newline?(result)
|
34
|
+
result
|
35
|
+
end
|
36
|
+
|
37
|
+
def insert_contents_into_at_line(doc)
|
38
|
+
lines = doc.lines
|
39
|
+
raise "Expected #{@filename} to have at least #{@line_number} but only has #{lines.count}" if lines.count < @line_number
|
40
|
+
result = []
|
41
|
+
lines.each_with_index do |line, index|
|
42
|
+
line_number = index.next
|
43
|
+
if line_number == @line_number
|
44
|
+
result << contents
|
45
|
+
result << "\n" unless ends_in_newline?(contents)
|
46
|
+
end
|
47
|
+
result << line
|
48
|
+
end
|
49
|
+
doc = result.flatten.join("")
|
50
|
+
end
|
51
|
+
|
52
|
+
def call(env = {})
|
53
|
+
dir = File.expand_path("../", @filename)
|
54
|
+
FileUtils.mkdir_p(dir)
|
55
|
+
|
56
|
+
doc = File.read(@filename)
|
57
|
+
if @line_number
|
58
|
+
puts "Writing to: '#{@filename}' line #{@line_number} with: #{contents.inspect}"
|
59
|
+
doc = insert_contents_into_at_line(doc)
|
60
|
+
else
|
61
|
+
puts "Appending to file: '#{@filename}' with: #{contents.inspect}"
|
62
|
+
doc = concat_with_newline(doc, contents)
|
63
|
+
end
|
64
|
+
|
65
|
+
File.open(@filename, "w") do |f|
|
66
|
+
f.write(doc)
|
67
|
+
end
|
68
|
+
contents
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
Rundoc.register_code_command(:'file.append', Rundoc::CodeCommand::FileCommand::Append)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class Rundoc::CodeCommand::FileCommand
|
2
|
+
class Remove < Rundoc::CodeCommand
|
3
|
+
|
4
|
+
def initialize(filename)
|
5
|
+
@filename = filename
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_md(env)
|
9
|
+
raise "must call write in its own code section" unless env[:commands].empty?
|
10
|
+
before = env[:before]
|
11
|
+
env[:before] = "In file `#{@filename}` remove:\n\n#{before}"
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env = {})
|
16
|
+
puts "Deleting '#{contents.strip}' from #{@filename}"
|
17
|
+
raise "#{@filename} does not exist" unless File.exist?(@filename)
|
18
|
+
|
19
|
+
regex = /^\s*#{Regexp.quote(contents)}/
|
20
|
+
doc = File.read(@filename)
|
21
|
+
doc.sub!(regex, '')
|
22
|
+
|
23
|
+
File.open(@filename, "w") do |f|
|
24
|
+
f.write(doc)
|
25
|
+
end
|
26
|
+
contents
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
Rundoc.register_code_command(:'file.remove', Rundoc::CodeCommand::FileCommand::Remove)
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Rundoc
|
2
|
+
class CodeCommand
|
3
|
+
class Pipe < Rundoc::CodeCommand
|
4
|
+
|
5
|
+
# ::: ls
|
6
|
+
# ::: | tail -n 2
|
7
|
+
# => "test\ntmp.file\n"
|
8
|
+
def initialize(line)
|
9
|
+
line_array = line.split(" ")
|
10
|
+
@first = line_array.shift.strip
|
11
|
+
@delegate = Rundoc.code_command_from_keyword(@first, line_array.join(" "))
|
12
|
+
@delegate = Rundoc::CodeCommand::Bash.new(line) if @delegate.kind_of?(Rundoc::CodeCommand::NoSuchCommand)
|
13
|
+
end
|
14
|
+
|
15
|
+
# before: "",
|
16
|
+
# after: "",
|
17
|
+
# commands:
|
18
|
+
# [[cmd, output], [cmd, output]]
|
19
|
+
def call(env = {})
|
20
|
+
last_command = env[:commands].last
|
21
|
+
puts "Piping: results of '#{last_command[:command]}' to '#{@delegate}'"
|
22
|
+
|
23
|
+
@delegate.push(last_command[:output])
|
24
|
+
@delegate.call(env)
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_md(env = {})
|
28
|
+
""
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
Rundoc.register_code_command(:pipe, Rundoc::CodeCommand::Pipe)
|
36
|
+
Rundoc.register_code_command(:|, Rundoc::CodeCommand::Pipe)
|
37
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'repl_runner'
|
2
|
+
|
3
|
+
module Rundoc
|
4
|
+
class CodeCommand
|
5
|
+
class Repl < Rundoc::CodeCommand
|
6
|
+
def initialize(command)
|
7
|
+
@command = command
|
8
|
+
@contents = ""
|
9
|
+
end
|
10
|
+
|
11
|
+
def keyword=(keyword)
|
12
|
+
@keyword = keyword
|
13
|
+
if keyword.to_s == "repl"
|
14
|
+
command_array = @command.split(" ")
|
15
|
+
@keyword = command_array.first
|
16
|
+
else
|
17
|
+
@command = "#{keyword} #{@command}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def call(env = {})
|
22
|
+
puts "Running '#{@command}'' with repl: #{keyword}"
|
23
|
+
repl = ReplRunner.new(:"#{keyword}", @command)
|
24
|
+
@result = repl.zip(contents.strip).flatten.join("\n")
|
25
|
+
return @result
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_md(env = {})
|
29
|
+
return "$ #{@command}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
Rundoc.register_code_command(:repl, Rundoc::CodeCommand::Repl)
|
37
|
+
Rundoc.register_code_command(:irb, Rundoc::CodeCommand::Repl)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ::Rundoc
|
2
|
+
class CodeCommand
|
3
|
+
class ::RundocCommand < ::Rundoc::CodeCommand
|
4
|
+
|
5
|
+
def initialize(line)
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_md(env = {})
|
9
|
+
""
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env = {})
|
13
|
+
puts "Running: #{contents}"
|
14
|
+
eval(contents)
|
15
|
+
""
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
Rundoc.register_code_command(:rundoc, ::Rundoc::CodeCommand::RundocCommand)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Rundoc
|
2
|
+
class CodeCommand
|
3
|
+
class Write < Rundoc::CodeCommand
|
4
|
+
def initialize(filename)
|
5
|
+
@filename = filename
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_md(env)
|
9
|
+
raise "must call write in its own code section" unless env[:commands].empty?
|
10
|
+
before = env[:before]
|
11
|
+
env[:before] = "In file `#{@filename}` write:\n\n#{before}"
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env = {})
|
16
|
+
puts "Writing to: '#{@filename}'"
|
17
|
+
|
18
|
+
dir = File.expand_path("../", @filename)
|
19
|
+
FileUtils.mkdir_p(dir)
|
20
|
+
File.open(@filename, "w") do |f|
|
21
|
+
f.write(contents)
|
22
|
+
end
|
23
|
+
contents
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
Rundoc.register_code_command(:write, Rundoc::CodeCommand::Write)
|
31
|
+
Rundoc.register_code_command(:'file.write', Rundoc::CodeCommand::Write)
|
32
|
+
|
33
|
+
require 'rundoc/code_command/file_command/append'
|
34
|
+
require 'rundoc/code_command/file_command/remove'
|
@@ -0,0 +1,145 @@
|
|
1
|
+
module Rundoc
|
2
|
+
# holds code, parses and creates CodeCommand
|
3
|
+
class CodeSection
|
4
|
+
class ParseError < StandardError
|
5
|
+
def initialize(options = {})
|
6
|
+
keyword = options[:keyword]
|
7
|
+
command = options[:command]
|
8
|
+
line_number = options[:line_number]
|
9
|
+
block = options[:block].lines.map do |line|
|
10
|
+
if line == command
|
11
|
+
" > #{line}"
|
12
|
+
else
|
13
|
+
" #{line}"
|
14
|
+
end
|
15
|
+
end.join("")
|
16
|
+
|
17
|
+
msg = "Error parsing (line:#{line_number}):\n"
|
18
|
+
msg << "> '#{command.strip}'\n"
|
19
|
+
msg << "No such registered command: '#{keyword}'\n"
|
20
|
+
msg << "registered commands: #{Rundoc.known_commands.inspect}\n\n"
|
21
|
+
msg << block
|
22
|
+
msg << "\n"
|
23
|
+
super msg
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
COMMAND_REGEX = Rundoc::Parser::COMMAND_REGEX # todo: move whole thing
|
28
|
+
attr_accessor :original, :fence, :lang, :code, :commands, :keyword
|
29
|
+
|
30
|
+
def initialize(match, options = {})
|
31
|
+
@original = match.to_s
|
32
|
+
@commands = []
|
33
|
+
@stack = []
|
34
|
+
@keyword = options[:keyword] or raise "keyword is required"
|
35
|
+
@fence = match[:fence]
|
36
|
+
@lang = match[:lang]
|
37
|
+
@code = match[:contents]
|
38
|
+
parse_code_command
|
39
|
+
end
|
40
|
+
|
41
|
+
def render
|
42
|
+
result = []
|
43
|
+
env = {}
|
44
|
+
env[:commands] = []
|
45
|
+
env[:before] = "#{fence}#{lang}"
|
46
|
+
env[:after] = "#{fence}"
|
47
|
+
|
48
|
+
@stack.each do |s|
|
49
|
+
unless s.respond_to?(:call)
|
50
|
+
result << s
|
51
|
+
next
|
52
|
+
end
|
53
|
+
|
54
|
+
code_command = s
|
55
|
+
code_output = code_command.call(env) || ""
|
56
|
+
code_line = code_command.to_md(env) || ""
|
57
|
+
|
58
|
+
env[:commands] << { object: code_command, output: code_output, command: code_line}
|
59
|
+
|
60
|
+
if code_command.render_result?
|
61
|
+
result << [code_line, code_output]
|
62
|
+
else
|
63
|
+
result << code_line unless code_command.hidden?
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
return "" if hidden?
|
68
|
+
|
69
|
+
array = [env[:before], result, env[:after]]
|
70
|
+
return array.flatten.compact.map(&:rstrip).reject(&:empty?).join("\n") << "\n"
|
71
|
+
end
|
72
|
+
|
73
|
+
# all of the commands are hidden
|
74
|
+
def hidden?
|
75
|
+
!not_hidden?
|
76
|
+
end
|
77
|
+
|
78
|
+
# one or more of the commands are not hidden
|
79
|
+
def not_hidden?
|
80
|
+
return true if commands.empty?
|
81
|
+
commands.map(&:not_hidden?).detect {|c| c }
|
82
|
+
end
|
83
|
+
|
84
|
+
def command_regex
|
85
|
+
COMMAND_REGEX.call(keyword)
|
86
|
+
end
|
87
|
+
|
88
|
+
def add_code(match, line)
|
89
|
+
add_match_to_code_command(match, commands)
|
90
|
+
check_parse_error(line, code)
|
91
|
+
end
|
92
|
+
|
93
|
+
def add_contents(line)
|
94
|
+
if commands.empty?
|
95
|
+
@stack << line
|
96
|
+
else
|
97
|
+
commands.last << line
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def parse_code_command
|
102
|
+
code.lines.each do |line|
|
103
|
+
if match = line.match(command_regex)
|
104
|
+
add_code(match, line)
|
105
|
+
else
|
106
|
+
add_contents(line)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def add_match_to_code_command(match, commands)
|
112
|
+
command = match[:command]
|
113
|
+
tag = match[:tag]
|
114
|
+
statement = match[:statement]
|
115
|
+
|
116
|
+
code_command = Rundoc.code_command_from_keyword(command, statement)
|
117
|
+
|
118
|
+
case tag
|
119
|
+
when /\-/
|
120
|
+
code_command.hidden = true
|
121
|
+
when /\=/
|
122
|
+
code_command.render_result = true
|
123
|
+
when /\s/
|
124
|
+
# default do nothing
|
125
|
+
end
|
126
|
+
|
127
|
+
@stack << "\n" if commands.last.is_a?(Rundoc::CodeCommand)
|
128
|
+
@stack << code_command
|
129
|
+
commands << code_command
|
130
|
+
code_command
|
131
|
+
end
|
132
|
+
|
133
|
+
def check_parse_error(command, code_block)
|
134
|
+
return unless code_command = @stack.last
|
135
|
+
return unless code_command.is_a?(Rundoc::CodeCommand::NoSuchCommand)
|
136
|
+
@original.lines.each_with_index do |line, index|
|
137
|
+
next unless line == command
|
138
|
+
raise ParseError.new(keyword: code_command.keyword,
|
139
|
+
block: code_block,
|
140
|
+
command: command,
|
141
|
+
line_number: index.next)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|