rundoc 1.1.3 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
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 +10 -12
  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 +92 -30
  43. data/test/fixtures/rails_5/rundoc.md +69 -10
  44. data/test/fixtures/rails_6/rundoc.md +226 -165
  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 +7 -9
  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 +141 -126
  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"