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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/check_changelog.yml +16 -7
  3. data/.github/workflows/ci.yml +48 -0
  4. data/.standard.yml +6 -0
  5. data/CHANGELOG.md +12 -0
  6. data/Gemfile +1 -1
  7. data/README.md +98 -5
  8. data/Rakefile +9 -10
  9. data/lib/rundoc/cli.rb +15 -17
  10. data/lib/rundoc/code_command/background/log/clear.rb +1 -1
  11. data/lib/rundoc/code_command/background/log/read.rb +1 -1
  12. data/lib/rundoc/code_command/background/process_spawn.rb +8 -9
  13. data/lib/rundoc/code_command/background/start.rb +7 -7
  14. data/lib/rundoc/code_command/background/stop.rb +1 -1
  15. data/lib/rundoc/code_command/background/wait.rb +2 -2
  16. data/lib/rundoc/code_command/background.rb +6 -6
  17. data/lib/rundoc/code_command/bash/cd.rb +6 -7
  18. data/lib/rundoc/code_command/bash.rb +12 -13
  19. data/lib/rundoc/code_command/file_command/append.rb +12 -16
  20. data/lib/rundoc/code_command/file_command/remove.rb +6 -9
  21. data/lib/rundoc/code_command/no_such_command.rb +0 -1
  22. data/lib/rundoc/code_command/pipe.rb +2 -5
  23. data/lib/rundoc/code_command/print/erb.rb +48 -0
  24. data/lib/rundoc/code_command/print/text.rb +33 -0
  25. data/lib/rundoc/code_command/raw.rb +1 -1
  26. data/lib/rundoc/code_command/rundoc/depend_on.rb +0 -1
  27. data/lib/rundoc/code_command/rundoc/require.rb +2 -3
  28. data/lib/rundoc/code_command/rundoc_command.rb +3 -4
  29. data/lib/rundoc/code_command/website/driver.rb +17 -17
  30. data/lib/rundoc/code_command/website/navigate.rb +2 -2
  31. data/lib/rundoc/code_command/website/screenshot.rb +1 -1
  32. data/lib/rundoc/code_command/website/visit.rb +4 -5
  33. data/lib/rundoc/code_command/website.rb +4 -4
  34. data/lib/rundoc/code_command/write.rb +10 -11
  35. data/lib/rundoc/code_command.rb +28 -17
  36. data/lib/rundoc/code_section.rb +42 -25
  37. data/lib/rundoc/parser.rb +17 -19
  38. data/lib/rundoc/peg_parser.rb +57 -59
  39. data/lib/rundoc/version.rb +1 -1
  40. data/lib/rundoc.rb +10 -14
  41. data/rundoc.gemspec +19 -21
  42. data/test/fixtures/rails_4/rundoc.md +100 -33
  43. data/test/fixtures/rails_5/rundoc.md +77 -14
  44. data/test/fixtures/rails_6/rundoc.md +231 -167
  45. data/test/fixtures/rails_7/rundoc.md +477 -0
  46. data/test/integration/print_test.rb +194 -0
  47. data/test/rundoc/code_commands/append_file_test.rb +5 -8
  48. data/test/rundoc/code_commands/background_test.rb +3 -6
  49. data/test/rundoc/code_commands/bash_test.rb +12 -7
  50. data/test/rundoc/code_commands/pipe_test.rb +9 -9
  51. data/test/rundoc/code_commands/print_test.rb +94 -0
  52. data/test/rundoc/code_commands/remove_contents_test.rb +4 -5
  53. data/test/rundoc/code_section_test.rb +50 -56
  54. data/test/rundoc/parser_test.rb +28 -61
  55. data/test/rundoc/peg_parser_test.rb +49 -53
  56. data/test/rundoc/regex_test.rb +120 -127
  57. data/test/rundoc/test_parse_java.rb +1 -3
  58. data/test/test_helper.rb +4 -6
  59. metadata +39 -42
  60. data/.travis.yml +0 -8
  61. 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
- @line_number = Integer(line)
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
- before = env[:before]
19
- if @line_number
20
- env[:before] = "In file `#{filename}`, on line #{@line_number} add:\n\n#{before}"
16
+
17
+ env[:before] << if @line_number
18
+ "In file `#{filename}`, on line #{@line_number} add:"
21
19
  else
22
- env[:before] = "At the end of `#{filename}` add:\n\n#{before}"
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
- doc = result.flatten.join("")
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.open(filename, "w") do |f|
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
- before = env[:before]
12
- env[:before] = "In file `#{filename}` remove:\n\n#{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 = File.read(filename)
22
- doc.sub!(regex, '')
21
+ doc = File.read(filename)
22
+ doc.sub!(regex, "")
23
23
 
24
- File.open(filename, "w") do |f|
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 NoSuchCommand < Rundoc::CodeCommand
4
-
5
4
  def call(env = {})
6
5
  raise "No such command registered with rundoc: #{@keyword.inspect} for '#{@keyword} #{@original_args}'"
7
6
  end
@@ -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
- return actual
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(:|, Rundoc::CodeCommand::Pipe)
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)
@@ -15,4 +15,4 @@ module Rundoc
15
15
  end
16
16
  end
17
17
  end
18
- end
18
+ end
@@ -1,7 +1,6 @@
1
1
  class ::Rundoc::CodeCommand
2
2
  class RundocCommand
3
3
  class DependOn < ::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 (but not to )
7
6
  def initialize(path)
@@ -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] ||= String.new
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
- return ""
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 'rundoc/code_command/rundoc/depend_on'
26
- require 'rundoc/code_command/rundoc/require'
24
+ require "rundoc/code_command/rundoc/depend_on"
25
+ require "rundoc/code_command/rundoc/require"
@@ -1,4 +1,4 @@
1
- require 'capybara'
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: , url: , width: 1024, height: 720, visible: false)
9
+ def initialize(name:, url:, width: 1024, height: 720, visible: false)
10
10
  browser_options = ::Selenium::WebDriver::Chrome::Options.new
11
- browser_options.args << '--headless' unless visible
12
- browser_options.args << '--disable-gpu' if Gem.win_platform?
13
- browser_options.args << '--hide-scrollbars'
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}".to_sym
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
- def self.tasks
48
- @tasks
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 = String.new
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 's3', 'aws'
72
+ when "s3", "aws"
73
73
  puts "Uploading screenshot to S3"
74
- require 'aws-sdk-s3'
75
- ENV.fetch('AWS_ACCESS_KEY_ID')
76
- s3 = Aws::S3::Resource.new(region: ENV.fetch('AWS_REGION'))
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('AWS_BUCKET_NAME')).object(key)
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: 'public-read' ,
84
- bucket: ENV.fetch('AWS_BUCKET_NAME'),
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
- return "screenshot_#{@count}.png"
108
+ "screenshot_#{@count}.png"
109
109
  end
110
110
  end
111
111
  end
@@ -1,7 +1,7 @@
1
1
  class Rundoc::CodeCommand::Website
2
2
  class Navigate < Rundoc::CodeCommand
3
- def initialize(name: )
4
- @name = name
3
+ def initialize(name:)
4
+ @name = name
5
5
  @driver = Rundoc::CodeCommand::Website::Driver.find(name)
6
6
  end
7
7
 
@@ -1,6 +1,6 @@
1
1
  class Rundoc::CodeCommand::Website
2
2
  class Screenshot < Rundoc::CodeCommand
3
- def initialize(name: , upload: false)
3
+ def initialize(name:, upload: false)
4
4
  @driver = Rundoc::CodeCommand::Website::Driver.find(name)
5
5
  @upload = upload
6
6
  end
@@ -1,8 +1,8 @@
1
1
  class Rundoc::CodeCommand::Website
2
2
  class Visit < Rundoc::CodeCommand
3
- def initialize(name: , url: nil, scroll: nil, height: 720, width: 1024, visible: false)
3
+ def initialize(name:, url: nil, scroll: nil, height: 720, width: 1024, visible: false)
4
4
  @name = name
5
- @url = 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 = String.new("Visting: #{@url}")
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
- return ""
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 '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'
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
- raise "must call write in its own code section" unless env[:commands].empty?
27
- before = env[:before]
28
- env[:before] = "In file `#{filename}` write:\n\n#{before}"
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.open(filename, "w") do |f|
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
- Rundoc.register_code_command(:write, Rundoc::CodeCommand::Write)
46
- Rundoc.register_code_command(:'file.write', Rundoc::CodeCommand::Write)
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"
@@ -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
- :command, :contents, :keyword,
7
- :original_args
17
+ :command, :contents, :keyword,
18
+ :original_args
8
19
 
9
- alias :render_result? :render_result
10
- alias :render_command? :render_command
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
- alias :<< :push
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 #{self.inspect}"
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 #{self.inspect}"
48
+ raise "not implemented on #{inspect}"
38
49
  end
39
50
  end
40
51
  end
41
52
 
42
-
43
- require 'rundoc/code_command/bash'
44
- require 'rundoc/code_command/pipe'
45
- require 'rundoc/code_command/write'
46
- require 'rundoc/code_command/repl'
47
- require 'rundoc/code_command/rundoc_command'
48
- require 'rundoc/code_command/no_such_command'
49
- require 'rundoc/code_command/raw'
50
- require 'rundoc/code_command/background'
51
- require 'rundoc/code_command/website'
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"