rundoc 4.1.4 → 5.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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +2 -1
  3. data/.standard.yml +1 -1
  4. data/CHANGELOG.md +7 -0
  5. data/README.md +36 -9
  6. data/lib/rundoc/cli.rb +4 -1
  7. data/lib/rundoc/code_command/background/log/clear.rb +12 -2
  8. data/lib/rundoc/code_command/background/log/read.rb +12 -2
  9. data/lib/rundoc/code_command/background/process_spawn.rb +3 -1
  10. data/lib/rundoc/code_command/background/start.rb +25 -6
  11. data/lib/rundoc/code_command/background/stdin_write.rb +21 -8
  12. data/lib/rundoc/code_command/background/stop.rb +12 -2
  13. data/lib/rundoc/code_command/background/wait.rb +15 -3
  14. data/lib/rundoc/code_command/background.rb +2 -0
  15. data/lib/rundoc/code_command/bash/cd.rb +7 -7
  16. data/lib/rundoc/code_command/bash.rb +43 -19
  17. data/lib/rundoc/code_command/comment.rb +33 -0
  18. data/lib/rundoc/code_command/deferred.rb +66 -0
  19. data/lib/rundoc/code_command/file_command/append.rb +29 -8
  20. data/lib/rundoc/code_command/file_command/remove.rb +27 -5
  21. data/lib/rundoc/code_command/no_such_command.rb +8 -3
  22. data/lib/rundoc/code_command/pipe.rb +36 -16
  23. data/lib/rundoc/code_command/pre/erb.rb +28 -18
  24. data/lib/rundoc/code_command/print/erb.rb +28 -4
  25. data/lib/rundoc/code_command/print/text.rb +27 -8
  26. data/lib/rundoc/code_command/raw.rb +17 -5
  27. data/lib/rundoc/code_command/rundoc/require.rb +25 -17
  28. data/lib/rundoc/code_command/rundoc_command.rb +21 -8
  29. data/lib/rundoc/code_command/website/driver.rb +2 -0
  30. data/lib/rundoc/code_command/website/navigate.rb +18 -12
  31. data/lib/rundoc/code_command/website/screenshot.rb +17 -11
  32. data/lib/rundoc/code_command/website/visit.rb +23 -12
  33. data/lib/rundoc/code_command/website.rb +2 -0
  34. data/lib/rundoc/code_command/write.rb +37 -9
  35. data/lib/rundoc/code_command.rb +5 -48
  36. data/lib/rundoc/context/after_build.rb +2 -0
  37. data/lib/rundoc/context/execution.rb +2 -0
  38. data/lib/rundoc/document.rb +6 -2
  39. data/lib/rundoc/fenced_code_block.rb +10 -7
  40. data/lib/rundoc/peg_parser.rb +17 -9
  41. data/lib/rundoc/version.rb +3 -1
  42. data/lib/rundoc.rb +52 -17
  43. data/rundoc.gemspec +2 -0
  44. data/test/rundoc/code_commands/append_file_test.rb +35 -10
  45. data/test/rundoc/code_commands/background_test.rb +24 -22
  46. data/test/rundoc/code_commands/bash_test.rb +10 -5
  47. data/test/rundoc/code_commands/comment_test.rb +116 -0
  48. data/test/rundoc/code_commands/pipe_test.rb +2 -2
  49. data/test/rundoc/code_commands/print_test.rb +13 -25
  50. data/test/rundoc/code_commands/remove_contents_test.rb +8 -3
  51. data/test/rundoc/code_section_test.rb +28 -21
  52. data/test/rundoc/peg_parser_test.rb +17 -1
  53. data/test/test_helper.rb +4 -2
  54. metadata +6 -6
  55. data/lib/rundoc/code_command/rundoc/depend_on.rb +0 -13
  56. data/test/fixtures/depend_on/dependency/rundoc.md +0 -5
  57. data/test/fixtures/depend_on/main/rundoc.md +0 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 83fd435266e63543e96c3e24fc4d116cd043f2c89e396b8839d283eace07248a
4
- data.tar.gz: 9818843a327f3ed3c4a46548db1dc8e9b2c706824716749d7a173563a752d6ae
3
+ metadata.gz: 85fbfa9f84b4e98eb72d487721e7f35001f7820404e30a138de4b4505d788f53
4
+ data.tar.gz: 1ff08ba1cdd468b190fc54eef124b7ab434d700ffe87ba2b4c8e676d03fb515e
5
5
  SHA512:
6
- metadata.gz: f5972a3213f3700659aa2d9ca602821f0cb443e9e56120b5e43485da6b0240a4b7b998dea1b0637b470ac098d0fab5c7ee7922b056eebfd08575c0177bc312d9
7
- data.tar.gz: c58f0fdf37e46817eb28871e1136811b0dd2c2a12925948e461f286b47de8c2b3bae1ba06345956908ac09c859ad0d1fe284d10a2c2a019516ba07a134103d07
6
+ metadata.gz: 8e87c610bcd8c8589407e68b503eee0578a1dc23b959baa138258185f7d08e6daa3ee17097e4b66b02fea896ee9e5be2bde936e2a601a2b18d1b1a2fc24b36a2
7
+ data.tar.gz: 9c9f4d7446beaedc74d61354794327cd30f372f7e5e16500678247f7bc549bb7b04992d0875c06c1fa06ae894a36c35902e07930cf55ab4e9fc01bb8b29c44d3
@@ -11,9 +11,9 @@ jobs:
11
11
  fail-fast: false
12
12
  matrix:
13
13
  ruby:
14
- - 3.1
15
14
  - 3.2
16
15
  - 3.3
16
+ - "4.0"
17
17
  - head
18
18
  steps:
19
19
  - name: Checkout code
@@ -34,6 +34,7 @@ jobs:
34
34
  matrix:
35
35
  ruby:
36
36
  - 3.3
37
+ - "4.0"
37
38
  - head
38
39
  steps:
39
40
  - name: Checkout code
data/.standard.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  fix: true # default: false
2
2
  parallel: true # default: false
3
3
  format: progress # default: Standard::Formatter
4
- ruby_version: 3.1 # default: RUBY_VERSION
4
+ ruby_version: 3.2 # default: RUBY_VERSION
5
5
  ignore: # default: []
6
6
  - 'test/fixtures/**/*'
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  ## HEAD
2
2
 
3
+ ## 5.0.0
4
+
5
+ - Added comment syntax. Use an octothorpe (`#`) after the visibility markers to comment out any commands and make them a no-op.
6
+ - Changed: Minimum Ruby version is now 3.2 (Ruby 3.1 reached EOL in March 2025).
7
+ - Changed: All code commands now use an Args + Runner class pattern. `register_code_command` now requires keyword arguments: `keyword:`, `args_klass:`, and `runner_klass:`.
8
+ - Fix: `seattle_method` parser rule no longer matches across newlines. Previously, a command with no same-line arguments (e.g. `:::>> rundoc`) would consume the next line as its argument, losing the newline between content lines. (https://github.com/zombocom/rundoc/pull/118)
9
+
3
10
  ## 4.1.4
4
11
 
5
12
  - Fix: Net::ReadTimeout errors on `website.visit` are now retried by default (https://github.com/zombocom/rundoc/pull/103)
data/README.md CHANGED
@@ -660,36 +660,63 @@ This command `filter_sensitive` can be called multiple times with different valu
660
660
 
661
661
  ## Writing a new command
662
662
 
663
+ > Note: This is an advanced topic and this interface is unstable.
664
+
663
665
  Rundoc does not have a stable internal command interface. You can define your own commands, but unless it is committed in this repo, it may break on a minor version change.
664
666
 
665
667
  To add a new command it needs to be parsed and called. Examples of commands being implemented are seen in `lib/rundoc/code_command`.
666
668
 
667
- A new command needs to be registered:
669
+ Each command is split into two classes: an **Args** class that handles argument parsing/validation and a **Runner** class that handles execution. Both must be registered:
668
670
 
671
+ ```ruby
672
+ Rundoc.register_code_command(
673
+ keyword: :lol,
674
+ args_klass: Rundoc::CodeCommand::LolArgs,
675
+ runner_klass: Rundoc::CodeCommand::LolRunner
676
+ )
669
677
  ```
670
- Rundoc.register_code_command(:lol, Rundoc::CodeCommand::Lol)
671
- ```
672
678
 
673
- They should inherit from Rundoc::CodeCommand:
679
+ The Args class is a plain Ruby class. Its initialize method receives input from the document and exposes parsed values via `attr_reader`:
680
+
681
+ ```ruby
682
+ class Rundoc::CodeCommand::LolArgs
683
+ attr_reader :message
674
684
 
685
+ def initialize(message)
686
+ @message = message
687
+ end
688
+ end
675
689
  ```
676
- class Rundoc::CodeCommand::Lol < Rundoc::CodeCommand
677
- def initialize(line)
690
+
691
+ The Runner class is namespaced under `Rundoc::CodeCommand` and receives the args instance via `user_args:`:
692
+
693
+ ```ruby
694
+ class Rundoc::CodeCommand::LolRunner
695
+ def initialize(user_args:, **)
696
+ @message = user_args.message
697
+ end
698
+
699
+ def to_md(env = {})
700
+ ""
701
+ end
702
+
703
+ def call(env = {})
704
+ @message
678
705
  end
679
706
  end
680
707
  ```
681
708
 
682
- The initialize method is called with input from the document. The command is rendered (`:::>-`) by the output of the `def call` method. The contents produced by the command (`:::->`) are rendered by the `def to_md` method.
709
+ The command is rendered (`:::>-`) by the output of the `def call` method. The contents produced by the command (`:::->`) are rendered by the `def to_md` method.
683
710
 
684
711
  The syntax for commands is ruby-ish but it is a custom grammar implemented in `lib/peg_parser.rb` for more info on manipulating the grammar see this tutorial on how I added keword-like/hash-like syntax https://github.com/schneems/implement_ruby_hash_syntax_with_parslet_example.
685
712
 
686
- Command initialize methods natively support:
713
+ Args class initialize methods natively support:
687
714
 
688
715
  - Barewords as a single string input
689
716
  - Keyword arguments
690
717
  - A combination of the two
691
718
 
692
- Anything that is passed to the command via "stdin" is available via a method `self.contents`. The interplay between the input and `self.contents` is not strongly defined.
719
+ Anything that is passed to the command via "stdin" is available on the Runner via a method `self.contents`. The interplay between the input and `self.contents` is not strongly defined.
693
720
 
694
721
  ## Copyright
695
722
 
data/lib/rundoc/cli.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rundoc
2
4
  class CLI
3
5
  module DEFAULTS
@@ -159,7 +161,8 @@ module Rundoc
159
161
  Dir.chdir(execution_context.output_dir) do
160
162
  parser = Rundoc::Document.new(
161
163
  source_contents,
162
- context: execution_context
164
+ context: execution_context,
165
+ io: io
163
166
  )
164
167
  output = begin
165
168
  parser.to_md
@@ -1,7 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Rundoc::CodeCommand::Background::Log
2
- class Clear < Rundoc::CodeCommand
4
+ class ClearArgs
5
+ attr_reader :name
6
+
3
7
  def initialize(name:)
4
8
  @name = name
9
+ end
10
+ end
11
+
12
+ class ClearRunner
13
+ def initialize(user_args:, render_command:, render_result:, io: nil, contents: nil)
14
+ @name = user_args.name
5
15
  @background = nil
6
16
  end
7
17
 
@@ -19,4 +29,4 @@ class Rundoc::CodeCommand::Background::Log
19
29
  end
20
30
  end
21
31
  end
22
- Rundoc.register_code_command(:"background.log.clear", Rundoc::CodeCommand::Background::Log::Clear)
32
+ Rundoc.register_code_command(keyword: :"background.log.clear", args_klass: Rundoc::CodeCommand::Background::Log::ClearArgs, runner_klass: Rundoc::CodeCommand::Background::Log::ClearRunner)
@@ -1,7 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Rundoc::CodeCommand::Background::Log
2
- class Read < Rundoc::CodeCommand
4
+ class ReadArgs
5
+ attr_reader :name
6
+
3
7
  def initialize(name:)
4
8
  @name = name
9
+ end
10
+ end
11
+
12
+ class ReadRunner
13
+ def initialize(user_args:, render_command:, render_result:, io: nil, contents: nil)
14
+ @name = user_args.name
5
15
  @background = nil
6
16
  end
7
17
 
@@ -18,4 +28,4 @@ class Rundoc::CodeCommand::Background::Log
18
28
  end
19
29
  end
20
30
  end
21
- Rundoc.register_code_command(:"background.log.read", Rundoc::CodeCommand::Background::Log::Read)
31
+ Rundoc.register_code_command(keyword: :"background.log.read", args_klass: Rundoc::CodeCommand::Background::Log::ReadArgs, runner_klass: Rundoc::CodeCommand::Background::Log::ReadRunner)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "shellwords"
2
4
  require "timeout"
3
5
  require "fileutils"
@@ -126,7 +128,7 @@ class Rundoc::CodeCommand::Background
126
128
  Process.kill("TERM", -Process.getpgid(@pid))
127
129
  Process.wait(@pid)
128
130
  rescue Errno::ESRCH => e
129
- puts "Error stopping process (command: #{command}): #{e}"
131
+ print_io&.puts "Error stopping process (command: #{command}): #{e}"
130
132
  ensure
131
133
  print_io&.puts "Log contents for `#{command}`:\n#{@log.read}"
132
134
  end
@@ -1,18 +1,37 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "tempfile"
2
4
 
3
5
  class Rundoc::CodeCommand::Background
4
- class Start < Rundoc::CodeCommand
6
+ class StartArgs
7
+ attr_reader :command, :name, :wait, :timeout, :log, :out, :allow_fail
8
+
5
9
  def initialize(command, name:, wait: nil, timeout: 5, log: Tempfile.new("log"), out: "2>&1", allow_fail: false)
6
- @timeout = timeout
7
10
  @command = command
8
11
  @name = name
9
12
  @wait = wait
10
- @allow_fail = allow_fail
13
+ @timeout = timeout
11
14
  @log = log
12
- @redirect = out
15
+ @out = out
16
+ @allow_fail = allow_fail
17
+ end
18
+ end
19
+
20
+ class StartRunner
21
+ attr_reader :io
22
+
23
+ def initialize(user_args:, render_command:, render_result:, io:, contents: nil)
24
+ @timeout = user_args.timeout
25
+ @command = user_args.command
26
+ @name = user_args.name
27
+ @wait = user_args.wait
28
+ @allow_fail = user_args.allow_fail
29
+ @log = user_args.log
30
+ @redirect = user_args.out
13
31
  FileUtils.touch(@log)
14
32
 
15
33
  @background = nil
34
+ @io = io
16
35
  end
17
36
 
18
37
  def background
@@ -22,7 +41,7 @@ class Rundoc::CodeCommand::Background
22
41
  log: @log,
23
42
  out: @redirect
24
43
  ).tap do |spawn|
25
- puts "Spawning commmand: `#{spawn.command}`"
44
+ io.puts "Spawning commmand: `#{spawn.command}`"
26
45
  ProcessSpawn.add(@name, spawn)
27
46
  end
28
47
  end
@@ -44,4 +63,4 @@ class Rundoc::CodeCommand::Background
44
63
  end
45
64
  end
46
65
 
47
- Rundoc.register_code_command(:"background.start", Rundoc::CodeCommand::Background::Start)
66
+ Rundoc.register_code_command(keyword: :"background.start", args_klass: Rundoc::CodeCommand::Background::StartArgs, runner_klass: Rundoc::CodeCommand::Background::StartRunner)
@@ -1,14 +1,27 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Rundoc::CodeCommand::Background
2
- # Will send contents to the background process via STDIN along with a newline
3
- #
4
- #
5
- class StdinWrite < Rundoc::CodeCommand
4
+ class StdinWriteArgs
5
+ attr_reader :contents, :name, :wait, :timeout, :ending
6
+
6
7
  def initialize(contents, name:, wait:, timeout: 5, ending: $/)
7
8
  @contents = contents
8
- @ending = ending
9
- @wait = wait
10
9
  @name = name
11
- @timeout_value = Integer(timeout)
10
+ @wait = wait
11
+ @timeout = Integer(timeout)
12
+ @ending = ending
13
+ end
14
+ end
15
+
16
+ class StdinWriteRunner
17
+ attr_reader :contents
18
+
19
+ def initialize(user_args:, render_command:, render_result:, io: nil, contents: nil)
20
+ @contents = user_args.contents
21
+ @ending = user_args.ending
22
+ @wait = user_args.wait
23
+ @name = user_args.name
24
+ @timeout_value = user_args.timeout
12
25
  @contents_written = nil
13
26
  @background = nil
14
27
  end
@@ -38,4 +51,4 @@ class Rundoc::CodeCommand::Background
38
51
  end
39
52
  end
40
53
  end
41
- Rundoc.register_code_command(:"background.stdin_write", Rundoc::CodeCommand::Background::StdinWrite)
54
+ Rundoc.register_code_command(keyword: :"background.stdin_write", args_klass: Rundoc::CodeCommand::Background::StdinWriteArgs, runner_klass: Rundoc::CodeCommand::Background::StdinWriteRunner)
@@ -1,7 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Rundoc::CodeCommand::Background
2
- class Stop < Rundoc::CodeCommand
4
+ class StopArgs
5
+ attr_reader :name
6
+
3
7
  def initialize(name:)
4
8
  @name = name
9
+ end
10
+ end
11
+
12
+ class StopRunner
13
+ def initialize(user_args:, render_command:, render_result:, io: nil, contents: nil)
14
+ @name = user_args.name
5
15
  @background = nil
6
16
  end
7
17
 
@@ -19,4 +29,4 @@ class Rundoc::CodeCommand::Background
19
29
  end
20
30
  end
21
31
  end
22
- Rundoc.register_code_command(:"background.stop", Rundoc::CodeCommand::Background::Stop)
32
+ Rundoc.register_code_command(keyword: :"background.stop", args_klass: Rundoc::CodeCommand::Background::StopArgs, runner_klass: Rundoc::CodeCommand::Background::StopRunner)
@@ -1,9 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Rundoc::CodeCommand::Background
2
- class Wait < Rundoc::CodeCommand
4
+ class WaitArgs
5
+ attr_reader :name, :wait, :timeout
6
+
3
7
  def initialize(name:, wait:, timeout: 5)
4
8
  @name = name
5
9
  @wait = wait
6
- @timeout_value = Integer(timeout)
10
+ @timeout = Integer(timeout)
11
+ end
12
+ end
13
+
14
+ class WaitRunner
15
+ def initialize(user_args:, render_command:, render_result:, io: nil, contents: nil)
16
+ @name = user_args.name
17
+ @wait = user_args.wait
18
+ @timeout_value = user_args.timeout
7
19
  @background = nil
8
20
  end
9
21
 
@@ -21,4 +33,4 @@ class Rundoc::CodeCommand::Background
21
33
  end
22
34
  end
23
35
  end
24
- Rundoc.register_code_command(:"background.wait", Rundoc::CodeCommand::Background::Wait)
36
+ Rundoc.register_code_command(keyword: :"background.wait", args_klass: Rundoc::CodeCommand::Background::WaitArgs, runner_klass: Rundoc::CodeCommand::Background::WaitRunner)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Rundoc::CodeCommand::Background
2
4
  end
3
5
 
@@ -1,9 +1,9 @@
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
- def initialize(line)
1
+ # frozen_string_literal: true
2
+
3
+ class Rundoc::CodeCommand::BashRunner
4
+ class Cd < Rundoc::CodeCommand::BashRunner
5
+ def initialize(line, io: $stdout)
6
+ @io = io
7
7
  @line = line
8
8
  end
9
9
 
@@ -23,7 +23,7 @@ class Rundoc::CodeCommand::Bash
23
23
 
24
24
  def call(env)
25
25
  line = @line.sub("cd", "").strip
26
- puts "running $ cd #{line}"
26
+ @io.puts "running $ cd #{line}"
27
27
 
28
28
  supress_chdir_warning do
29
29
  Dir.chdir(line)
@@ -1,18 +1,32 @@
1
- class Rundoc::CodeCommand::Bash < Rundoc::CodeCommand
2
- # line = "cd ..""
3
- # line = "pwd"
4
- # line = "ls"
1
+ # frozen_string_literal: true
2
+
3
+ class Rundoc::CodeCommand::BashArgs
4
+ attr_reader :line
5
+
5
6
  def initialize(line)
6
7
  @line = line
7
- @contents = ""
8
+ end
9
+ end
10
+
11
+ class Rundoc::CodeCommand::BashRunner
12
+ attr_reader :io, :contents
13
+
14
+ def initialize(user_args:, render_command:, render_result:, io:, contents: nil)
15
+ @io = io
16
+ @contents = contents.dup if contents && !contents.empty?
17
+ @line = user_args.line
8
18
  @delegate = case @line.split(" ").first.downcase
9
19
  when "cd"
10
- Cd.new(@line)
20
+ Cd.new(@line, io: io)
11
21
  else
12
22
  false
13
23
  end
14
24
  end
15
25
 
26
+ def raise_on_error?
27
+ true
28
+ end
29
+
16
30
  def to_md(env = {})
17
31
  return @delegate.to_md(env) if @delegate
18
32
 
@@ -34,30 +48,40 @@ class Rundoc::CodeCommand::Bash < Rundoc::CodeCommand
34
48
  cmd = "(#{cmd}) 2>&1"
35
49
  msg = "Running: $ '#{cmd}'"
36
50
  msg << " with stdin: '#{stdin.inspect}'" if stdin && !stdin.empty?
37
- puts msg
51
+ io.puts msg
38
52
 
39
- result = ""
40
- IO.popen(cmd, "w+") do |io|
41
- io << stdin if stdin
42
- io.close_write
53
+ result = +""
54
+ IO.popen(cmd, "w+") do |pipe|
55
+ pipe << stdin if stdin
56
+ pipe.close_write
43
57
 
44
- until io.eof?
45
- buffer = io.gets
46
- puts " #{buffer}"
58
+ until pipe.eof?
59
+ buffer = pipe.gets
60
+ io.puts " #{buffer}"
47
61
 
48
62
  result << sanitize_escape_chars(buffer)
49
63
  end
50
64
  end
51
65
 
52
- unless $?.success?
53
- raise "Command `#{@line}` exited with non zero status: #{result}" unless keyword.to_s.include?("fail")
66
+ if raise_on_error? && !$?.success?
67
+ raise "Command `#{@line}` exited with non zero status: #{result}"
54
68
  end
55
69
  result
56
70
  end
57
71
  end
58
72
 
59
- Rundoc.register_code_command(:bash, Rundoc::CodeCommand::Bash)
60
- Rundoc.register_code_command(:"$", Rundoc::CodeCommand::Bash)
61
- Rundoc.register_code_command(:"fail.$", Rundoc::CodeCommand::Bash)
73
+ class Rundoc::CodeCommand::BashRunnerFailOk < Rundoc::CodeCommand::BashRunner
74
+ def raise_on_error?
75
+ false
76
+ end
77
+ end
78
+
79
+ Rundoc.register_code_command(keyword: :bash, args_klass: Rundoc::CodeCommand::BashArgs, runner_klass: Rundoc::CodeCommand::BashRunner)
80
+ Rundoc.register_code_command(keyword: :"$", args_klass: Rundoc::CodeCommand::BashArgs, runner_klass: Rundoc::CodeCommand::BashRunner)
81
+ Rundoc.register_code_command(
82
+ keyword: :"fail.$",
83
+ args_klass: Rundoc::CodeCommand::BashArgs,
84
+ runner_klass: Rundoc::CodeCommand::BashRunnerFailOk
85
+ )
62
86
 
63
87
  require "rundoc/code_command/bash/cd"
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Rundoc::CodeCommand::CommentArgs
4
+ attr_reader :line
5
+
6
+ def initialize(line = nil)
7
+ @line = line
8
+ end
9
+ end
10
+
11
+ class Rundoc::CodeCommand::CommentRunner
12
+ def initialize(user_args:, render_command:, render_result:, io:, contents: nil)
13
+ @io = io
14
+ @line = user_args&.line
15
+ @contents = contents
16
+ end
17
+
18
+ def call(env = {})
19
+ @io.puts "Skipping command (commented out): # #{@line}\n#{@contents}".strip
20
+ ""
21
+ end
22
+
23
+ def to_md(env = {})
24
+ ""
25
+ end
26
+ end
27
+
28
+ Rundoc.register_code_command(
29
+ keyword: :"#",
30
+ args_klass: Rundoc::CodeCommand::CommentArgs,
31
+ runner_klass: Rundoc::CodeCommand::CommentRunner,
32
+ always_hidden: true
33
+ )
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rundoc
4
+ module CodeCommand
5
+ # Hold enough information to construct commands, but don't yet
6
+ #
7
+ # Allows us to separate parse time constructs from runtime injectables
8
+ # (such as IO). Which gives us a cleaner running model.
9
+ class Deferred
10
+ attr_accessor :render_result, :render_command,
11
+ :contents, :keyword, :original_args
12
+
13
+ alias_method :render_result?, :render_result
14
+ alias_method :render_command?, :render_command
15
+
16
+ attr_reader :runner_klass
17
+
18
+ def initialize(args_instance:, runner_klass:, always_hidden: false)
19
+ @args_instance = args_instance
20
+ @runner_klass = runner_klass
21
+ @always_hidden = always_hidden
22
+ end
23
+
24
+ def hidden?
25
+ !render_command? && !render_result?
26
+ end
27
+
28
+ def not_hidden?
29
+ !hidden?
30
+ end
31
+
32
+ def push(contents)
33
+ @contents ||= +""
34
+ @contents << contents
35
+ end
36
+ alias_method :<<, :push
37
+
38
+ def build(io: $stdout)
39
+ @built ||= begin
40
+ runner = @runner_klass.new(
41
+ user_args: @args_instance,
42
+ render_command: render_command,
43
+ render_result: render_result,
44
+ contents: @contents,
45
+ io: io
46
+ )
47
+ if @always_hidden
48
+ @render_command = false
49
+ @render_result = false
50
+ end
51
+ runner
52
+ end
53
+ rescue UnknownCommand
54
+ raise "No such command registered with rundoc #{keyword.inspect} for `#{keyword} #{original_args}`"
55
+ end
56
+
57
+ def call(env = {})
58
+ build.call(env)
59
+ end
60
+
61
+ def to_md(env = {})
62
+ build.to_md(env)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -1,18 +1,39 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Rundoc::CodeCommand::FileCommand
2
- class Append < Rundoc::CodeCommand
3
- include FileUtil
4
+ class AppendArgs
5
+ attr_reader :filename
4
6
 
5
7
  def initialize(filename)
6
- @filename, line = filename.split("#")
8
+ @filename = filename
9
+ end
10
+ end
11
+
12
+ class AppendRunner
13
+ NEWLINE = Rundoc::CodeCommand::WriteRunner::NEWLINE
14
+
15
+ include Rundoc::CodeCommand::FileUtil
16
+
17
+ attr_reader :io, :contents
18
+
19
+ def initialize(user_args:, render_command:, render_result:, io:, contents: nil)
20
+ @filename, line = user_args.filename.split("#")
7
21
  @line_number = if line
8
22
  Integer(line)
9
23
  end
24
+ @io = io
25
+ @render_command = render_command
26
+ @contents = contents.dup if contents && !contents.empty?
27
+ end
28
+
29
+ def render_command?
30
+ @render_command
10
31
  end
11
32
 
12
33
  def to_md(env)
13
34
  return unless render_command?
14
35
 
15
- if env[:commands].any? { |c| c[:object].not_hidden? }
36
+ if env[:commands].any? { |c| c[:visibility].not_hidden? }
16
37
  raise "Must call append in its own code section"
17
38
  end
18
39
 
@@ -34,7 +55,7 @@ class Rundoc::CodeCommand::FileCommand
34
55
  end
35
56
 
36
57
  def concat_with_newline(str1, str2)
37
- result = ""
58
+ result = +""
38
59
  result << str1
39
60
  result << "\n" unless ends_in_newline?(result)
40
61
  result << str2
@@ -61,10 +82,10 @@ class Rundoc::CodeCommand::FileCommand
61
82
  mkdir_p
62
83
  doc = File.read(filename)
63
84
  if @line_number
64
- puts "Writing to: '#{filename}' line #{@line_number} with: #{contents.inspect}"
85
+ io.puts "Writing to: '#{filename}' line #{@line_number} with: #{contents.inspect}"
65
86
  doc = insert_contents_into_at_line(doc)
66
87
  else
67
- puts "Appending to file: '#{filename}' with: #{contents.inspect}"
88
+ io.puts "Appending to file: '#{filename}' with: #{contents.inspect}"
68
89
  doc = concat_with_newline(doc, contents)
69
90
  end
70
91
 
@@ -74,4 +95,4 @@ class Rundoc::CodeCommand::FileCommand
74
95
  end
75
96
  end
76
97
 
77
- Rundoc.register_code_command(:"file.append", Rundoc::CodeCommand::FileCommand::Append)
98
+ Rundoc.register_code_command(keyword: :"file.append", args_klass: Rundoc::CodeCommand::FileCommand::AppendArgs, runner_klass: Rundoc::CodeCommand::FileCommand::AppendRunner)