rundoc 1.1.2 → 2.0.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/.github/workflows/check_changelog.yml +16 -7
- data/.github/workflows/ci.yml +48 -0
- data/.standard.yml +6 -0
- data/CHANGELOG.md +12 -0
- data/Gemfile +1 -1
- data/README.md +98 -5
- data/Rakefile +9 -10
- data/lib/rundoc/cli.rb +15 -17
- data/lib/rundoc/code_command/background/log/clear.rb +1 -1
- data/lib/rundoc/code_command/background/log/read.rb +1 -1
- data/lib/rundoc/code_command/background/process_spawn.rb +8 -9
- data/lib/rundoc/code_command/background/start.rb +7 -7
- data/lib/rundoc/code_command/background/stop.rb +1 -1
- data/lib/rundoc/code_command/background/wait.rb +2 -2
- data/lib/rundoc/code_command/background.rb +6 -6
- data/lib/rundoc/code_command/bash/cd.rb +6 -7
- data/lib/rundoc/code_command/bash.rb +12 -13
- data/lib/rundoc/code_command/file_command/append.rb +12 -16
- data/lib/rundoc/code_command/file_command/remove.rb +6 -9
- data/lib/rundoc/code_command/no_such_command.rb +0 -1
- data/lib/rundoc/code_command/pipe.rb +2 -5
- data/lib/rundoc/code_command/print/erb.rb +48 -0
- data/lib/rundoc/code_command/print/text.rb +33 -0
- data/lib/rundoc/code_command/raw.rb +1 -1
- data/lib/rundoc/code_command/rundoc/depend_on.rb +0 -1
- data/lib/rundoc/code_command/rundoc/require.rb +2 -3
- data/lib/rundoc/code_command/rundoc_command.rb +3 -4
- data/lib/rundoc/code_command/website/driver.rb +17 -17
- data/lib/rundoc/code_command/website/navigate.rb +2 -2
- data/lib/rundoc/code_command/website/screenshot.rb +1 -1
- data/lib/rundoc/code_command/website/visit.rb +4 -5
- data/lib/rundoc/code_command/website.rb +4 -4
- data/lib/rundoc/code_command/write.rb +10 -11
- data/lib/rundoc/code_command.rb +28 -17
- data/lib/rundoc/code_section.rb +42 -25
- data/lib/rundoc/parser.rb +17 -19
- data/lib/rundoc/peg_parser.rb +57 -59
- data/lib/rundoc/version.rb +1 -1
- data/lib/rundoc.rb +10 -14
- data/rundoc.gemspec +19 -21
- data/test/fixtures/rails_4/rundoc.md +100 -33
- data/test/fixtures/rails_5/rundoc.md +77 -14
- data/test/fixtures/rails_6/rundoc.md +231 -167
- data/test/fixtures/rails_7/rundoc.md +477 -0
- data/test/integration/print_test.rb +194 -0
- data/test/rundoc/code_commands/append_file_test.rb +5 -8
- data/test/rundoc/code_commands/background_test.rb +3 -6
- data/test/rundoc/code_commands/bash_test.rb +12 -7
- data/test/rundoc/code_commands/pipe_test.rb +9 -9
- data/test/rundoc/code_commands/print_test.rb +94 -0
- data/test/rundoc/code_commands/remove_contents_test.rb +4 -5
- data/test/rundoc/code_section_test.rb +50 -56
- data/test/rundoc/parser_test.rb +28 -61
- data/test/rundoc/peg_parser_test.rb +49 -53
- data/test/rundoc/regex_test.rb +120 -127
- data/test/rundoc/test_parse_java.rb +1 -3
- data/test/test_helper.rb +4 -6
- metadata +39 -42
- data/.travis.yml +0 -8
- data/lib/rundoc/code_command/repl.rb +0 -37
@@ -3,11 +3,9 @@ class Rundoc::CodeCommand::FileCommand
|
|
3
3
|
include FileUtil
|
4
4
|
|
5
5
|
def initialize(filename)
|
6
|
-
@filename, line = filename.split(
|
7
|
-
if line
|
8
|
-
|
9
|
-
else
|
10
|
-
@line_number = nil
|
6
|
+
@filename, line = filename.split("#")
|
7
|
+
@line_number = if line
|
8
|
+
Integer(line)
|
11
9
|
end
|
12
10
|
end
|
13
11
|
|
@@ -15,17 +13,18 @@ class Rundoc::CodeCommand::FileCommand
|
|
15
13
|
return unless render_command?
|
16
14
|
|
17
15
|
raise "must call write in its own code section" unless env[:commands].empty?
|
18
|
-
|
19
|
-
if @line_number
|
20
|
-
|
16
|
+
|
17
|
+
env[:before] << if @line_number
|
18
|
+
"In file `#{filename}`, on line #{@line_number} add:"
|
21
19
|
else
|
22
|
-
|
20
|
+
"At the end of `#{filename}` add:"
|
23
21
|
end
|
22
|
+
env[:before] << NEWLINE
|
24
23
|
nil
|
25
24
|
end
|
26
25
|
|
27
26
|
def last_char_of(string)
|
28
|
-
string[-1,1]
|
27
|
+
string[-1, 1]
|
29
28
|
end
|
30
29
|
|
31
30
|
def ends_in_newline?(string)
|
@@ -53,7 +52,7 @@ class Rundoc::CodeCommand::FileCommand
|
|
53
52
|
end
|
54
53
|
result << line
|
55
54
|
end
|
56
|
-
|
55
|
+
result.flatten.join("")
|
57
56
|
end
|
58
57
|
|
59
58
|
def call(env = {})
|
@@ -67,13 +66,10 @@ class Rundoc::CodeCommand::FileCommand
|
|
67
66
|
doc = concat_with_newline(doc, contents)
|
68
67
|
end
|
69
68
|
|
70
|
-
File.
|
71
|
-
f.write(doc)
|
72
|
-
end
|
69
|
+
File.write(filename, doc)
|
73
70
|
contents
|
74
71
|
end
|
75
72
|
end
|
76
73
|
end
|
77
74
|
|
78
|
-
|
79
|
-
Rundoc.register_code_command(:'file.append', Rundoc::CodeCommand::FileCommand::Append)
|
75
|
+
Rundoc.register_code_command(:"file.append", Rundoc::CodeCommand::FileCommand::Append)
|
@@ -8,8 +8,8 @@ class Rundoc::CodeCommand::FileCommand
|
|
8
8
|
|
9
9
|
def to_md(env)
|
10
10
|
raise "must call write in its own code section" unless env[:commands].empty?
|
11
|
-
|
12
|
-
env[:before]
|
11
|
+
env[:before] << "In file `#{filename}` remove:"
|
12
|
+
env[:before] << NEWLINE
|
13
13
|
nil
|
14
14
|
end
|
15
15
|
|
@@ -18,16 +18,13 @@ class Rundoc::CodeCommand::FileCommand
|
|
18
18
|
raise "#{filename} does not exist" unless File.exist?(filename)
|
19
19
|
|
20
20
|
regex = /^\s*#{Regexp.quote(contents)}/
|
21
|
-
doc
|
22
|
-
doc.sub!(regex,
|
21
|
+
doc = File.read(filename)
|
22
|
+
doc.sub!(regex, "")
|
23
23
|
|
24
|
-
File.
|
25
|
-
f.write(doc)
|
26
|
-
end
|
24
|
+
File.write(filename, doc)
|
27
25
|
contents
|
28
26
|
end
|
29
27
|
end
|
30
28
|
end
|
31
29
|
|
32
|
-
|
33
|
-
Rundoc.register_code_command(:'file.remove', Rundoc::CodeCommand::FileCommand::Remove)
|
30
|
+
Rundoc.register_code_command(:"file.remove", Rundoc::CodeCommand::FileCommand::Remove)
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module Rundoc
|
2
2
|
class CodeCommand
|
3
3
|
class Pipe < Rundoc::CodeCommand
|
4
|
-
|
5
4
|
# ::: ls
|
6
5
|
# ::: | tail -n 2
|
7
6
|
# => "test\ntmp.file\n"
|
@@ -33,7 +32,7 @@ module Rundoc
|
|
33
32
|
actual = actual.first if actual.is_a?(Array)
|
34
33
|
|
35
34
|
actual = Rundoc::CodeCommand::Bash.new(code) if actual.is_a?(Rundoc::CodeCommand::NoSuchCommand)
|
36
|
-
|
35
|
+
actual
|
37
36
|
|
38
37
|
# Since `| tail -n 2` does not start with a `$` assume any "naked" commands
|
39
38
|
# are bash
|
@@ -44,7 +43,5 @@ module Rundoc
|
|
44
43
|
end
|
45
44
|
end
|
46
45
|
|
47
|
-
|
48
46
|
Rundoc.register_code_command(:pipe, Rundoc::CodeCommand::Pipe)
|
49
|
-
Rundoc.register_code_command(:|,
|
50
|
-
|
47
|
+
Rundoc.register_code_command(:|, Rundoc::CodeCommand::Pipe)
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require "erb"
|
2
|
+
|
3
|
+
class EmptyBinding
|
4
|
+
def self.create
|
5
|
+
new.empty_binding
|
6
|
+
end
|
7
|
+
|
8
|
+
def empty_binding
|
9
|
+
binding
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
RUNDOC_ERB_BINDINGS = Hash.new { |h, k| h[k] = EmptyBinding.create }
|
14
|
+
|
15
|
+
class Rundoc::CodeCommand
|
16
|
+
class PrintERB < Rundoc::CodeCommand
|
17
|
+
def initialize(line = nil, binding: "default")
|
18
|
+
@line = line
|
19
|
+
@binding = RUNDOC_ERB_BINDINGS[binding]
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_md(env)
|
23
|
+
if render_before?
|
24
|
+
env[:before] << render
|
25
|
+
end
|
26
|
+
|
27
|
+
""
|
28
|
+
end
|
29
|
+
|
30
|
+
def render
|
31
|
+
@render ||= ERB.new([@line, contents].compact.join("\n")).result(@binding)
|
32
|
+
end
|
33
|
+
|
34
|
+
def call(erb = {})
|
35
|
+
if render_before?
|
36
|
+
""
|
37
|
+
else
|
38
|
+
render
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def render_before?
|
43
|
+
!render_command? && render_result?
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
Rundoc.register_code_command(:"print.erb", Rundoc::CodeCommand::PrintERB)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Rundoc::CodeCommand
|
2
|
+
class PrintText < Rundoc::CodeCommand
|
3
|
+
def initialize(line)
|
4
|
+
@line = line
|
5
|
+
end
|
6
|
+
|
7
|
+
def to_md(env)
|
8
|
+
if render_before?
|
9
|
+
env[:before] << [@line, contents].compact.join("\n")
|
10
|
+
end
|
11
|
+
|
12
|
+
""
|
13
|
+
end
|
14
|
+
|
15
|
+
def hidden?
|
16
|
+
!render_result?
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(env = {})
|
20
|
+
if render_before?
|
21
|
+
""
|
22
|
+
else
|
23
|
+
[@line, contents].compact.join("\n")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def render_before?
|
28
|
+
!render_command? && render_result?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Rundoc.register_code_command(:"print.text", Rundoc::CodeCommand::PrintText)
|
@@ -1,7 +1,6 @@
|
|
1
1
|
class ::Rundoc::CodeCommand
|
2
2
|
class RundocCommand
|
3
3
|
class Require < ::Rundoc::CodeCommand
|
4
|
-
|
5
4
|
# Pass in the relative path of another rundoc document in order to
|
6
5
|
# run all of it's commands. Resulting contents will be displayed
|
7
6
|
# in current document
|
@@ -15,7 +14,7 @@ class ::Rundoc::CodeCommand
|
|
15
14
|
end
|
16
15
|
|
17
16
|
def call(env = {})
|
18
|
-
env[:replace] ||=
|
17
|
+
env[:replace] ||= +""
|
19
18
|
current_path = Pathname.new(env[:document_path]).dirname
|
20
19
|
document_path = @path.expand_path(current_path)
|
21
20
|
|
@@ -24,7 +23,7 @@ class ::Rundoc::CodeCommand
|
|
24
23
|
puts "rundoc.require: Done executing #{@path.to_s.inspect}, putting contents into document"
|
25
24
|
|
26
25
|
env[:replace] << output
|
27
|
-
|
26
|
+
""
|
28
27
|
end
|
29
28
|
|
30
29
|
def hidden?
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module ::Rundoc
|
2
2
|
class CodeCommand
|
3
3
|
class ::RundocCommand < ::Rundoc::CodeCommand
|
4
|
-
|
5
4
|
def initialize(contents = "")
|
6
5
|
@contents = contents
|
7
6
|
end
|
@@ -12,7 +11,7 @@ module ::Rundoc
|
|
12
11
|
|
13
12
|
def call(env = {})
|
14
13
|
puts "Running: #{contents}"
|
15
|
-
eval(contents)
|
14
|
+
eval(contents) # rubocop:disable Security/Eval
|
16
15
|
""
|
17
16
|
end
|
18
17
|
end
|
@@ -22,5 +21,5 @@ end
|
|
22
21
|
Rundoc.register_code_command(:rundoc, RundocCommand)
|
23
22
|
Rundoc.register_code_command(:"rundoc.configure", RundocCommand)
|
24
23
|
|
25
|
-
require
|
26
|
-
require
|
24
|
+
require "rundoc/code_command/rundoc/depend_on"
|
25
|
+
require "rundoc/code_command/rundoc/require"
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "capybara"
|
2
2
|
|
3
3
|
Capybara::Selenium::Driver.load_selenium
|
4
4
|
|
@@ -6,17 +6,17 @@ class Rundoc::CodeCommand::Website
|
|
6
6
|
class Driver
|
7
7
|
attr_reader :session
|
8
8
|
|
9
|
-
def initialize(name
|
9
|
+
def initialize(name:, url:, width: 1024, height: 720, visible: false)
|
10
10
|
browser_options = ::Selenium::WebDriver::Chrome::Options.new
|
11
|
-
browser_options.args <<
|
12
|
-
browser_options.args <<
|
13
|
-
browser_options.args <<
|
11
|
+
browser_options.args << "--headless" unless visible
|
12
|
+
browser_options.args << "--disable-gpu" if Gem.win_platform?
|
13
|
+
browser_options.args << "--hide-scrollbars"
|
14
14
|
# browser_options.args << "--window-size=#{width},#{height}"
|
15
15
|
@width = width
|
16
16
|
@height = height
|
17
17
|
|
18
18
|
@driver = Capybara::Selenium::Driver.new(nil, browser: :chrome, options: browser_options)
|
19
|
-
driver_name = "rundoc_driver_#{name}"
|
19
|
+
driver_name = :"rundoc_driver_#{name}"
|
20
20
|
Capybara.register_driver(driver_name) do |app|
|
21
21
|
@driver
|
22
22
|
end
|
@@ -44,14 +44,14 @@ class Rundoc::CodeCommand::Website
|
|
44
44
|
session.reset_session!
|
45
45
|
end
|
46
46
|
|
47
|
-
|
48
|
-
|
47
|
+
class << self
|
48
|
+
attr_reader :tasks
|
49
49
|
end
|
50
50
|
|
51
51
|
def safe_eval(code)
|
52
52
|
@driver.send(:eval, code)
|
53
53
|
rescue => e
|
54
|
-
msg =
|
54
|
+
msg = +""
|
55
55
|
msg << "Error running code #{code.inspect} at #{current_url.inspect}\n"
|
56
56
|
msg << "saving a screenshot to: `tmp/error.png`"
|
57
57
|
puts msg
|
@@ -69,19 +69,19 @@ class Rundoc::CodeCommand::Website
|
|
69
69
|
return file_path unless upload
|
70
70
|
|
71
71
|
case upload
|
72
|
-
when
|
72
|
+
when "s3", "aws"
|
73
73
|
puts "Uploading screenshot to S3"
|
74
|
-
require
|
75
|
-
ENV.fetch(
|
76
|
-
s3 = Aws::S3::Resource.new(region: ENV.fetch(
|
74
|
+
require "aws-sdk-s3"
|
75
|
+
ENV.fetch("AWS_ACCESS_KEY_ID")
|
76
|
+
s3 = Aws::S3::Resource.new(region: ENV.fetch("AWS_REGION"))
|
77
77
|
|
78
78
|
key = "#{timestamp}/#{file_name}"
|
79
|
-
obj = s3.bucket(ENV.fetch(
|
79
|
+
obj = s3.bucket(ENV.fetch("AWS_BUCKET_NAME")).object(key)
|
80
80
|
obj.upload_file(file_path)
|
81
81
|
|
82
82
|
obj.client.put_object_acl(
|
83
|
-
acl:
|
84
|
-
bucket: ENV.fetch(
|
83
|
+
acl: "public-read",
|
84
|
+
bucket: ENV.fetch("AWS_BUCKET_NAME"),
|
85
85
|
key: key
|
86
86
|
)
|
87
87
|
|
@@ -105,7 +105,7 @@ class Rundoc::CodeCommand::Website
|
|
105
105
|
def self.next_screenshot_name
|
106
106
|
@count ||= 0
|
107
107
|
@count += 1
|
108
|
-
|
108
|
+
"screenshot_#{@count}.png"
|
109
109
|
end
|
110
110
|
end
|
111
111
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
class Rundoc::CodeCommand::Website
|
2
2
|
class Visit < Rundoc::CodeCommand
|
3
|
-
def initialize(name
|
3
|
+
def initialize(name:, url: nil, scroll: nil, height: 720, width: 1024, visible: false)
|
4
4
|
@name = name
|
5
|
-
@url
|
5
|
+
@url = url
|
6
6
|
@scroll = scroll
|
7
7
|
@driver = Driver.new(
|
8
8
|
name: name,
|
@@ -19,7 +19,7 @@ class Rundoc::CodeCommand::Website
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def call(env = {})
|
22
|
-
message =
|
22
|
+
message = +"Visting: #{@url}"
|
23
23
|
message << "and executing:\n#{contents}" unless contents.nil? || contents.empty?
|
24
24
|
|
25
25
|
puts message
|
@@ -27,11 +27,10 @@ class Rundoc::CodeCommand::Website
|
|
27
27
|
@driver.visit(@url) if @url
|
28
28
|
@driver.scroll(@scroll) if @scroll
|
29
29
|
|
30
|
-
|
31
30
|
return "" if contents.nil? || contents.empty?
|
32
31
|
@driver.safe_eval(contents)
|
33
32
|
|
34
|
-
|
33
|
+
""
|
35
34
|
end
|
36
35
|
|
37
36
|
def hidden?
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class Rundoc::CodeCommand::Website
|
2
2
|
end
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
4
|
+
require "rundoc/code_command/website/driver"
|
5
|
+
require "rundoc/code_command/website/screenshot"
|
6
|
+
require "rundoc/code_command/website/visit"
|
7
|
+
require "rundoc/code_command/website/navigate"
|
@@ -23,27 +23,26 @@ module Rundoc
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def to_md(env)
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
if render_command?
|
27
|
+
raise "must call write in its own code section" unless env[:commands].empty?
|
28
|
+
env[:before] << "In file `#{filename}` write:"
|
29
|
+
env[:before] << NEWLINE
|
30
|
+
end
|
29
31
|
nil
|
30
32
|
end
|
31
33
|
|
32
34
|
def call(env = {})
|
33
35
|
puts "Writing to: '#{filename}'"
|
34
36
|
mkdir_p
|
35
|
-
File.
|
36
|
-
f.write(contents)
|
37
|
-
end
|
37
|
+
File.write(filename, contents)
|
38
38
|
contents
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
+
Rundoc.register_code_command(:write, Rundoc::CodeCommand::Write)
|
45
|
+
Rundoc.register_code_command(:"file.write", Rundoc::CodeCommand::Write)
|
44
46
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
require 'rundoc/code_command/file_command/append'
|
49
|
-
require 'rundoc/code_command/file_command/remove'
|
47
|
+
require "rundoc/code_command/file_command/append"
|
48
|
+
require "rundoc/code_command/file_command/remove"
|
data/lib/rundoc/code_command.rb
CHANGED
@@ -2,12 +2,23 @@ module Rundoc
|
|
2
2
|
# Generic CodeCommand class to be inherited
|
3
3
|
#
|
4
4
|
class CodeCommand
|
5
|
+
# Newlines are stripped and re-added, this tells the project that
|
6
|
+
# we're intentionally wanting an extra newline
|
7
|
+
NEWLINE = Object.new
|
8
|
+
def NEWLINE.to_s
|
9
|
+
""
|
10
|
+
end
|
11
|
+
|
12
|
+
def NEWLINE.empty?
|
13
|
+
false
|
14
|
+
end
|
15
|
+
|
5
16
|
attr_accessor :render_result, :render_command,
|
6
|
-
|
7
|
-
|
17
|
+
:command, :contents, :keyword,
|
18
|
+
:original_args
|
8
19
|
|
9
|
-
|
10
|
-
|
20
|
+
alias_method :render_result?, :render_result
|
21
|
+
alias_method :render_command?, :render_command
|
11
22
|
|
12
23
|
def initialize(*args)
|
13
24
|
end
|
@@ -24,28 +35,28 @@ module Rundoc
|
|
24
35
|
@contents ||= ""
|
25
36
|
@contents << contents
|
26
37
|
end
|
27
|
-
|
38
|
+
alias_method :<<, :push
|
28
39
|
|
29
40
|
# Executes command to build project
|
30
41
|
# Is expected to return the result of the command
|
31
42
|
def call(env = {})
|
32
|
-
raise "not implemented on #{
|
43
|
+
raise "not implemented on #{inspect}"
|
33
44
|
end
|
34
45
|
|
35
46
|
# the output of the command, i.e. `$ cat foo.txt`
|
36
47
|
def to_md(env = {})
|
37
|
-
raise "not implemented on #{
|
48
|
+
raise "not implemented on #{inspect}"
|
38
49
|
end
|
39
50
|
end
|
40
51
|
end
|
41
52
|
|
42
|
-
|
43
|
-
require
|
44
|
-
require
|
45
|
-
require
|
46
|
-
require
|
47
|
-
require
|
48
|
-
require
|
49
|
-
require
|
50
|
-
require
|
51
|
-
require
|
53
|
+
require "rundoc/code_command/bash"
|
54
|
+
require "rundoc/code_command/pipe"
|
55
|
+
require "rundoc/code_command/write"
|
56
|
+
require "rundoc/code_command/rundoc_command"
|
57
|
+
require "rundoc/code_command/no_such_command"
|
58
|
+
require "rundoc/code_command/raw"
|
59
|
+
require "rundoc/code_command/background"
|
60
|
+
require "rundoc/code_command/website"
|
61
|
+
require "rundoc/code_command/print/text"
|
62
|
+
require "rundoc/code_command/print/erb"
|