markdown_exec 2.0.8.4 → 2.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 858c301950e3ca7d43bc8c8c9a87f1c340b75710c28743a02ed0811a649b46ba
4
- data.tar.gz: 4c7445f2d0e05e974cadd163894772b865bd7f94717f6f070fda6b2db2a0ef8c
3
+ metadata.gz: f49177c09809e5635f448181166f2fe60dffe9b942f1c23eeb29b2ecd43b55a8
4
+ data.tar.gz: 43488e384c44c757e1c7b95ad68e755a60a5bd617f3532c4e3213604984097e5
5
5
  SHA512:
6
- metadata.gz: c157d1ec261a140205eabe4d2ec8a30839e8b8f1c716c2d24710d3630c587e03282b11a5f27e269e02b8e1a568fbca7bf2e37537cc04d4b9d4cfce9ef1ab4803
7
- data.tar.gz: d991a308e029da9078adb996d8735951e3100eb117bc5a1f196db040513d4e20c715c6a4a805dcd528a93bd98d1a7b125eb2d88c4d9fea7449af1ad04add67be
6
+ metadata.gz: 9c923456c84259f80f53a839d48d4ed54c91f3bdc3ddb06fb96a1014b79a4640f21eed0bdb1f58635869fa70a5fb786259745a6e2a46cba2780a0093b81bc3e9
7
+ data.tar.gz: fbccdda04147b4a9ac0c9dd31bff501a626c60112fd70d0554aa89d2e005494e755abc0f63714c417e25461da23de3a960478cc1dd65fef9c126e927b6bbf037
data/CHANGELOG.md CHANGED
@@ -1,14 +1,23 @@
1
1
  # Changelog
2
2
 
3
- Pass-through arguments after "--" to the script
4
- M Gemfile.lock
5
- M bin/tab_completion.sh
6
- M examples/pass-through.md
7
- M lib/hash_delegator.rb
8
- M lib/markdown_exec.rb
9
- M lib/markdown_exec/version.rb
10
- M lib/menu.src.yml
11
- M lib/menu.yml
3
+ ## [2.1.0] - 2024-07-15
4
+
5
+ ### Added
6
+
7
+ - Option to toggle the output of an execution report.
8
+ - Option to toggle a menu entry to view saved script and output files.
9
+ - Options for formatting and parsing saved script and output file names.
10
+
11
+ ### Changed
12
+
13
+ - Fix handling of output streams for executed scripts to improve logging out output and addition to inherited code.
14
+ - YAML blocks are not executable from the menu.
15
+ - Fix collection of output of Link blocks.
16
+ - Pass-through arguments after "--" to the script.
17
+ - Remove app info from menu.yml.
18
+ - Remove test for unwanted arguments.
19
+ - Fix Link next_block_name when filename is used.
20
+ - In example doc, use nicknames to allow block content to be displayed.
12
21
 
13
22
  ## [2.0.8] - 2024-06-05
14
23
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- markdown_exec (2.0.8.4)
4
+ markdown_exec (2.1.0)
5
5
  clipboard (~> 1.3.6)
6
6
  open3 (~> 0.1.1)
7
7
  optparse (~> 0.1.1)
@@ -13,7 +13,7 @@ __filedirs_all()
13
13
  }
14
14
 
15
15
  _mde_echo_version() {
16
- echo "2.0.8.4"
16
+ echo "2.1.0"
17
17
  }
18
18
 
19
19
  _mde() {
@@ -178,4 +178,4 @@ _mde() {
178
178
 
179
179
  complete -o filenames -o nospace -F _mde mde
180
180
  # _mde_echo_version
181
- # echo "Updated: 2024-06-24 04:53:41 UTC"
181
+ # echo "Updated: 2024-07-16 20:54:59 UTC"
@@ -0,0 +1,50 @@
1
+ # Demonstrate data blocks
2
+
3
+ ```opts :(document_options)
4
+ pause_after_script_execution: true
5
+ ```
6
+
7
+ ## Create a data file by requiring a YAML block.
8
+ ::: YAML into a file
9
+ / YAML block that loads data into a file.
10
+ ```yaml :(test1) >test1.yml
11
+ a: species
12
+ b: genus
13
+ ```
14
+ This is a Bash block that
15
+ - requires a hidden YAML block (that creates a file), and
16
+ - displays the file.
17
+ ```bash +(test1)
18
+ echo "- The data file created"
19
+ ls -al *.yml
20
+ echo -e "\n- Contents of the file"
21
+ cat -n test1.yml
22
+ echo -e "\n- Remove the data file"
23
+ rm test1.yml
24
+ ```
25
+
26
+ ## Load data by requiring a yaml block.
27
+ ::: YAML into a shell variable
28
+ / YAML block that loads data into a variable.
29
+ ```yaml :(test2) >$test2
30
+ c: family
31
+ d: order
32
+ ```
33
+ This is a Bash block that
34
+ - requires a hidden YAML block (that sets a variable), and
35
+ - displays the variable.
36
+ ```bash +(test2)
37
+ echo 'data:'
38
+ echo "$test2"
39
+ ```
40
+
41
+ ## Visible YAML block that is not executable.
42
+ ::: Non-interactive data
43
+ ```yaml
44
+ e: class
45
+ f: phylum
46
+ ```
47
+
48
+ # Related MDE options
49
+ block_stdin_scan | Match to place block body into a file or a variable
50
+ block_stdout_scan | Match to place block body into a file or a variable
@@ -0,0 +1,46 @@
1
+ # Demo options: output_execution_report, output_execution_summary
2
+
3
+ ::: Options are initially True
4
+ ```opts :(document_options) +[document_options]
5
+ output_execution_report: true
6
+ output_execution_summary: true
7
+ pause_after_script_execution: true
8
+ ```
9
+ ```bash
10
+ whoami
11
+ pwd >&2
12
+ date >&1 1>&2
13
+ ```
14
+
15
+ ## output_execution_report
16
+ ### Example
17
+ -^-
18
+ Command: mde ./examples/opt_output_execution_summary.md
19
+ StdOut: logs/mde_2024-07-08-03-21-59_opt_output_execution_summary_,_whoami___pwd__&2___date__&1_1_&2_.out.txt
20
+ -v-
21
+ ### Toggle
22
+ ```opts
23
+ output_execution_report: false
24
+ ```
25
+ ```opts
26
+ output_execution_report: true
27
+ ```
28
+
29
+ ## output_execution_summary
30
+ ### Example (edited)
31
+ :execute_aborted_at:
32
+ :execute_completed_at: 2024-07-08 03:21:59.988451000 Z
33
+ :execute_error:
34
+ :execute_error_message:
35
+ :execute_options: { ... }
36
+ :execute_started_at: 2024-07-08 03:21:59.864442000 Z
37
+ :saved_filespec:
38
+ :script_block_name:
39
+ :streamed_lines: { ... }
40
+ ### Toggle
41
+ ```opts
42
+ output_execution_summary: false
43
+ ```
44
+ ```opts
45
+ output_execution_summary: true
46
+ ```
data/examples/save.md ADDED
@@ -0,0 +1,7 @@
1
+ ```opts :(document_options)
2
+ execute_in_own_window: false
3
+ save_execution_output: true
4
+ ```
5
+ ```bash :test
6
+ echo "$(date -u)"
7
+ ```
data/lib/constants.rb CHANGED
@@ -48,6 +48,7 @@ class MenuState
48
48
  CONTINUE = :continue
49
49
  EDIT = :edit
50
50
  EXIT = :exit
51
+ HISTORY = :history
51
52
  LOAD = :load
52
53
  SAVE = :save
53
54
  SHELL = :shell
@@ -34,6 +34,7 @@ require_relative 'mdoc'
34
34
  require_relative 'regexp'
35
35
  require_relative 'resize_terminal'
36
36
  require_relative 'std_out_err_logger'
37
+ require_relative 'streams_out'
37
38
  require_relative 'string_util'
38
39
 
39
40
  class String
@@ -163,15 +164,6 @@ module HashDelegatorSelf
163
164
  # end.join("\n")
164
165
  # end
165
166
 
166
- # Formats and returns the execution streams (like stdin, stdout, stderr) for a given key.
167
- # It concatenates the array of strings found under the specified key in the run_state's files.
168
- #
169
- # @param key [Symbol] The key corresponding to the desired execution stream.
170
- # @return [String] A concatenated string of the execution stream's contents.
171
- def format_execution_streams(key, files = {})
172
- (files || {}).fetch(key, []).join
173
- end
174
-
175
167
  # Indents all lines in a given string with a specified indentation string.
176
168
  # @param body [String] A multi-line string to be indented.
177
169
  # @param indent [String] The string used for indentation (default is an empty string).
@@ -266,16 +258,6 @@ module HashDelegatorSelf
266
258
  exit 1
267
259
  end
268
260
 
269
- # # Evaluates the given string as Ruby code and rescues any StandardErrors.
270
- # # If an error occurs, it calls the error_handler method with 'safeval'.
271
- # # @param str [String] The string to be evaluated.
272
- # # @return [Object] The result of evaluating the string.
273
- # def safeval(str)
274
- # eval(str)
275
- # rescue StandardError # catches NameError, StandardError
276
- # error_handler('safeval')
277
- # end
278
-
279
261
  def set_file_permissions(file_path, chmod_value)
280
262
  File.chmod(chmod_value, file_path)
281
263
  end
@@ -309,21 +291,6 @@ module HashDelegatorSelf
309
291
  &block)
310
292
  end
311
293
 
312
- def write_execution_output_to_file(files, filespec)
313
- FileUtils.mkdir_p File.dirname(filespec)
314
-
315
- File.write(
316
- filespec,
317
- ["-STDOUT-\n",
318
- format_execution_streams(ExecutionStreams::STD_OUT, files),
319
- "-STDERR-\n",
320
- format_execution_streams(ExecutionStreams::STD_ERR, files),
321
- "-STDIN-\n",
322
- format_execution_streams(ExecutionStreams::STD_IN, files),
323
- "\n"].join
324
- )
325
- end
326
-
327
294
  # Yields a line as a new block if the selected message type includes :line.
328
295
  # @param [String] line The line to be processed.
329
296
  # @param [Array<Symbol>] selected_messages A list of message types to check.
@@ -587,6 +554,9 @@ module MarkdownExec
587
554
  when MenuState::EXIT
588
555
  option_name = @delegate_object[:menu_option_exit_name]
589
556
  insert_at_top = @delegate_object[:menu_exit_at_top]
557
+ when MenuState::HISTORY
558
+ option_name = @delegate_object[:menu_option_history_name]
559
+ insert_at_top = @delegate_object[:menu_load_at_top]
590
560
  when MenuState::LOAD
591
561
  option_name = @delegate_object[:menu_option_load_name]
592
562
  insert_at_top = @delegate_object[:menu_load_at_top]
@@ -599,6 +569,8 @@ module MarkdownExec
599
569
  when MenuState::VIEW
600
570
  option_name = @delegate_object[:menu_option_view_name]
601
571
  insert_at_top = @delegate_object[:menu_load_at_top]
572
+ else
573
+ raise "Missing MenuState: #{menu_state}"
602
574
  end
603
575
 
604
576
  formatted_name = format(@delegate_object[:menu_link_format],
@@ -726,11 +698,12 @@ module MarkdownExec
726
698
  return unless @delegate_object[:saved_stdout_folder]
727
699
 
728
700
  @delegate_object[:logged_stdout_filename] =
729
- SavedAsset.stdout_name(blockname: block_name,
730
- filename: File.basename(@delegate_object[:filename],
731
- '.*'),
732
- prefix: @delegate_object[:logged_stdout_filename_prefix],
733
- time: Time.now.utc)
701
+ SavedAsset.new(blockname: block_name,
702
+ filename: @delegate_object[:filename],
703
+ prefix: @delegate_object[:logged_stdout_filename_prefix],
704
+ time: Time.now.utc,
705
+ exts: '.out.txt',
706
+ saved_asset_format: @delegate_object[:saved_asset_format]).generate_name
734
707
 
735
708
  @logged_stdout_filespec =
736
709
  @delegate_object[:logged_stdout_filespec] =
@@ -793,7 +766,7 @@ module MarkdownExec
793
766
  end
794
767
 
795
768
  def command_execute(command, args: [])
796
- run_state_reset_stream_logs
769
+ @run_state.files = StreamsOut.new
797
770
  @run_state.options = @delegate_object
798
771
  @run_state.started_at = Time.now.utc
799
772
 
@@ -820,14 +793,14 @@ module MarkdownExec
820
793
  @run_state.aborted_at = Time.now.utc
821
794
  @run_state.error_message = err.message
822
795
  @run_state.error = err
823
- @run_state.files[ExecutionStreams::STD_ERR] += [@run_state.error_message]
796
+ @run_state.files.append_stream_line(ExecutionStreams::STD_ERR, @run_state.error_message)
824
797
  @fout.fout "Error ENOENT: #{err.inspect}"
825
798
  rescue SignalException => err
826
799
  # Handle SignalException
827
800
  @run_state.aborted_at = Time.now.utc
828
801
  @run_state.error_message = 'SIGTERM'
829
802
  @run_state.error = err
830
- @run_state.files[ExecutionStreams::STD_ERR] += [@run_state.error_message]
803
+ @run_state.files.append_stream_line(ExecutionStreams::STD_ERR, @run_state.error_message)
831
804
  @fout.fout "Error ENOENT: #{err.inspect}"
832
805
  end
833
806
 
@@ -1080,8 +1053,7 @@ module MarkdownExec
1080
1053
  return unless @delegate_object[:save_execution_output]
1081
1054
  return if @run_state.in_own_window
1082
1055
 
1083
- HashDelegator.write_execution_output_to_file(@run_state.files,
1084
- @delegate_object[:logged_stdout_filespec])
1056
+ @run_state.files.write_execution_output_to_file(@delegate_object[:logged_stdout_filespec])
1085
1057
  end
1086
1058
 
1087
1059
  # Select and execute a code block from a Markdown document.
@@ -1117,12 +1089,14 @@ module MarkdownExec
1117
1089
  pop_add_current_code_to_head_and_trigger_load(@dml_link_state, inherited_block_names, code_lines, inherited_dependencies, selected)
1118
1090
  end
1119
1091
 
1120
- item_back = format(@delegate_object[:menu_link_format], HashDelegator.safeval(@delegate_object[:menu_option_back_name]))
1121
- item_edit = format(@delegate_object[:menu_link_format], HashDelegator.safeval(@delegate_object[:menu_option_edit_name]))
1122
- item_load = format(@delegate_object[:menu_link_format], HashDelegator.safeval(@delegate_object[:menu_option_load_name]))
1123
- item_save = format(@delegate_object[:menu_link_format], HashDelegator.safeval(@delegate_object[:menu_option_save_name]))
1124
- item_shell = format(@delegate_object[:menu_link_format], HashDelegator.safeval(@delegate_object[:menu_option_shell_name]))
1125
- item_view = format(@delegate_object[:menu_link_format], HashDelegator.safeval(@delegate_object[:menu_option_view_name]))
1092
+ fdo = ->(mo) { format(@delegate_object[:menu_link_format], HashDelegator.safeval(@delegate_object[mo])) }
1093
+ item_back = fdo.call(:menu_option_back_name)
1094
+ item_edit = fdo.call(:menu_option_edit_name)
1095
+ item_history = fdo.call(:menu_option_history_name)
1096
+ item_load = fdo.call(:menu_option_load_name)
1097
+ item_save = fdo.call(:menu_option_save_name)
1098
+ item_shell = fdo.call(:menu_option_shell_name)
1099
+ item_view = fdo.call(:menu_option_view_name)
1126
1100
 
1127
1101
  @run_state.batch_random = Random.new.rand
1128
1102
  @run_state.batch_index = 0
@@ -1136,6 +1110,12 @@ module MarkdownExec
1136
1110
  # puts "@ - parse document #{data}"
1137
1111
  inpseq_parse_document(data)
1138
1112
 
1113
+ if @delegate_object[:menu_for_history]
1114
+ history_files.tap do |files|
1115
+ menu_enable_option(item_history, files.count, 'files', menu_state: MenuState::HISTORY) if files.count.positive?
1116
+ end
1117
+ end
1118
+
1139
1119
  if @delegate_object[:menu_for_saved_lines] && @delegate_object[:document_saved_lines_glob].present?
1140
1120
 
1141
1121
  sf = document_name_in_glob_as_file_name(@dml_link_state.document_filename, @delegate_object[:document_saved_lines_glob])
@@ -1146,11 +1126,11 @@ module MarkdownExec
1146
1126
 
1147
1127
  # add menu items (glob, load, save) and enable selectively
1148
1128
  menu_add_disabled_option(sf) if files.count.positive? || lines_count.positive?
1149
- menu_enable_option(format(@delegate_object[:menu_link_format], HashDelegator.safeval(@delegate_object[:menu_option_load_name])), files.count, 'files', menu_state: MenuState::LOAD) if files.count.positive?
1150
- menu_enable_option(format(@delegate_object[:menu_link_format], HashDelegator.safeval(@delegate_object[:menu_option_edit_name])), lines_count, 'lines', menu_state: MenuState::EDIT) if lines_count.positive?
1151
- menu_enable_option(format(@delegate_object[:menu_link_format], HashDelegator.safeval(@delegate_object[:menu_option_save_name])), 1, '', menu_state: MenuState::SAVE) if lines_count.positive?
1152
- menu_enable_option(format(@delegate_object[:menu_link_format], HashDelegator.safeval(@delegate_object[:menu_option_view_name])), 1, '', menu_state: MenuState::VIEW) if lines_count.positive?
1153
- menu_enable_option(format(@delegate_object[:menu_link_format], HashDelegator.safeval(@delegate_object[:menu_option_shell_name])), 1, '', menu_state: MenuState::SHELL) if @delegate_object[:menu_with_shell]
1129
+ menu_enable_option(item_load, files.count, 'files', menu_state: MenuState::LOAD) if files.count.positive?
1130
+ menu_enable_option(item_edit, lines_count, 'lines', menu_state: MenuState::EDIT) if lines_count.positive?
1131
+ menu_enable_option(item_save, 1, '', menu_state: MenuState::SAVE) if lines_count.positive?
1132
+ menu_enable_option(item_view, 1, '', menu_state: MenuState::VIEW) if lines_count.positive?
1133
+ menu_enable_option(item_shell, 1, '', menu_state: MenuState::SHELL) if @delegate_object[:menu_with_shell]
1154
1134
  end
1155
1135
 
1156
1136
  when :display_menu
@@ -1195,6 +1175,42 @@ module MarkdownExec
1195
1175
  debounce_reset
1196
1176
  edited = edit_text(@dml_link_state.inherited_lines.join("\n"))
1197
1177
  @dml_link_state.inherited_lines = edited.split("\n") if edited
1178
+
1179
+ return :break if pause_user_exit
1180
+
1181
+ InputSequencer.next_link_state(prior_block_was_link: true)
1182
+
1183
+ when item_history
1184
+ debounce_reset
1185
+ files = history_files
1186
+ files_table_rows = files.map do |file|
1187
+ if Regexp.new(@delegate_object[:saved_asset_match]) =~ file
1188
+ OpenStruct.new(file: file, row: [$~[:time], $~[:blockname], $~[:exts]].join(' '))
1189
+ else
1190
+ warn "Cannot parse name: #{file}"
1191
+ next
1192
+ end
1193
+ end.compact
1194
+
1195
+ case (name = prompt_select_code_filename(
1196
+ [@delegate_object[:prompt_filespec_back]] +
1197
+ files_table_rows.map(&:row),
1198
+ string: @delegate_object[:prompt_select_history_file],
1199
+ color_sym: :prompt_color_after_script_execution
1200
+ ))
1201
+ when @delegate_object[:prompt_filespec_back]
1202
+ # do nothing
1203
+ else
1204
+ file = files_table_rows.select { |ftr| ftr.row == name }&.first
1205
+ info = file_info(file.file)
1206
+ warn "#{file.file} - #{info[:lines]} lines / #{info[:size]} bytes"
1207
+ warn(File.readlines(file.file, chomp: false).map.with_index do |line, ind|
1208
+ format(' %s. %s', format('% 4d', ind).violet, line)
1209
+ end)
1210
+ end
1211
+
1212
+ return :break if pause_user_exit
1213
+
1198
1214
  InputSequencer.next_link_state(prior_block_was_link: true)
1199
1215
 
1200
1216
  when item_load
@@ -1205,6 +1221,9 @@ module MarkdownExec
1205
1221
  @dml_link_state.inherited_lines ||= []
1206
1222
  @dml_link_state.inherited_lines += File.readlines(load_filespec, chomp: true)
1207
1223
  end
1224
+
1225
+ return :break if pause_user_exit
1226
+
1208
1227
  InputSequencer.next_link_state(prior_block_was_link: true)
1209
1228
 
1210
1229
  when item_save
@@ -1218,6 +1237,7 @@ module MarkdownExec
1218
1237
  return :break
1219
1238
 
1220
1239
  end
1240
+
1221
1241
  InputSequencer.next_link_state(prior_block_was_link: true)
1222
1242
 
1223
1243
  when item_shell
@@ -1236,11 +1256,17 @@ module MarkdownExec
1236
1256
  warn "#{'ERR'.bred} #{exit_status}"
1237
1257
  end
1238
1258
  end
1259
+
1260
+ return :break if pause_user_exit
1261
+
1239
1262
  InputSequencer.next_link_state(prior_block_was_link: true)
1240
1263
 
1241
1264
  when item_view
1242
1265
  debounce_reset
1243
1266
  warn @dml_link_state.inherited_lines.join("\n")
1267
+
1268
+ return :break if pause_user_exit
1269
+
1244
1270
  InputSequencer.next_link_state(prior_block_was_link: true)
1245
1271
 
1246
1272
  else
@@ -1558,6 +1584,21 @@ module MarkdownExec
1558
1584
  string_send_color(data_string, color_sym)
1559
1585
  end
1560
1586
 
1587
+ # size of a file in bytes and the number of lines
1588
+ def file_info(file_path)
1589
+ file_size = 0
1590
+ line_count = 0
1591
+
1592
+ File.open(file_path, 'r') do |file|
1593
+ file.each_line do |_line|
1594
+ line_count += 1
1595
+ end
1596
+ file_size = file.size
1597
+ end
1598
+
1599
+ { size: file_size, lines: line_count }
1600
+ end
1601
+
1561
1602
  def format_and_execute_command(code_lines:)
1562
1603
  formatted_command = code_lines.flatten.join("\n")
1563
1604
  @fout.fout fetch_color(data_sym: :script_execution_head,
@@ -1654,7 +1695,7 @@ module MarkdownExec
1654
1695
  Thread.new do
1655
1696
  stream.each_line do |line|
1656
1697
  line.strip!
1657
- @run_state.files[file_type] << line if @run_state.files
1698
+ @run_state.files.append_stream_line(file_type, line) if @run_state.files.streams
1658
1699
 
1659
1700
  if @delegate_object[:output_stdout]
1660
1701
  # print line
@@ -1671,6 +1712,16 @@ module MarkdownExec
1671
1712
  end
1672
1713
  end
1673
1714
 
1715
+ def history_files
1716
+ Dir.glob(
1717
+ File.join(
1718
+ @delegate_object[:saved_script_folder],
1719
+ SavedAsset.new(filename: @delegate_object[:filename],
1720
+ saved_asset_format: @delegate_object[:saved_asset_format]).generate_name
1721
+ )
1722
+ )
1723
+ end
1724
+
1674
1725
  # Initializes variables for regex and other states
1675
1726
  def initial_state
1676
1727
  {
@@ -1752,7 +1803,7 @@ module MarkdownExec
1752
1803
  file.rewind
1753
1804
 
1754
1805
  if link_block_data.fetch(LinkKeys::EXEC, false)
1755
- run_state_reset_stream_logs
1806
+ @run_state.files = StreamsOut.new
1756
1807
  execute_command_with_streams([cmd]) do |_stdin, stdout, stderr, _thread|
1757
1808
  line = stdout || stderr
1758
1809
  output_lines.push(line) if line
@@ -1876,6 +1927,7 @@ module MarkdownExec
1876
1927
  expanded_expression
1877
1928
  end
1878
1929
  end
1930
+
1879
1931
  # Handle expression with wildcard characters
1880
1932
  def load_filespec_wildcard_expansion(expr, auto_load_single: false)
1881
1933
  files = find_files(expr)
@@ -1886,7 +1938,11 @@ module MarkdownExec
1886
1938
  else
1887
1939
  ## user selects from existing files or other
1888
1940
  #
1889
- case (name = prompt_select_code_filename([@delegate_object[:prompt_filespec_back]] + files))
1941
+ case (name = prompt_select_code_filename(
1942
+ [@delegate_object[:prompt_filespec_back]] + files,
1943
+ string: @delegate_object[:prompt_select_code_file],
1944
+ color_sym: :prompt_color_after_script_execution
1945
+ ))
1890
1946
  when @delegate_object[:prompt_filespec_back]
1891
1947
  # do nothing
1892
1948
  else
@@ -2053,16 +2109,16 @@ module MarkdownExec
2053
2109
  def output_execution_summary
2054
2110
  return unless @delegate_object[:output_execution_summary]
2055
2111
 
2056
- fout_section 'summary', {
2112
+ @fout.fout_section 'summary', {
2057
2113
  execute_aborted_at: @run_state.aborted_at,
2058
2114
  execute_completed_at: @run_state.completed_at,
2059
2115
  execute_error: @run_state.error,
2060
2116
  execute_error_message: @run_state.error_message,
2061
- execute_files: @run_state.files,
2062
2117
  execute_options: @run_state.options,
2063
2118
  execute_started_at: @run_state.started_at,
2119
+ saved_filespec: @run_state.saved_filespec,
2064
2120
  script_block_name: @run_state.script_block_name,
2065
- saved_filespec: @run_state.saved_filespec
2121
+ streamed_lines: @run_state.files.streams
2066
2122
  }
2067
2123
  end
2068
2124
 
@@ -2075,6 +2131,11 @@ module MarkdownExec
2075
2131
  ), level: level
2076
2132
  end
2077
2133
 
2134
+ def pause_user_exit
2135
+ @delegate_object[:pause_after_script_execution] &&
2136
+ prompt_select_continue == MenuState::EXIT
2137
+ end
2138
+
2078
2139
  def pop_add_current_code_to_head_and_trigger_load(link_state, block_names, code_lines,
2079
2140
  dependencies, selected, next_block_name: nil)
2080
2141
  pop = @link_history.pop # updatable
@@ -2301,10 +2362,9 @@ module MarkdownExec
2301
2362
 
2302
2363
  # public
2303
2364
 
2304
- def prompt_select_code_filename(filenames)
2365
+ def prompt_select_code_filename(filenames, string: @delegate_object[:prompt_select_code_file], color_sym: :prompt_color_after_script_execution)
2305
2366
  @prompt.select(
2306
- string_send_color(@delegate_object[:prompt_select_code_file],
2307
- :prompt_color_after_script_execution),
2367
+ string_send_color(string, color_sym),
2308
2368
  filter: true,
2309
2369
  quiet: true
2310
2370
  ) do |menu|
@@ -2445,7 +2505,7 @@ module MarkdownExec
2445
2505
  end
2446
2506
 
2447
2507
  # Registers console attributes by modifying the options hash.
2448
- # This method handles terminal resizing and adjusts the console dimensions
2508
+ # This method handles terminal resizing and adjusts the console dimensions
2449
2509
  # and pagination settings based on the current terminal size.
2450
2510
  #
2451
2511
  # @param opts [Hash] a hash containing various options for the console settings.
@@ -2462,19 +2522,15 @@ module MarkdownExec
2462
2522
  # register_console_attributes(opts)
2463
2523
  # # opts will be updated with the current console dimensions and pagination settings.
2464
2524
  def register_console_attributes(opts)
2465
- begin
2466
- if (resized = @delegate_object[:menu_resize_terminal])
2467
- resize_terminal
2468
- end
2525
+ if (resized = @delegate_object[:menu_resize_terminal])
2526
+ resize_terminal
2527
+ end
2469
2528
 
2470
- if resized || !opts[:console_width]
2471
- opts[:console_height], opts[:console_width] = opts[:console_winsize] = IO.console.winsize
2472
- end
2529
+ opts[:console_height], opts[:console_width] = opts[:console_winsize] = IO.console.winsize if resized || !opts[:console_width]
2473
2530
 
2474
- opts[:per_page] = opts[:select_page_height] = [opts[:console_height] - 3, 4].max unless opts[:select_page_height]&.positive?
2475
- rescue StandardError
2476
- HashDelegator.error_handler('register_console_attributes', { abort: true })
2477
- end
2531
+ opts[:per_page] = opts[:select_page_height] = [opts[:console_height] - 3, 4].max unless opts[:select_page_height]&.positive?
2532
+ rescue StandardError
2533
+ HashDelegator.error_handler('register_console_attributes', { abort: true })
2478
2534
  end
2479
2535
 
2480
2536
  # Check if the delegate object responds to a given method.
@@ -2493,13 +2549,6 @@ module MarkdownExec
2493
2549
  end
2494
2550
  end
2495
2551
 
2496
- def run_state_reset_stream_logs
2497
- @run_state.files = Hash.new()
2498
- @run_state.files[ExecutionStreams::STD_ERR] = []
2499
- @run_state.files[ExecutionStreams::STD_IN] = []
2500
- @run_state.files[ExecutionStreams::STD_OUT] = []
2501
- end
2502
-
2503
2552
  def runtime_exception(exception_sym, name, items)
2504
2553
  if @delegate_object[exception_sym] != 0
2505
2554
  data = { name: name, detail: items.join(', ') }
@@ -2543,8 +2592,11 @@ module MarkdownExec
2543
2592
  ## user selects from existing files or other
2544
2593
  # input into path with wildcard for easy entry
2545
2594
  #
2546
- name = prompt_select_code_filename([@delegate_object[:prompt_filespec_back], @delegate_object[:prompt_filespec_other]] + files)
2547
- case name
2595
+ case (name = prompt_select_code_filename(
2596
+ [@delegate_object[:prompt_filespec_back], @delegate_object[:prompt_filespec_other]] + files,
2597
+ string: @delegate_object[:prompt_select_code_file],
2598
+ color_sym: :prompt_color_after_script_execution
2599
+ ))
2548
2600
  when @delegate_object[:prompt_filespec_back]
2549
2601
  # do nothing
2550
2602
  when @delegate_object[:prompt_filespec_other]
@@ -2811,12 +2863,12 @@ module MarkdownExec
2811
2863
 
2812
2864
  time_now = Time.now.utc
2813
2865
  @run_state.saved_script_filename =
2814
- SavedAsset.script_name(
2815
- blockname: selected.pub_name,
2816
- filename: @delegate_object[:filename],
2817
- prefix: @delegate_object[:saved_script_filename_prefix],
2818
- time: time_now
2819
- )
2866
+ SavedAsset.new(blockname: selected.pub_name,
2867
+ exts: '.sh',
2868
+ filename: @delegate_object[:filename],
2869
+ prefix: @delegate_object[:saved_script_filename_prefix],
2870
+ saved_asset_format: @delegate_object[:saved_asset_format],
2871
+ time: time_now).generate_name
2820
2872
  @run_state.saved_filespec =
2821
2873
  File.join(@delegate_object[:saved_script_folder],
2822
2874
  @run_state.saved_script_filename)
@@ -3416,25 +3468,27 @@ module MarkdownExec
3416
3468
  @hd.instance_variable_set(:@run_state, mock('run_state'))
3417
3469
  end
3418
3470
 
3419
- def test_format_execution_streams_with_valid_key
3420
- result = HashDelegator.format_execution_streams(ExecutionStreams::STD_OUT,
3421
- { stdout: %w[output1 output2] })
3471
+ def test_format_execution_stream_with_valid_key
3472
+ result = HashDelegator.format_execution_stream(
3473
+ { stdout: %w[output1 output2] },
3474
+ ExecutionStreams::STD_OUT
3475
+ )
3422
3476
 
3423
- assert_equal 'output1output2', result
3477
+ assert_equal "output1\noutput2", result
3424
3478
  end
3425
3479
 
3426
- def test_format_execution_streams_with_empty_key
3480
+ def test_format_execution_stream_with_empty_key
3427
3481
  @hd.instance_variable_get(:@run_state).stubs(:files).returns({})
3428
3482
 
3429
- result = HashDelegator.format_execution_streams(ExecutionStreams::STD_ERR)
3483
+ result = HashDelegator.format_execution_stream(nil, ExecutionStreams::STD_ERR)
3430
3484
 
3431
3485
  assert_equal '', result
3432
3486
  end
3433
3487
 
3434
- def test_format_execution_streams_with_nil_files
3488
+ def test_format_execution_stream_with_nil_files
3435
3489
  @hd.instance_variable_get(:@run_state).stubs(:files).returns(nil)
3436
3490
 
3437
- result = HashDelegator.format_execution_streams(:stdin)
3491
+ result = HashDelegator.format_execution_stream(nil, :stdin)
3438
3492
 
3439
3493
  assert_equal '', result
3440
3494
  end
@@ -7,5 +7,5 @@ module MarkdownExec
7
7
  BIN_NAME = 'mde'
8
8
  GEM_NAME = 'markdown_exec'
9
9
  TAP_DEBUG = 'MDE_DEBUG'
10
- VERSION = '2.0.8.4'
10
+ VERSION = '2.1.0'
11
11
  end
data/lib/menu.src.yml CHANGED
@@ -127,6 +127,13 @@
127
127
  :opt_name: menu_for_saved_lines
128
128
  :procname: val_as_bool
129
129
 
130
+ - :arg_name: BOOL
131
+ :default: true
132
+ :description: Add menu options for history
133
+ :env_var: MDE_menu_for_history
134
+ :opt_name: menu_for_history
135
+ :procname: val_as_bool
136
+
130
137
  - :arg_name: BOOL
131
138
  :default: false
132
139
  :description: Dump @delegate_object
@@ -643,8 +650,8 @@
643
650
  :opt_name: menu_note_format
644
651
  :procname: val_as_str
645
652
 
646
- ## all lines that do not start with "/ " are notes
647
- - :default: "^(?<line>(?!/ )(?<indent>[ \t]*)(?<text>.*?)(?<trailing>[ \t]*))?$"
653
+ ## lines that start with "/" are comments (hidden), not notes (visible)
654
+ - :default: "^(?<line>(?!/)(?<indent>[ \t]*)(?<text>.*?)(?<trailing>[ \t]*))?$"
648
655
  :description: Pattern for notes in block selection menu
649
656
  :env_var: MDE_MENU_NOTE_MATCH
650
657
  :opt_name: menu_note_match
@@ -671,6 +678,13 @@
671
678
  :opt_name: menu_option_exit_name
672
679
  :procname: val_as_str
673
680
 
681
+ - :default:
682
+ :line: "* History"
683
+ :description: Text for History option
684
+ :env_var: MDE_MENU_OPTION_HISTORY_NAME
685
+ :opt_name: menu_option_history_name
686
+ :procname: val_as_str
687
+
674
688
  - :default:
675
689
  :line: "* Load"
676
690
  :description: Text for Load option
@@ -992,6 +1006,12 @@
992
1006
  :opt_name: prompt_select_code_file
993
1007
  :procname: val_as_str
994
1008
 
1009
+ - :default: "\nView file:"
1010
+ :description: Prompt to select a saved asset
1011
+ :env_var: MDE_PROMPT_SELECT_HISTORY_FILE
1012
+ :opt_name: prompt_select_history_file
1013
+ :procname: val_as_str
1014
+
995
1015
  - :default: "\nChoose a file:"
996
1016
  :description: Prompt to select a markdown document
997
1017
  :env_var: MDE_PROMPT_SELECT_MD
@@ -1038,6 +1058,18 @@
1038
1058
  :opt_name: runtime_exception_error_level
1039
1059
  :procname: val_as_int
1040
1060
 
1061
+ - :default: '%{prefix}%{join}%{time}%{join}%{filename}%{join}%{mark}%{join}%{blockname}%{join}%{exts}'
1062
+ :description: saved_asset_format
1063
+ :env_var: MDE_SAVED_ASSET_FORMAT
1064
+ :opt_name: saved_asset_format
1065
+ :procname: val_as_str
1066
+
1067
+ - :default: "^(?<prefix>.+)(?<join>_)(?<time>[0-9\\-]+)\\g'join'(?<filename>.+)\\g'join'(?<mark>~)\\g'join'(?<blockname>.+)\\g'join'(?<exts>\\..+)$"
1068
+ :description: saved_asset_match
1069
+ :env_var: MDE_SAVED_ASSET_MATCH
1070
+ :opt_name: saved_asset_match
1071
+ :procname: val_as_str
1072
+
1041
1073
  - :arg_name: BOOL
1042
1074
  :default: false
1043
1075
  :description: Whether to save an executed script
data/lib/menu.yml CHANGED
@@ -106,6 +106,12 @@
106
106
  :env_var: MDE_MENU_FOR_SAVED_LINES
107
107
  :opt_name: menu_for_saved_lines
108
108
  :procname: val_as_bool
109
+ - :arg_name: BOOL
110
+ :default: true
111
+ :description: Add menu options for history
112
+ :env_var: MDE_menu_for_history
113
+ :opt_name: menu_for_history
114
+ :procname: val_as_bool
109
115
  - :arg_name: BOOL
110
116
  :default: false
111
117
  :description: Dump @delegate_object
@@ -542,7 +548,7 @@
542
548
  :env_var: MDE_MENU_NOTE_FORMAT
543
549
  :opt_name: menu_note_format
544
550
  :procname: val_as_str
545
- - :default: "^(?<line>(?!/ )(?<indent>[ \t]*)(?<text>.*?)(?<trailing>[ \t]*))?$"
551
+ - :default: "^(?<line>(?!/)(?<indent>[ \t]*)(?<text>.*?)(?<trailing>[ \t]*))?$"
546
552
  :description: Pattern for notes in block selection menu
547
553
  :env_var: MDE_MENU_NOTE_MATCH
548
554
  :opt_name: menu_note_match
@@ -565,6 +571,12 @@
565
571
  :env_var: MDE_MENU_OPTION_EXIT_NAME
566
572
  :opt_name: menu_option_exit_name
567
573
  :procname: val_as_str
574
+ - :default:
575
+ :line: "* History"
576
+ :description: Text for History option
577
+ :env_var: MDE_MENU_OPTION_HISTORY_NAME
578
+ :opt_name: menu_option_history_name
579
+ :procname: val_as_str
568
580
  - :default:
569
581
  :line: "* Load"
570
582
  :description: Text for Load option
@@ -848,6 +860,13 @@
848
860
  :procname: val_as_str
849
861
  - :default: |2-
850
862
 
863
+ View file:
864
+ :description: Prompt to select a saved asset
865
+ :env_var: MDE_PROMPT_SELECT_HISTORY_FILE
866
+ :opt_name: prompt_select_history_file
867
+ :procname: val_as_str
868
+ - :default: |2-
869
+
851
870
  Choose a file:
852
871
  :description: Prompt to select a markdown document
853
872
  :env_var: MDE_PROMPT_SELECT_MD
@@ -889,6 +908,16 @@
889
908
  :env_var: MDE_RUNTIME_EXCEPTION_ERROR_LEVEL
890
909
  :opt_name: runtime_exception_error_level
891
910
  :procname: val_as_int
911
+ - :default: "%{prefix}%{join}%{time}%{join}%{filename}%{join}%{mark}%{join}%{blockname}%{join}%{exts}"
912
+ :description: saved_asset_format
913
+ :env_var: MDE_SAVED_ASSET_FORMAT
914
+ :opt_name: saved_asset_format
915
+ :procname: val_as_str
916
+ - :default: "^(?<prefix>.+)(?<join>_)(?<time>[0-9\\-]+)\\g'join'(?<filename>.+)\\g'join'(?<mark>~)\\g'join'(?<blockname>.+)\\g'join'(?<exts>\\..+)$"
917
+ :description: saved_asset_match
918
+ :env_var: MDE_SAVED_ASSET_MATCH
919
+ :opt_name: saved_asset_match
920
+ :procname: val_as_str
892
921
  - :arg_name: BOOL
893
922
  :default: false
894
923
  :description: Whether to save an executed script
data/lib/saved_assets.rb CHANGED
@@ -12,23 +12,57 @@ module MarkdownExec
12
12
  # method derives a name for stdout redirection.
13
13
  #
14
14
  class SavedAsset
15
- FNR11 = %r{[^!#%&()\+,\-0-9=A-Z_a-z~]}.freeze
15
+ FNR11 = %r{[^!#%\+\-0-9=@A-Z_a-z]}.freeze # characters than can be used in a file name without quotes or escaping
16
+ # except '.', ',', '~' reserved for tokenization
16
17
  # / !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
17
18
  FNR12 = '_'
18
19
  DEFAULT_FTIME = '%F-%H-%M-%S'
20
+ FILE_BLOCK_SEP = ','
21
+ JOIN_STR = '_'
22
+ MARK_STR = '~'
19
23
 
20
- # Generates a formatted script name based on the provided parameters.
21
- def self.script_name(filename:, prefix:, time:, blockname:, ftime: DEFAULT_FTIME, join_str: '_', pattern: FNR11, replace: FNR12, exts: '.sh')
22
- fne = filename.gsub(pattern, replace)
23
- bne = blockname.gsub(pattern, replace)
24
- "#{[prefix, time.strftime(ftime), fne, ',', bne].join(join_str)}#{exts}"
24
+ # @param filename [String] the name of the file
25
+ # @param prefix [String] the prefix to use
26
+ # @param time [Time] the time object for formatting
27
+ # @param blockname [String] the block name to include
28
+ # @param ftime [String] the time format (default: DEFAULT_FTIME)
29
+ # @param pattern [Regexp] the pattern to search (default: FNR11)
30
+ # @param replace [String] the string to replace the pattern (default: FNR12)
31
+ # @param exts [String] the extension to append (default: '.sh')
32
+ def initialize(
33
+ saved_asset_format:, filename: nil, prefix: nil, time: nil, blockname: nil,
34
+ ftime: DEFAULT_FTIME, pattern: FNR11, replace: FNR12, exts: nil,
35
+ mark: nil, join_str: nil
36
+ )
37
+ @filename = filename ? filename.gsub(pattern, replace) : '*' # [String] the name of the file
38
+ @prefix = prefix || '*' # [String] the prefix to use
39
+ @time = time ? time.strftime(ftime) : '*' # [Time] the time object for formatting
40
+ @blockname = blockname ? blockname.gsub(pattern, replace) : '*' # [String] the block name to include
41
+ # @ftime = ftime # [String] the time format (default: DEFAULT_FTIME)
42
+ # @pattern = pattern # [Regexp] the pattern to search (default: FNR11)
43
+ # @replace = replace # [String] the string to replace the pattern (default: FNR12)
44
+ @exts = exts || '.*' # [String] the extension to append (default: '.sh')
45
+ @mark = mark || MARK_STR
46
+ @join_str = join_str || JOIN_STR
47
+ @saved_asset_format = saved_asset_format
25
48
  end
26
49
 
27
- # Generates a formatted stdout name based on the provided parameters.
28
- def self.stdout_name(filename:, prefix:, time:, blockname:, ftime: DEFAULT_FTIME, join_str: '_', pattern: FNR11, replace: FNR12, exts: '.out.txt')
29
- fne = filename.gsub(pattern, replace)
30
- bne = blockname.gsub(pattern, replace)
31
- "#{[prefix, time.strftime(ftime), fne, ',', bne].join(join_str)}#{exts}"
50
+ # Generates a formatted name based on the provided parameters.
51
+ #
52
+ # @return [String] the generated formatted name
53
+ def generate_name
54
+ format(
55
+ @saved_asset_format,
56
+ {
57
+ blockname: @blockname,
58
+ exts: @exts,
59
+ filename: @filename,
60
+ join: @join_str,
61
+ mark: @mark,
62
+ prefix: @prefix,
63
+ time: @time
64
+ }
65
+ )
32
66
  end
33
67
  end
34
68
  end
@@ -61,4 +95,76 @@ class SavedAssetTest < Minitest::Test
61
95
  filename: filename, prefix: prefix, time: time, blockname: blockname
62
96
  )
63
97
  end
98
+
99
+ def test_wildcard_name_with_all_parameters
100
+ filename = 'sample.txt'
101
+ prefix = 'test'
102
+ time = Time.new(2023, 1, 1, 12, 0, 0)
103
+ blockname = 'block/1:2'
104
+ expected_wildcard = 'test_2023-01-01-12-00-00_sample_txt_,_block_1_2.sh'
105
+
106
+ assert_equal expected_wildcard, MarkdownExec::SavedAsset.wildcard_name(
107
+ filename: filename, prefix: prefix, time: time, blockname: blockname
108
+ )
109
+ end
110
+
111
+ def test_wildcard_name_with_missing_time
112
+ filename = 'sample.txt'
113
+ prefix = 'test'
114
+ time = nil
115
+ blockname = 'block/1:2'
116
+ expected_wildcard = 'test_*_sample_txt_,_block_1_2.sh'
117
+
118
+ assert_equal expected_wildcard, MarkdownExec::SavedAsset.wildcard_name(
119
+ filename: filename, prefix: prefix, time: time, blockname: blockname
120
+ )
121
+ end
122
+
123
+ def test_wildcard_name_with_missing_filename
124
+ filename = nil
125
+ prefix = 'test'
126
+ time = Time.new(2023, 1, 1, 12, 0, 0)
127
+ blockname = 'block/1:2'
128
+ expected_wildcard = 'test_2023-01-01-12-00-00_*_,_block_1_2.sh'
129
+
130
+ assert_equal expected_wildcard, MarkdownExec::SavedAsset.wildcard_name(
131
+ filename: filename, prefix: prefix, time: time, blockname: blockname
132
+ )
133
+ end
134
+
135
+ def test_wildcard_name_with_missing_prefix
136
+ filename = 'sample.txt'
137
+ prefix = nil
138
+ time = Time.new(2023, 1, 1, 12, 0, 0)
139
+ blockname = 'block/1:2'
140
+ expected_wildcard = '*_2023-01-01-12-00-00_sample_txt_,_block_1_2.sh'
141
+
142
+ assert_equal expected_wildcard, MarkdownExec::SavedAsset.wildcard_name(
143
+ filename: filename, prefix: prefix, time: time, blockname: blockname
144
+ )
145
+ end
146
+
147
+ def test_wildcard_name_with_missing_blockname
148
+ filename = 'sample.txt'
149
+ prefix = 'test'
150
+ time = Time.new(2023, 1, 1, 12, 0, 0)
151
+ blockname = nil
152
+ expected_wildcard = 'test_2023-01-01-12-00-00_sample_txt_,_*.sh'
153
+
154
+ assert_equal expected_wildcard, MarkdownExec::SavedAsset.wildcard_name(
155
+ filename: filename, prefix: prefix, time: time, blockname: blockname
156
+ )
157
+ end
158
+
159
+ def test_wildcard_name_with_all_missing
160
+ filename = nil
161
+ prefix = nil
162
+ time = nil
163
+ blockname = nil
164
+ expected_wildcard = '*_*_*_,_*.sh'
165
+
166
+ assert_equal expected_wildcard, MarkdownExec::SavedAsset.wildcard_name(
167
+ filename: filename, prefix: prefix, time: time, blockname: blockname
168
+ )
169
+ end
64
170
  end
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # encoding=utf-8
5
+
6
+ class StreamsOut
7
+ attr_accessor :streams
8
+
9
+ def initialize
10
+ @streams = []
11
+ end
12
+
13
+ def append_stream_line(stream, line)
14
+ @streams << { stream: stream, line: line, timestamp: Time.now }
15
+ end
16
+
17
+ def write_execution_output_to_file(filespec)
18
+ FileUtils.mkdir_p File.dirname(filespec)
19
+
20
+ output = @streams.map do |entry|
21
+ case entry[:stream]
22
+ when ExecutionStreams::STD_OUT
23
+ entry[:line]
24
+ # "OUT: #{entry[:line]}"
25
+ when ExecutionStreams::STD_ERR
26
+ entry[:line]
27
+ # "ERR: #{entry[:line]}"
28
+ when ExecutionStreams::STD_IN
29
+ entry[:line]
30
+ # " IN: #{entry[:line]}"
31
+ end
32
+ end.join("\n")
33
+
34
+ File.write(filespec, output)
35
+ end
36
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: markdown_exec
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.8.4
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fareed Stevenson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-24 00:00:00.000000000 Z
11
+ date: 2024-07-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: clipboard
@@ -115,6 +115,7 @@ files:
115
115
  - bin/tab_completion.sh.erb
116
116
  - examples/block_names.md
117
117
  - examples/colors.md
118
+ - examples/data-files.md
118
119
  - examples/document_options.md
119
120
  - examples/duplicate_block.md
120
121
  - examples/import0.md
@@ -135,10 +136,12 @@ files:
135
136
  - examples/load_code.md
136
137
  - examples/nickname.md
137
138
  - examples/opts.md
139
+ - examples/opts_output_execution.md
138
140
  - examples/pass-through.md
139
141
  - examples/pause-after-execution.md
140
142
  - examples/plant.md
141
143
  - examples/port.md
144
+ - examples/save.md
142
145
  - examples/search.md
143
146
  - examples/vars.md
144
147
  - examples/wrap.md
@@ -179,6 +182,7 @@ files:
179
182
  - lib/saved_files_matcher.rb
180
183
  - lib/shared.rb
181
184
  - lib/std_out_err_logger.rb
185
+ - lib/streams_out.rb
182
186
  - lib/string_util.rb
183
187
  - lib/tap.rb
184
188
  homepage: https://rubygems.org/gems/markdown_exec