markdown_exec 2.0.2 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ece122ac9b2994b3a0ee90b6a6b07f637abd015f45b2275c0bcf740a2fbfb173
4
- data.tar.gz: f8c79187fc3f1fb4f8d53750dbb6078cb81ab58c04114bc484cd66ed22f890a5
3
+ metadata.gz: b67dcb867789b2a348645d74be064f2f596be8821f1174ceb736151ac7565732
4
+ data.tar.gz: 390919d82d1dcadb508edf926235269a96f6f30aee75d3b0368bc8c8ecfc94e2
5
5
  SHA512:
6
- metadata.gz: 57246f8b67613bdf55911dcc5274b7bad32b3702c3070ee75f30754ea8a816ebeee42b930bceb363313256b1b5368fd05bf2c1ccfbde545ea934d6b9d66d8e86
7
- data.tar.gz: fefcd1ed4b825a81cd9e5bfa79c0c3124550778908ad2200dd6ac9cd5db1ba6c70d2cc4987df05700ba2dd554461fd0b39ba330a32209f2edc7a7ad80cdadff3
6
+ metadata.gz: e0294e1c0eff38cd85d4917144bc41c407fea45b4fa89e680345c346873743c99565edaa1d224184a6b1a7106d1c6fe2d6cf77236cf63f98881bed2096812a1b
7
+ data.tar.gz: 23a6b99a7e205d60c6667c23a95acfd476dd36ab54192a183786a56773edf1e44cb803bef20afd2f86c13e237d2494c07a22cc4e9857cff1ae5dd41f73ebadeb
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.0.3] - 2024-04-15
4
+
5
+ ### Added
6
+
7
+ - Option to set menu line count to fill console height.
8
+ - Rescue when named block in link block is missing.
9
+
10
+ ### Changed
11
+
12
+ - Fix handling of variables with spaces in link blocks.
13
+ - Fix substitution for '/' in block names used in file names.
14
+
3
15
  ## [2.0.2] - 2024-02-09
4
16
 
5
17
  ### Changed
data/Gemfile CHANGED
@@ -9,7 +9,6 @@ gemspec
9
9
  gem 'clipboard'
10
10
  gem 'debug'
11
11
  gem 'erb'
12
- # gem 'httparty' # 2024-01-01 for ChatGPI API
13
12
  gem 'irb', '>= 1.8.0'
14
13
  gem 'mocha', require: false
15
14
  gem 'minitest', require: false
@@ -24,6 +23,5 @@ gem 'rubocop-minitest', require: false
24
23
  gem 'rubocop-rake', require: false
25
24
  gem 'rubocop-rspec', require: false
26
25
  gem 'shellwords'
27
- # gem 'tty-file'
28
26
  gem 'uri', '0.12.2'
29
27
  gem 'yaml', '~> 0.2.1'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- markdown_exec (2.0.2)
4
+ markdown_exec (2.0.3)
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.2"
16
+ echo "2.0.3"
17
17
  }
18
18
 
19
19
  _mde() {
@@ -186,4 +186,4 @@ _mde() {
186
186
 
187
187
  complete -o filenames -o nospace -F _mde mde
188
188
  # _mde_echo_version
189
- # echo "Updated: 2024-02-09 19:26:00 UTC"
189
+ # echo "Updated: 2024-04-17 23:39:50 UTC"
data/examples/linked.md CHANGED
@@ -5,6 +5,11 @@ pause_after_script_execution: false
5
5
  user_must_approve: false
6
6
  ```
7
7
 
8
+ ```link :missing_block
9
+ block: (display_variable)
10
+ eval: true
11
+ ```
12
+
8
13
  ```link :link_with_vars_with_spaces
9
14
  vars:
10
15
  test: "1 2 3"
@@ -33,11 +33,15 @@ class AnsiFormatter
33
33
  def scan_and_process_multiple_substrings(str, substrings, plain_sym, color_sym)
34
34
  return string_send_color(str, plain_sym) if substrings.empty? || substrings.any?(&:empty?)
35
35
 
36
+ substring_patterns = substrings.map do |value|
37
+ [value, Regexp.new(value, Regexp::IGNORECASE)]
38
+ end
39
+
36
40
  results = []
37
41
  remaining_str = str.dup
38
42
 
39
43
  while remaining_str.length.positive?
40
- match_indices = substrings.map { |substring| remaining_str.index(substring) }.compact
44
+ match_indices = substring_patterns.map { |_, pattern| remaining_str.index(pattern) }.compact
41
45
  earliest_match = match_indices.min
42
46
 
43
47
  if earliest_match
@@ -48,12 +52,12 @@ class AnsiFormatter
48
52
  end
49
53
 
50
54
  # Find which substring has this earliest match
51
- matching_substring = substrings.find do |substring|
52
- remaining_str.index(substring) == earliest_match
55
+ matching_substring = substring_patterns.find do |_, pattern|
56
+ remaining_str.index(pattern) == earliest_match
53
57
  end
54
58
 
55
59
  if matching_substring
56
- matching_segment = remaining_str.slice!(0...matching_substring.length)
60
+ matching_segment = remaining_str.slice!(0...matching_substring[0].length)
57
61
  results << string_send_color(matching_segment, color_sym)
58
62
  end
59
63
  else
@@ -102,7 +102,7 @@ class DirectorySearcher
102
102
  # @param include_subdirectories [Boolean] Whether to search in subdirectories.
103
103
  # @param filename_glob [String, nil] Glob pattern for file names.
104
104
  def initialize(pattern, paths, include_subdirectories: true, filename_glob: '*.[Mm][Dd]') #'*.md'
105
- @pattern = pattern
105
+ @pattern = Regexp.new(pattern, Regexp::IGNORECASE)
106
106
  @paths = paths
107
107
  @include_subdirectories = include_subdirectories
108
108
  @filename_glob = filename_glob
@@ -11,7 +11,6 @@ require 'optparse'
11
11
  require 'set'
12
12
  require 'shellwords'
13
13
  require 'tmpdir'
14
- # require 'tty-file'
15
14
  require 'tty-prompt'
16
15
  require 'yaml'
17
16
 
@@ -21,6 +20,7 @@ require_relative 'block_label'
21
20
  require_relative 'block_types'
22
21
  require_relative 'cached_nested_file_reader'
23
22
  require_relative 'constants'
23
+ require_relative 'std_out_err_logger'
24
24
  require_relative 'directory_searcher'
25
25
  require_relative 'exceptions'
26
26
  require_relative 'fcb'
@@ -193,18 +193,15 @@ module HashDelegatorSelf
193
193
  end
194
194
 
195
195
  def next_link_state(block_name_from_cli:, was_using_cli:, block_state:, block_name: nil)
196
- # &bsp 'next_link_state', block_name_from_cli, was_using_cli, block_state
197
196
  # Set block_name based on block_name_from_cli
198
197
  block_name = @cli_block_name if block_name_from_cli
199
- # &bsp 'block_name:', block_name
200
198
 
201
199
  # Determine the state of breaker based on was_using_cli and the block type
200
+ # true only when block_name is nil, block_name_from_cli is false, was_using_cli is true, and the block_state.block[:shell] equals BlockType::BASH. In all other scenarios, breaker is false.
202
201
  breaker = !block_name && !block_name_from_cli && was_using_cli && block_state.block[:shell] == BlockType::BASH
203
- # &bsp 'breaker:', breaker
204
202
 
205
203
  # Reset block_name_from_cli if the conditions are not met
206
204
  block_name_from_cli ||= false
207
- # &bsp 'block_name_from_cli:', block_name_from_cli
208
205
 
209
206
  [block_name, block_name_from_cli, breaker]
210
207
  end
@@ -352,6 +349,20 @@ module CompactionHelpers
352
349
  end
353
350
  end
354
351
 
352
+ module PathUtils
353
+ # Determines if a given path is absolute or substitutes a placeholder in an expression with the path.
354
+ # @param path [String] The input path to check or fill in.
355
+ # @param expression [String] The expression where a wildcard '*' is replaced by the path if it's not absolute.
356
+ # @return [String] The absolute path or the expression with the wildcard replaced by the path.
357
+ def self.resolve_path_or_substitute(path, expression)
358
+ if path.include?('/')
359
+ path
360
+ else
361
+ expression.gsub('*', path)
362
+ end
363
+ end
364
+ end
365
+
355
366
  module MarkdownExec
356
367
  class DebugHelper
357
368
  # Class-level variable to store history of printed messages
@@ -368,7 +379,7 @@ module MarkdownExec
368
379
  end
369
380
  end
370
381
 
371
- class HashDelegator
382
+ class HashDelegatorParent
372
383
  attr_accessor :most_recent_loaded_filename, :pass_args, :run_state
373
384
 
374
385
  extend HashDelegatorSelf
@@ -559,11 +570,11 @@ module MarkdownExec
559
570
 
560
571
  # private
561
572
 
562
- def calc_logged_stdout_filename
573
+ def calc_logged_stdout_filename(block_name:)
563
574
  return unless @delegate_object[:saved_stdout_folder]
564
575
 
565
576
  @delegate_object[:logged_stdout_filename] =
566
- SavedAsset.stdout_name(blockname: @delegate_object[:block_name],
577
+ SavedAsset.stdout_name(blockname: block_name,
567
578
  filename: File.basename(@delegate_object[:filename],
568
579
  '.*'),
569
580
  prefix: @delegate_object[:logged_stdout_filename_prefix],
@@ -898,7 +909,7 @@ module MarkdownExec
898
909
  # @param selected [FCB] The selected functional code block object.
899
910
  def execute_required_lines(required_lines: [], selected: FCB.new)
900
911
  write_command_file(required_lines: required_lines, selected: selected) if @delegate_object[:save_executed_script]
901
- calc_logged_stdout_filename
912
+ calc_logged_stdout_filename(block_name: @dml_block_state.block[:oname]) if @dml_block_state
902
913
  format_and_execute_command(code_lines: required_lines)
903
914
  post_execution_process
904
915
  end
@@ -950,7 +961,6 @@ module MarkdownExec
950
961
  next_load_file: LoadFile::Reuse
951
962
  )
952
963
 
953
-
954
964
  elsif selected[:shell] == BlockType::VARS
955
965
  debounce_reset
956
966
  block_names = []
@@ -972,6 +982,7 @@ module MarkdownExec
972
982
  selected: selected,
973
983
  link_state: link_state,
974
984
  block_source: block_source)
985
+
975
986
  else
976
987
  LoadFileLinkState.new(LoadFile::Reuse, link_state)
977
988
  end
@@ -1132,42 +1143,47 @@ module MarkdownExec
1132
1143
  def link_block_data_eval(link_state, code_lines, selected, link_block_data, block_source:)
1133
1144
  all_code = HashDelegator.code_merge(link_state&.inherited_lines, code_lines)
1134
1145
 
1135
- if link_block_data.fetch(LinkKeys::Exec, false)
1136
- @run_state.files = Hash.new([])
1137
- output_lines = []
1146
+ Tempfile.open do |file|
1147
+ file.write(all_code.join("\n"))
1148
+ file.rewind
1138
1149
 
1139
- Open3.popen3(
1140
- @delegate_object[:shell],
1141
- '-c', all_code.join("\n")
1142
- ) do |stdin, stdout, stderr, _exec_thr|
1143
- handle_stream(stream: stdout, file_type: ExecutionStreams::StdOut) do |line|
1144
- output_lines.push(line)
1145
- end
1146
- handle_stream(stream: stderr, file_type: ExecutionStreams::StdErr) do |line|
1147
- output_lines.push(line)
1148
- end
1150
+ if link_block_data.fetch(LinkKeys::Exec, false)
1151
+ @run_state.files = Hash.new([])
1152
+ output_lines = []
1149
1153
 
1150
- in_thr = handle_stream(stream: $stdin, file_type: ExecutionStreams::StdIn) do |line|
1151
- stdin.puts(line)
1152
- end
1154
+ Open3.popen3(
1155
+ "#{@delegate_object[:shell]} #{file.path}"
1156
+ ) do |stdin, stdout, stderr, _exec_thr|
1157
+ handle_stream(stream: stdout, file_type: ExecutionStreams::StdOut) do |line|
1158
+ output_lines.push(line)
1159
+ end
1160
+ handle_stream(stream: stderr, file_type: ExecutionStreams::StdErr) do |line|
1161
+ output_lines.push(line)
1162
+ end
1153
1163
 
1154
- wait_for_stream_processing
1155
- sleep 0.1
1156
- in_thr.kill if in_thr&.alive?
1157
- end
1164
+ in_thr = handle_stream(stream: $stdin, file_type: ExecutionStreams::StdIn) do |line|
1165
+ stdin.puts(line)
1166
+ end
1158
1167
 
1159
- ## select output_lines that look like assignment or match other specs
1160
- #
1161
- output_lines = process_string_array(
1162
- output_lines,
1163
- begin_pattern: @delegate_object.fetch(:output_assignment_begin, nil),
1164
- end_pattern: @delegate_object.fetch(:output_assignment_end, nil),
1165
- scan1: @delegate_object.fetch(:output_assignment_match, nil),
1166
- format1: @delegate_object.fetch(:output_assignment_format, nil)
1167
- )
1168
+ wait_for_stream_processing
1169
+ sleep 0.1
1170
+ in_thr.kill if in_thr&.alive?
1171
+ end
1168
1172
 
1169
- else
1170
- output_lines = `#{all_code.join("\n")}`.split("\n")
1173
+ ## select output_lines that look like assignment or match other specs
1174
+ #
1175
+ output_lines = process_string_array(
1176
+ output_lines,
1177
+ begin_pattern: @delegate_object.fetch(:output_assignment_begin, nil),
1178
+ end_pattern: @delegate_object.fetch(:output_assignment_end, nil),
1179
+ scan1: @delegate_object.fetch(:output_assignment_match, nil),
1180
+ format1: @delegate_object.fetch(:output_assignment_format, nil)
1181
+ )
1182
+
1183
+ else
1184
+ # output_lines = `#{all_code.join("\n")}`.split("\n")
1185
+ output_lines = `#{@delegate_object[:shell]} #{file.path}`.split("\n")
1186
+ end
1171
1187
  end
1172
1188
 
1173
1189
  HashDelegator.error_handler('all_code eval output_lines is nil', { abort: true }) unless output_lines
@@ -1285,7 +1301,7 @@ module MarkdownExec
1285
1301
  puts format(@delegate_object[:prompt_show_expr_format],
1286
1302
  { expr: filespec })
1287
1303
  puts @delegate_object[:prompt_enter_filespec]
1288
- resolve_path_or_substitute(gets.chomp, filespec)
1304
+ PathUtils.resolve_path_or_substitute(gets.chomp, filespec)
1289
1305
  end
1290
1306
 
1291
1307
  # Handle expression with wildcard characters
@@ -1320,11 +1336,34 @@ module MarkdownExec
1320
1336
  }
1321
1337
  end
1322
1338
 
1339
+ # # Loads auto link block.
1340
+ # def load_auto_link_block(all_blocks, link_state, mdoc, block_source:)
1341
+ # block_name = @delegate_object[:document_load_link_block_name]
1342
+ # return unless block_name.present? && @most_recent_loaded_filename != @delegate_object[:filename]
1343
+
1344
+ # block = HashDelegator.block_find(all_blocks, :oname, block_name)
1345
+ # return unless block
1346
+
1347
+ # if block.fetch(:shell, '') != BlockType::LINK
1348
+ # HashDelegator.error_handler('must be Link block type', { abort: true })
1349
+
1350
+ # else
1351
+ # # debounce_reset
1352
+ # push_link_history_and_trigger_load(
1353
+ # link_block_body: block.fetch(:body, ''),
1354
+ # mdoc: mdoc,
1355
+ # selected: block,
1356
+ # link_state: link_state,
1357
+ # block_source: block_source
1358
+ # )
1359
+ # end
1360
+ # end
1361
+
1323
1362
  # Loads auto blocks based on delegate object settings and updates if new filename is detected.
1324
1363
  # Executes a specified block once per filename.
1325
1364
  # @param all_blocks [Array] Array of all block elements.
1326
1365
  # @return [Boolean, nil] True if values were modified, nil otherwise.
1327
- def load_auto_blocks(all_blocks)
1366
+ def load_auto_opts_block(all_blocks)
1328
1367
  block_name = @delegate_object[:document_load_opts_block_name]
1329
1368
  return unless block_name.present? && @most_recent_loaded_filename != @delegate_object[:filename]
1330
1369
 
@@ -1354,7 +1393,8 @@ module MarkdownExec
1354
1393
 
1355
1394
  # recreate menu with new options
1356
1395
  #
1357
- all_blocks, mdoc = mdoc_and_blocks_from_nested_files if load_auto_blocks(all_blocks)
1396
+ all_blocks, mdoc = mdoc_and_blocks_from_nested_files if load_auto_opts_block(all_blocks)
1397
+ # load_auto_link_block(all_blocks, link_state, mdoc, block_source: {})
1358
1398
 
1359
1399
  menu_blocks = mdoc.fcbs_per_options(@delegate_object)
1360
1400
  add_menu_chrome_blocks!(menu_blocks: menu_blocks, link_state: link_state)
@@ -1756,18 +1796,6 @@ module MarkdownExec
1756
1796
  end
1757
1797
  end
1758
1798
 
1759
- # Determines if a given path is absolute or substitutes a placeholder in an expression with the path.
1760
- # @param path [String] The input path to check or fill in.
1761
- # @param expression [String] The expression where a wildcard '*' is replaced by the path if it's not absolute.
1762
- # @return [String] The absolute path or the expression with the wildcard replaced by the path.
1763
- def resolve_path_or_substitute(path, expression)
1764
- if path.include?('/')
1765
- path
1766
- else
1767
- expression.gsub('*', path)
1768
- end
1769
- end
1770
-
1771
1799
  def runtime_exception(exception_sym, name, items)
1772
1800
  if @delegate_object[exception_sym] != 0
1773
1801
  data = { name: name, detail: items.join(', ') }
@@ -1841,12 +1869,20 @@ module MarkdownExec
1841
1869
  @delegate_object[:block_name] = nil
1842
1870
 
1843
1871
  when :user_choice
1844
- # puts "? - Select a block to execute (or type #{$texit} to exit):"
1845
- break if ii_user_choice == :break # into @dml_block_state
1846
- break if @dml_block_state.block.nil? # no block matched
1847
-
1872
+ if @dml_link_state.block_name.present?
1873
+ # @prior_block_was_link = true
1874
+ @dml_block_state.block = @dml_blocks_in_file.find do |item|
1875
+ item[:oname] == @dml_link_state.block_name
1876
+ end
1877
+ @dml_link_state.block_name = nil
1878
+ else
1879
+ # puts "? - Select a block to execute (or type #{$texit} to exit):"
1880
+ break if ii_user_choice == :break # into @dml_block_state
1881
+ break if @dml_block_state.block.nil? # no block matched
1882
+ end
1848
1883
  # puts "! - Executing block: #{data}"
1849
- @dml_block_state.block[:oname]
1884
+ # @dml_block_state.block[:oname]
1885
+ @dml_block_state.block&.fetch(:oname, nil)
1850
1886
 
1851
1887
  when :execute_block
1852
1888
  block_name = data
@@ -1888,13 +1924,12 @@ module MarkdownExec
1888
1924
 
1889
1925
  ## order of block name processing: link block, cli, from user
1890
1926
  #
1891
- @cli_block_name = block_name
1892
1927
  @dml_link_state.block_name, @run_state.block_name_from_cli, cli_break = \
1893
1928
  HashDelegator.next_link_state(
1894
- block_name_from_cli: !@dml_link_state.block_name,
1895
- was_using_cli: @dml_now_using_cli,
1929
+ block_name: @dml_link_state.block_name,
1930
+ block_name_from_cli: !@dml_link_state.block_name.present?,
1896
1931
  block_state: @dml_block_state,
1897
- block_name: @dml_link_state.block_name
1932
+ was_using_cli: @dml_now_using_cli
1898
1933
  )
1899
1934
 
1900
1935
  if !@dml_block_state.block[:block_name_from_ui] && cli_break
@@ -2282,7 +2317,12 @@ module MarkdownExec
2282
2317
  @delegate_object
2283
2318
  end
2284
2319
 
2285
- selection_opts.merge!(per_page: @delegate_object[:select_page_height])
2320
+ sph = @delegate_object[:select_page_height]
2321
+ unless sph.positive?
2322
+ require 'io/console'
2323
+ sph = [IO.console.winsize[0] - 3, 4].max
2324
+ end
2325
+ selection_opts.merge!(per_page: sph)
2286
2326
 
2287
2327
  selected_option = select_option_with_metadata(prompt_title, block_menu,
2288
2328
  selection_opts)
@@ -2331,13 +2371,63 @@ module MarkdownExec
2331
2371
  if save_expr.present?
2332
2372
  save_filespec = save_filespec_from_expression(save_expr)
2333
2373
  File.write(save_filespec, HashDelegator.join_code_lines(link_state&.inherited_lines))
2334
- # TTY::File.create_file save_filespec, HahDelegator.join_code_lines(link_state&.inherited_lines), force: true
2335
2374
  @delegate_object[:filename]
2336
2375
  else
2337
2376
  link_block_data[LinkKeys::File] || @delegate_object[:filename]
2338
2377
  end
2339
2378
  end
2340
2379
  end
2380
+
2381
+ class HashDelegator < HashDelegatorParent
2382
+ # Cleans a value, handling both Hash and Struct types.
2383
+ # For Structs, the cleaned version is converted to a hash.
2384
+ def self.clean_value(value)
2385
+ case value
2386
+ when Hash
2387
+ clean_hash_recursively(value)
2388
+ when Struct
2389
+ struct_hash = value.to_h # Convert the Struct to a hash
2390
+ cleaned_hash = clean_hash_recursively(struct_hash) # Clean the hash
2391
+ # Return the cleaned hash instead of updating the Struct
2392
+ return cleaned_hash
2393
+ else
2394
+ value
2395
+ end
2396
+ end
2397
+
2398
+ # Recursively cleans the given object (hash or struct) from unwanted values.
2399
+ def self.clean_hash_recursively(obj)
2400
+ obj.each do |key, value|
2401
+ cleaned_value = clean_value(value) # Clean and possibly convert value
2402
+ obj[key] = cleaned_value if value.is_a?(Hash) || value.is_a?(Struct)
2403
+ end
2404
+
2405
+ if obj.is_a?(Hash)
2406
+ obj.select! { |key, value| ![nil, '', [], {}, nil].include?(value) }
2407
+ end
2408
+
2409
+ obj
2410
+ end
2411
+
2412
+ def self.next_link_state(*args, **kwargs, &block)
2413
+ super
2414
+ # result = super
2415
+
2416
+ # @logger ||= StdOutErrLogger.new
2417
+ # @logger.unknown(
2418
+ # HashDelegator.clean_hash_recursively(
2419
+ # { "HashDelegator.next_link_state":
2420
+ # { 'args': args,
2421
+ # 'at': Time.now.strftime('%FT%TZ'),
2422
+ # 'for': /[^\/]+:\d+/.match(caller.first)[0],
2423
+ # 'kwargs': kwargs,
2424
+ # 'return': result } }
2425
+ # )
2426
+ # )
2427
+
2428
+ # result
2429
+ end
2430
+ end
2341
2431
  end
2342
2432
 
2343
2433
  return if $PROGRAM_NAME != __FILE__
@@ -2348,12 +2438,20 @@ Bundler.require(:default)
2348
2438
  require 'minitest/autorun'
2349
2439
  require 'mocha/minitest'
2350
2440
 
2351
- ####
2352
- require_relative 'instance_method_wrapper'
2353
- # MarkdownExec::HashDelegator.prepend(InstanceMethodWrapper)
2354
- # MarkdownExec::HashDelegator.singleton_class.prepend(ClassMethodWrapper)
2441
+ require_relative 'std_out_err_logger'
2355
2442
 
2356
2443
  module MarkdownExec
2444
+ class TestHashDelegator0 < Minitest::Test
2445
+ def setup
2446
+ @hd = HashDelegator.new
2447
+ end
2448
+
2449
+ # Test case for empty body
2450
+ def test_next_link_state
2451
+ @hd.next_link_state(block_name_from_cli: nil, was_using_cli: nil, block_state: nil, block_name: nil)
2452
+ end
2453
+ end
2454
+
2357
2455
  class TestHashDelegator < Minitest::Test
2358
2456
  def setup
2359
2457
  @hd = HashDelegator.new
@@ -3194,29 +3292,33 @@ module MarkdownExec
3194
3292
  end
3195
3293
  end
3196
3294
 
3197
- def test_resolves_absolute_path
3198
- absolute_path = '/usr/local/bin'
3199
- assert_equal '/usr/local/bin', resolve_path_or_substitute(absolute_path, 'prefix/*/suffix')
3200
- end
3295
+ class PathUtilsTest < Minitest::Test
3296
+ def test_absolute_path_returns_unchanged
3297
+ absolute_path = "/usr/local/bin"
3298
+ expression = "path/to/*/directory"
3299
+ assert_equal absolute_path, PathUtils.resolve_path_or_substitute(absolute_path, expression)
3300
+ end
3201
3301
 
3202
- def test_substitutes_wildcard_with_path
3203
- path = 'bin'
3204
- expression = 'prefix/*/suffix'
3205
- expected_result = 'prefix/bin/suffix'
3206
- assert_equal expected_result, resolve_path_or_substitute(path, expression)
3207
- end
3302
+ def test_relative_path_gets_substituted
3303
+ relative_path = "my_folder"
3304
+ expression = "path/to/*/directory"
3305
+ expected_output = "path/to/my_folder/directory"
3306
+ assert_equal expected_output, PathUtils.resolve_path_or_substitute(relative_path, expression)
3307
+ end
3208
3308
 
3209
- def test_handles_path_with_no_separator_as_is
3210
- path = 'bin'
3211
- expression = 'prefix*suffix'
3212
- expected_result = 'prefixbinsuffix'
3213
- assert_equal expected_result, resolve_path_or_substitute(path, expression)
3214
- end
3309
+ def test_path_with_no_slash_substitutes_correctly
3310
+ relative_path = "data"
3311
+ expression = "path/to/*/directory"
3312
+ expected_output = "path/to/data/directory"
3313
+ assert_equal expected_output, PathUtils.resolve_path_or_substitute(relative_path, expression)
3314
+ end
3215
3315
 
3216
- def test_returns_expression_unchanged_for_empty_path
3217
- path = ''
3218
- expression = 'prefix/*/suffix'
3219
- expected_result = 'prefix/*/suffix'
3220
- assert_equal expected_result, resolve_path_or_substitute(path, expression)
3316
+ def test_empty_path_substitution
3317
+ empty_path = ""
3318
+ expression = "path/to/*/directory"
3319
+ expected_output = "path/to//directory"
3320
+ assert_equal expected_output, PathUtils.resolve_path_or_substitute(empty_path, expression)
3321
+ end
3221
3322
  end
3323
+
3222
3324
  end # module MarkdownExec
@@ -34,6 +34,7 @@ class InputSequencer
34
34
  prior_block_was_link: next_state.prior_block_was_link.nil? ? current.prior_block_was_link : next_state.prior_block_was_link
35
35
  )
36
36
  rescue
37
+ pp backtrace
37
38
  binding.irb
38
39
  end
39
40
 
@@ -75,11 +76,14 @@ class InputSequencer
75
76
 
76
77
  if now_menu.display_menu
77
78
  exit_when_bq_empty = false
78
-
79
79
  run_yield :display_menu, &block
80
80
 
81
81
  choice = run_yield :user_choice, &block
82
82
 
83
+ if choice.nil?
84
+ raise "Block not recognized."
85
+ break
86
+ end
83
87
  break if run_yield(:exit?, choice&.downcase, &block) # Exit loop and method to terminate the app
84
88
 
85
89
  next_state = run_yield :execute_block, choice, &block
@@ -115,6 +119,7 @@ class InputSequencer
115
119
  now_menu = InputSequencer.merge_link_state(now_menu, next_menu)
116
120
  end
117
121
  rescue
122
+ pp backtrace
118
123
  binding.irb
119
124
  end
120
125
  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.2'
10
+ VERSION = '2.0.3'
11
11
  end
data/lib/markdown_exec.rb CHANGED
@@ -10,7 +10,6 @@ require 'open3'
10
10
  require 'optparse'
11
11
  require 'shellwords'
12
12
  require 'tmpdir'
13
- # require 'tty-file'
14
13
  require 'tty-prompt'
15
14
  require 'yaml'
16
15
 
data/lib/menu.src.yml CHANGED
@@ -99,6 +99,12 @@
99
99
  :opt_name: display_level_xbase_prefix
100
100
  :procname: val_as_str
101
101
 
102
+ # - :default: "(document_link)"
103
+ # :description: Name of Link block to load with the document
104
+ # :env_var: MDE_DOCUMENT_LOAD_LINK_BLOCK_NAME
105
+ # :opt_name: document_load_link_block_name
106
+ # :procname: val_as_str
107
+
102
108
  - :default: "(document_options)"
103
109
  :description: Name of Opts block to load with the document
104
110
  :env_var: MDE_DOCUMENT_LOAD_OPTS_BLOCK_NAME
@@ -108,7 +114,6 @@
108
114
  - :arg_name: BOOL
109
115
  :default: false
110
116
  :description: Dump @delegate_object
111
- :env_var: MDE_DUMP_DELEGATE_OBJECT
112
117
  :long_name: dump-dump-delegate-object
113
118
  :opt_name: dump_delegate_object
114
119
  :procname: val_as_bool
@@ -116,7 +121,6 @@
116
121
  - :arg_name: BOOL
117
122
  :default: false
118
123
  :description: Dump BlocksInFile (stage 1)
119
- :env_var: MDE_DUMP_BLOCKS_IN_FILE
120
124
  :long_name: dump-blocks-in-file
121
125
  :opt_name: dump_blocks_in_file
122
126
  :procname: val_as_bool
@@ -124,7 +128,6 @@
124
128
  - :arg_name: BOOL
125
129
  :default: false
126
130
  :description: Dump inherited block_names
127
- :env_var: MDE_DUMP_INHERITED_BLOCK_NAMES
128
131
  :long_name: dump-dump-inherited-block_names
129
132
  :opt_name: dump_inherited_block_names
130
133
  :procname: val_as_bool
@@ -132,7 +135,6 @@
132
135
  - :arg_name: BOOL
133
136
  :default: false
134
137
  :description: Dump inherited dependencies
135
- :env_var: MDE_DUMP_INHERITED_DEPENDENCIES
136
138
  :long_name: dump-dump-inherited-dependencies
137
139
  :opt_name: dump_inherited_dependencies
138
140
  :procname: val_as_bool
@@ -140,7 +142,6 @@
140
142
  - :arg_name: BOOL
141
143
  :default: false
142
144
  :description: Dump inherited lines
143
- :env_var: MDE_DUMP_INHERITED_LINES
144
145
  :long_name: dump-dump-inherited-lines
145
146
  :opt_name: dump_inherited_lines
146
147
  :procname: val_as_bool
@@ -148,7 +149,6 @@
148
149
  - :arg_name: BOOL
149
150
  :default: false
150
151
  :description: Dump MenuBlocks (stage 2)
151
- :env_var: MDE_DUMP_MENU_BLOCKS
152
152
  :long_name: dump-menu-blocks
153
153
  :opt_name: dump_menu_blocks
154
154
  :procname: val_as_bool
@@ -156,7 +156,6 @@
156
156
  - :arg_name: BOOL
157
157
  :default: false
158
158
  :description: Dump selected block
159
- :env_var: MDE_DUMP_SELECTED_BLOCK
160
159
  :long_name: dump-selected-block
161
160
  :opt_name: dump_selected_block
162
161
  :procname: val_as_bool
@@ -206,35 +205,30 @@
206
205
  :opt_name: exclude_expect_blocks
207
206
  :procname: val_as_bool
208
207
 
208
+ # - :default: >
209
+ # osascript scripts/applescript/mde.applescript "%{batch_index}" "%{home}" " %{started_at} - %{document_filename} - %{block_name} " "%{script_filespec}" "%{output_filespec}"
209
210
  - :default: >
210
211
  osascript -e '
211
- tell application "iTerm"
212
- tell application "System Events"
213
- tell application "Finder"
214
- set {posx, posy, screenWidth, screenHeight} to bounds of window of desktop
215
- end tell
216
- tell application process "Finder"
217
- set {missing value, menubarHeight} to the size of menu bar 1
218
- end tell
219
- end tell
220
-
221
- set winHeight to (screenHeight * 2 / 3)
222
- set winWidth to (screenWidth * 2 / 3)
223
- set xoff to menubarHeight * %{batch_index}
224
- set yoff to xoff mod (screenHeight - winHeight)
225
-
226
- create window with default profile
227
- tell the first window
228
- set bounds to {xoff, yoff, xoff + winWidth, yoff + winHeight}
229
- tell the current session
230
- write text "s=\"%{script_filespec}\""
231
- write text "o=\"%{output_filespec}\""
232
- write text "cd \"%{home}\""
233
- write text "echo -ne \"\\033]; %{started_at} - %{document_filename} - %{block_name} \\007\""
234
- write text "\"$s\" | tee -a \"$o\""
235
- end tell
236
- end tell
237
- end tell'
212
+ on run argv
213
+ set batch_index to "%{batch_index}"
214
+ set home to "%{home}"
215
+ set output_filespec to "%{output_filespec}"
216
+ set script_filespec to "%{script_filespec}"
217
+ set title to " %{started_at} - %{document_filename} - %{block_name} "
218
+
219
+ tell application "iTerm"
220
+ create window with default profile
221
+ tell the first window
222
+ tell the current session
223
+ write text "s=" & quoted form of script_filespec & ""
224
+ write text "o=" & quoted form of output_filespec & ""
225
+ write text "cd " & quoted form of home & ""
226
+ write text "echo -ne \"\\033]; " & title & " \\007\""
227
+ write text "\"$s\" 2>&1 | tee -a \"$o\""
228
+ end tell
229
+ end tell
230
+ end tell
231
+ end run'
238
232
  :description: execute_command_format
239
233
  :env_var: MDE_EXECUTE_COMMAND_FORMAT
240
234
  :opt_name: execute_command_format
@@ -247,7 +241,7 @@
247
241
  :procname: val_as_str
248
242
 
249
243
  - :arg_name: BOOL
250
- :default: true
244
+ :default: false
251
245
  :description: Execute script in own window
252
246
  :env_var: MDE_EXECUTE_IN_OWN_WINDOW
253
247
  :opt_name: execute_in_own_window
@@ -301,7 +295,7 @@
301
295
 
302
296
  - :arg_name: FIND
303
297
  :default: ''
304
- :description: Find in documents
298
+ :description: Find argument in documents
305
299
  :long_name: find
306
300
  :procname: find
307
301
  :short_name: "?"
@@ -1056,8 +1050,8 @@
1056
1050
  :opt_name: select_by_shell_regex
1057
1051
  :procname: val_as_str
1058
1052
 
1059
- - :default: 36
1060
- :description: 'Maximum # of rows in select list'
1053
+ - :default: 0
1054
+ :description: 'Maximum # of rows in select list. Detects current limit if not specified.'
1061
1055
  :env_var: MDE_SELECT_PAGE_HEIGHT
1062
1056
  :opt_name: select_page_height
1063
1057
  :procname: val_as_int
data/lib/menu.yml CHANGED
@@ -1,4 +1,4 @@
1
- # MDE - Markdown Executor (2.0.2)
1
+ # MDE - Markdown Executor (2.0.3)
2
2
  ---
3
3
  - :description: Show current configuration values
4
4
  :procname: show_config
@@ -91,49 +91,42 @@
91
91
  - :arg_name: BOOL
92
92
  :default: false
93
93
  :description: Dump @delegate_object
94
- :env_var: MDE_DUMP_DELEGATE_OBJECT
95
94
  :long_name: dump-dump-delegate-object
96
95
  :opt_name: dump_delegate_object
97
96
  :procname: val_as_bool
98
97
  - :arg_name: BOOL
99
98
  :default: false
100
99
  :description: Dump BlocksInFile (stage 1)
101
- :env_var: MDE_DUMP_BLOCKS_IN_FILE
102
100
  :long_name: dump-blocks-in-file
103
101
  :opt_name: dump_blocks_in_file
104
102
  :procname: val_as_bool
105
103
  - :arg_name: BOOL
106
104
  :default: false
107
105
  :description: Dump inherited block_names
108
- :env_var: MDE_DUMP_INHERITED_BLOCK_NAMES
109
106
  :long_name: dump-dump-inherited-block_names
110
107
  :opt_name: dump_inherited_block_names
111
108
  :procname: val_as_bool
112
109
  - :arg_name: BOOL
113
110
  :default: false
114
111
  :description: Dump inherited dependencies
115
- :env_var: MDE_DUMP_INHERITED_DEPENDENCIES
116
112
  :long_name: dump-dump-inherited-dependencies
117
113
  :opt_name: dump_inherited_dependencies
118
114
  :procname: val_as_bool
119
115
  - :arg_name: BOOL
120
116
  :default: false
121
117
  :description: Dump inherited lines
122
- :env_var: MDE_DUMP_INHERITED_LINES
123
118
  :long_name: dump-dump-inherited-lines
124
119
  :opt_name: dump_inherited_lines
125
120
  :procname: val_as_bool
126
121
  - :arg_name: BOOL
127
122
  :default: false
128
123
  :description: Dump MenuBlocks (stage 2)
129
- :env_var: MDE_DUMP_MENU_BLOCKS
130
124
  :long_name: dump-menu-blocks
131
125
  :opt_name: dump_menu_blocks
132
126
  :procname: val_as_bool
133
127
  - :arg_name: BOOL
134
128
  :default: false
135
129
  :description: Dump selected block
136
- :env_var: MDE_DUMP_SELECTED_BLOCK
137
130
  :long_name: dump-selected-block
138
131
  :opt_name: dump_selected_block
139
132
  :procname: val_as_bool
@@ -177,21 +170,28 @@
177
170
  :env_var: MDE_EXCLUDE_EXPECT_BLOCKS
178
171
  :opt_name: exclude_expect_blocks
179
172
  :procname: val_as_bool
180
- - :default: "osascript -e '\n tell application \"iTerm\"\n tell application
181
- \"System Events\"\n tell application \"Finder\"\n set
182
- {posx, posy, screenWidth, screenHeight} to bounds of window of desktop\n end
183
- tell\n tell application process \"Finder\"\n set {missing
184
- value, menubarHeight} to the size of menu bar 1\n end tell\n end
185
- tell\n\n set winHeight to (screenHeight * 2 / 3)\n set winWidth
186
- to (screenWidth * 2 / 3)\n set xoff to menubarHeight * %{batch_index}\n
187
- \ set yoff to xoff mod (screenHeight - winHeight)\n \n create
188
- window with default profile\n tell the first window\n set bounds
189
- to {xoff, yoff, xoff + winWidth, yoff + winHeight}\n tell the current
190
- session\n write text \"s=\\\"%{script_filespec}\\\"\"\n write
191
- text \"o=\\\"%{output_filespec}\\\"\"\n write text \"cd \\\"%{home}\\\"\"\n
192
- \ write text \"echo -ne \\\"\\\\033]; %{started_at} - %{document_filename}
193
- - %{block_name} \\\\007\\\"\"\n write text \"\\\"$s\\\" | tee -a
194
- \\\"$o\\\"\"\n end tell\n end tell\n end tell'\n"
173
+ - :default: |
174
+ osascript -e '
175
+ on run argv
176
+ set batch_index to "%{batch_index}"
177
+ set home to "%{home}"
178
+ set output_filespec to "%{output_filespec}"
179
+ set script_filespec to "%{script_filespec}"
180
+ set title to " %{started_at} - %{document_filename} - %{block_name} "
181
+
182
+ tell application "iTerm"
183
+ create window with default profile
184
+ tell the first window
185
+ tell the current session
186
+ write text "s=" & quoted form of script_filespec & ""
187
+ write text "o=" & quoted form of output_filespec & ""
188
+ write text "cd " & quoted form of home & ""
189
+ write text "echo -ne \"\\033]; " & title & " \\007\""
190
+ write text "\"$s\" 2>&1 | tee -a \"$o\""
191
+ end tell
192
+ end tell
193
+ end tell
194
+ end run'
195
195
  :description: execute_command_format
196
196
  :env_var: MDE_EXECUTE_COMMAND_FORMAT
197
197
  :opt_name: execute_command_format
@@ -202,7 +202,7 @@
202
202
  :opt_name: execute_command_title_time_format
203
203
  :procname: val_as_str
204
204
  - :arg_name: BOOL
205
- :default: true
205
+ :default: false
206
206
  :description: Execute script in own window
207
207
  :env_var: MDE_EXECUTE_IN_OWN_WINDOW
208
208
  :opt_name: execute_in_own_window
@@ -249,7 +249,7 @@
249
249
  :short_name: f
250
250
  - :arg_name: FIND
251
251
  :default: ''
252
- :description: Find in documents
252
+ :description: Find argument in documents
253
253
  :long_name: find
254
254
  :procname: find
255
255
  :short_name: "?"
@@ -901,8 +901,8 @@
901
901
  :env_var: MDE_SELECT_BY_SHELL_REGEX
902
902
  :opt_name: select_by_shell_regex
903
903
  :procname: val_as_str
904
- - :default: 36
905
- :description: 'Maximum # of rows in select list'
904
+ - :default: 0
905
+ :description: 'Maximum # of rows in select list. Detects current limit if not specified.'
906
906
  :env_var: MDE_SELECT_PAGE_HEIGHT
907
907
  :opt_name: select_page_height
908
908
  :procname: val_as_int
data/lib/saved_assets.rb CHANGED
@@ -19,43 +19,45 @@ module MarkdownExec
19
19
  # Generates a formatted script name based on the provided parameters.
20
20
  def self.script_name(filename:, prefix:, time:, blockname:, ftime: DEFAULT_FTIME, join_str: '_', pattern: FNR11, replace: FNR12, exts: '.sh')
21
21
  fne = filename.gsub(pattern, replace)
22
- "#{[prefix, time.strftime(ftime), fne, ',', blockname].join(join_str)}#{exts}"
22
+ bne = blockname.gsub(pattern, replace)
23
+ "#{[prefix, time.strftime(ftime), fne, ',', bne].join(join_str)}#{exts}"
23
24
  end
24
25
 
25
26
  # Generates a formatted stdout name based on the provided parameters.
26
27
  def self.stdout_name(filename:, prefix:, time:, blockname:, ftime: DEFAULT_FTIME, join_str: '_', pattern: FNR11, replace: FNR12, exts: '.out.txt')
27
28
  fne = filename.gsub(pattern, replace)
28
- "#{[prefix, time.strftime(ftime), fne, ',', blockname].join(join_str)}#{exts}"
29
+ bne = blockname.gsub(pattern, replace)
30
+ "#{[prefix, time.strftime(ftime), fne, ',', bne].join(join_str)}#{exts}"
29
31
  end
30
32
  end
31
33
  end
32
34
 
33
- if $PROGRAM_NAME == __FILE__
34
- require 'minitest/autorun'
35
+ return if $PROGRAM_NAME != __FILE__
35
36
 
36
- class SavedAssetTest < Minitest::Test
37
- def test_script_name
38
- filename = 'sample.txt'
39
- prefix = 'test'
40
- time = Time.new(2023, 1, 1, 12, 0, 0) # Sample date-time for consistency in testing
41
- blockname = 'block1'
37
+ require 'minitest/autorun'
42
38
 
43
- expected_name = 'test_2023-01-01-12-00-00_sample.txt_,_block1.sh'
44
- assert_equal expected_name,
45
- MarkdownExec::SavedAsset.script_name(filename: filename, prefix: prefix, time: time,
46
- blockname: blockname)
47
- end
39
+ class SavedAssetTest < Minitest::Test
40
+ def test_script_name_with_special_characters_in_blockname
41
+ filename = 'sample.txt'
42
+ prefix = 'test'
43
+ time = Time.new(2023, 1, 1, 12, 0, 0)
44
+ blockname = 'block/1:2'
45
+
46
+ expected_name = 'test_2023-01-01-12-00-00_sample.txt_,_block_1_2.sh'
47
+ assert_equal expected_name, MarkdownExec::SavedAsset.script_name(
48
+ filename: filename, prefix: prefix, time: time, blockname: blockname
49
+ )
50
+ end
48
51
 
49
- def test_stdout_name
50
- filename = 'sample.txt'
51
- prefix = 'test'
52
- time = Time.new(2023, 1, 1, 12, 0, 0)
53
- blockname = 'block1'
52
+ def test_stdout_name_with_special_characters_in_blockname
53
+ filename = 'sample.txt'
54
+ prefix = 'test'
55
+ time = Time.new(2023, 1, 1, 12, 0, 0)
56
+ blockname = 'block/1:2'
54
57
 
55
- expected_name = 'test_2023-01-01-12-00-00_sample.txt_,_block1.out.txt'
56
- assert_equal expected_name,
57
- MarkdownExec::SavedAsset.stdout_name(filename: filename, prefix: prefix, time: time,
58
- blockname: blockname)
59
- end
58
+ expected_name = 'test_2023-01-01-12-00-00_sample.txt_,_block_1_2.out.txt'
59
+ assert_equal expected_name, MarkdownExec::SavedAsset.stdout_name(
60
+ filename: filename, prefix: prefix, time: time, blockname: blockname
61
+ )
60
62
  end
61
63
  end
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env -S bundle exec ruby
2
+ # frozen_string_literal: true
3
+
4
+ # encoding=utf-8
5
+ require 'logger'
6
+
7
+ # Logger::LogDevice is used by Logger, the parent class of StdOutErrLogger
8
+ class Logger::LogDevice
9
+ # remove header
10
+ def add_log_header(file); end
11
+ end
12
+
13
+ # Custom logger to direct info to stdout and warn and above to stderr
14
+ #
15
+ class StdOutErrLogger < Logger
16
+ attr_reader :file
17
+
18
+ # def initialize(file = nil)
19
+ def initialize(file = "#{__dir__}/../tmp/hash_delegator_next_link_state.yaml")
20
+ @file = file
21
+ super(file || STDOUT)
22
+ self.formatter = proc do |severity, datetime, progname, msg|
23
+ "#{msg}\n"
24
+ end
25
+ end
26
+
27
+ def add(severity, message = nil, progname = nil, &block)
28
+ message = (message || block&.call || progname) if message.nil?
29
+ message = "- #{message.to_json}\n"
30
+ ### message = message.join("\n") if message.is_a? Array
31
+ out = format_message(format_severity(severity), Time.now, progname, message)
32
+ if severity == Logger::UNKNOWN # does not follow spec, outputs to stderr for IO
33
+ # $stderr.puts(out)
34
+ super
35
+ elsif severity >= Logger::WARN
36
+ if @file
37
+ super
38
+ else
39
+ $stderr.puts(out)
40
+ end
41
+ else
42
+ if @file
43
+ super
44
+ else
45
+ $stdout.puts(out)
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ return if $PROGRAM_NAME != __FILE__
52
+
53
+ require 'minitest/autorun'
54
+
55
+ class StdOutErrLoggerTest < Minitest::Test
56
+ # Redirect STDOUT and STDERR to capture them for assertions
57
+ def setup
58
+ @original_stdout = $stdout
59
+ @original_stderr = $stderr
60
+ $stdout = StringIO.new
61
+ $stderr = StringIO.new
62
+ end
63
+
64
+ def teardown
65
+ $stdout = @original_stdout
66
+ $stderr = @original_stderr
67
+ end
68
+
69
+ def test_initialize_without_file
70
+ logger = StdOutErrLogger.new
71
+ assert_nil logger.file
72
+ assert_equal Logger::DEBUG, logger.level
73
+ end
74
+
75
+ def test_initialize_with_file
76
+ Tempfile.open do |file|
77
+ logger = StdOutErrLogger.new(file.path)
78
+ assert_equal file.path, logger.file
79
+ end
80
+ end
81
+
82
+ def test_logging_info
83
+ logger = StdOutErrLogger.new
84
+ logger.info("Info message")
85
+ assert_equal "Info message\n", $stdout.string
86
+ assert_empty $stderr.string
87
+ end
88
+
89
+ def test_logging_warning
90
+ logger = StdOutErrLogger.new
91
+ logger.warn("Warning message")
92
+ assert_empty $stdout.string
93
+ assert_equal "Warning message\n", $stderr.string
94
+ end
95
+
96
+ def test_logging_error
97
+ logger = StdOutErrLogger.new
98
+ logger.error("Error message")
99
+ assert_empty $stdout.string
100
+ assert_equal "Error message\n", $stderr.string
101
+ end
102
+
103
+ def test_logging_with_array
104
+ logger = StdOutErrLogger.new
105
+ logger.info(["Message line 1", "Message line 2"])
106
+ assert_equal "Message line 1\nMessage line 2\n", $stdout.string
107
+ end
108
+
109
+ def test_logging_with_block
110
+ logger = StdOutErrLogger.new
111
+ logger.info { "Block message" }
112
+ assert_equal "Block message\n", $stdout.string
113
+ end
114
+
115
+ def test_logging_unknown_severity
116
+ logger = StdOutErrLogger.new
117
+ logger.add(Logger::UNKNOWN, "Unknown severity message")
118
+ assert_empty $stdout.string
119
+ assert_equal "Unknown severity message\n", $stderr.string
120
+ end
121
+ 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.2
4
+ version: 2.0.3
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-02-09 00:00:00.000000000 Z
11
+ date: 2024-04-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: clipboard
@@ -169,6 +169,7 @@ files:
169
169
  - lib/saved_assets.rb
170
170
  - lib/saved_files_matcher.rb
171
171
  - lib/shared.rb
172
+ - lib/std_out_err_logger.rb
172
173
  - lib/string_util.rb
173
174
  - lib/tap.rb
174
175
  homepage: https://rubygems.org/gems/markdown_exec