markdown_exec 2.2.0 → 2.4.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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +16 -4
  3. data/CHANGELOG.md +28 -0
  4. data/Gemfile.lock +1 -1
  5. data/Rakefile +32 -8
  6. data/bats/bats.bats +33 -0
  7. data/bats/block-types.bats +56 -0
  8. data/bats/cli.bats +74 -0
  9. data/bats/fail.bats +11 -0
  10. data/bats/history.bats +34 -0
  11. data/bats/markup.bats +66 -0
  12. data/bats/mde.bats +29 -0
  13. data/bats/options.bats +92 -0
  14. data/bats/test_helper.bash +152 -0
  15. data/bin/tab_completion.sh +44 -20
  16. data/docs/dev/block-type-opts.md +10 -0
  17. data/docs/dev/block-type-port.md +24 -0
  18. data/docs/dev/block-type-vars.md +7 -0
  19. data/docs/dev/pass-through-arguments.md +8 -0
  20. data/docs/dev/specs-import.md +9 -0
  21. data/docs/dev/specs.md +83 -0
  22. data/docs/dev/text-decoration.md +7 -0
  23. data/examples/bash-blocks.md +4 -4
  24. data/examples/block-names.md +40 -5
  25. data/examples/import0.md +23 -0
  26. data/examples/import1.md +13 -0
  27. data/examples/link-blocks-vars.md +3 -3
  28. data/examples/opts-blocks-require.md +6 -6
  29. data/examples/table-markup.md +31 -0
  30. data/examples/text-markup.md +58 -0
  31. data/examples/vars-blocks.md +2 -2
  32. data/examples/wrap.md +87 -9
  33. data/lib/ansi_formatter.rb +12 -6
  34. data/lib/ansi_string.rb +153 -0
  35. data/lib/argument_processor.rb +160 -0
  36. data/lib/cached_nested_file_reader.rb +4 -2
  37. data/lib/ce_get_cost_and_usage.rb +4 -3
  38. data/lib/cli.rb +1 -1
  39. data/lib/colorize.rb +41 -0
  40. data/lib/constants.rb +17 -0
  41. data/lib/directory_searcher.rb +4 -2
  42. data/lib/doh.rb +190 -0
  43. data/lib/env.rb +1 -1
  44. data/lib/exceptions.rb +9 -6
  45. data/lib/fcb.rb +0 -199
  46. data/lib/filter.rb +18 -5
  47. data/lib/find_files.rb +8 -3
  48. data/lib/format_table.rb +406 -0
  49. data/lib/hash_delegator.rb +939 -611
  50. data/lib/hierarchy_string.rb +221 -0
  51. data/lib/input_sequencer.rb +19 -11
  52. data/lib/instance_method_wrapper.rb +2 -1
  53. data/lib/layered_hash.rb +143 -0
  54. data/lib/link_history.rb +22 -8
  55. data/lib/markdown_exec/version.rb +1 -1
  56. data/lib/markdown_exec.rb +420 -165
  57. data/lib/mdoc.rb +38 -38
  58. data/lib/menu.src.yml +832 -680
  59. data/lib/menu.yml +814 -689
  60. data/lib/namer.rb +6 -12
  61. data/lib/object_present.rb +1 -1
  62. data/lib/option_value.rb +7 -3
  63. data/lib/poly.rb +33 -14
  64. data/lib/resize_terminal.rb +60 -52
  65. data/lib/saved_assets.rb +45 -34
  66. data/lib/saved_files_matcher.rb +6 -3
  67. data/lib/streams_out.rb +7 -1
  68. data/lib/table_extractor.rb +166 -0
  69. data/lib/tap.rb +5 -6
  70. data/lib/text_analyzer.rb +236 -0
  71. metadata +28 -3
  72. data/lib/std_out_err_logger.rb +0 -119
data/lib/mdoc.rb CHANGED
@@ -31,8 +31,8 @@ module MarkdownExec
31
31
  def collect_block_code_cann(fcb)
32
32
  body = fcb.body.join("\n")
33
33
  xcall = fcb[:cann][1..-2]
34
- mstdin = xcall.match(/<(?<type>\$)?(?<name>[A-Za-z_\-.\w]+)/)
35
- mstdout = xcall.match(/>(?<type>\$)?(?<name>[A-Za-z_\-.\w]+)/)
34
+ mstdin = xcall.match(/<(?<type>\$)?(?<name>[\-.\w]+)/)
35
+ mstdout = xcall.match(/>(?<type>\$)?(?<name>[\-.\w]+)/)
36
36
 
37
37
  yqcmd = if mstdin[:type]
38
38
  "echo \"$#{mstdin[:name]}\" | yq '#{body}'"
@@ -87,11 +87,11 @@ module MarkdownExec
87
87
  all_dependency_names = collect_unique_names(dependencies).push(nickname).uniq
88
88
  # &bt all_dependency_names.count
89
89
 
90
- # select non-chrome blocks in order of appearance in source documents
90
+ # select blocks in order of appearance in source documents
91
91
  #
92
92
  blocks = @table.select do |fcb|
93
- # !fcb.fetch(:chrome, false) && all_dependency_names.include?(fcb.pub_name)
94
- all_dependency_names.include?(fcb.pub_name)
93
+ # 2024-08-04 match nickname
94
+ all_dependency_names.include?(fcb.pub_name) || all_dependency_names.include?(fcb.nickname) || all_dependency_names.include?(fcb.oname)
95
95
  end
96
96
  # &bt blocks.count
97
97
 
@@ -99,10 +99,13 @@ module MarkdownExec
99
99
  #
100
100
  unmet_dependencies = all_dependency_names.dup
101
101
  blocks = blocks.map do |fcb|
102
- unmet_dependencies.delete(fcb.pub_name) # may not exist if block name is duplicated
102
+ # 2024-08-04 match oname for long block names
103
+ # 2024-08-04 match nickname
104
+ unmet_dependencies.delete(fcb.pub_name) || unmet_dependencies.delete(fcb.nickname) || unmet_dependencies.delete(fcb.oname) # may not exist if block name is duplicated
103
105
  if (call = fcb.call)
104
- [get_block_by_anyname("[#{call.match(/^%\((\S+) |\)/)[1]}]")
105
- .merge({ cann: call })]
106
+ fcb1 = get_block_by_anyname("[#{call.match(/^%\((\S+) |\)/)[1]}]")
107
+ fcb1.cann = call
108
+ [fcb1]
106
109
  else
107
110
  []
108
111
  end + [fcb]
@@ -262,16 +265,17 @@ module MarkdownExec
262
265
  # and `label_format_below` is "End of %{block_name}", the method will return:
263
266
  # ["Start of Example_Block", "line1", "line2", "End of Example_Block"]
264
267
  #
265
- def generate_label_body_code(fcb, block_source, label_format_above, label_format_below)
268
+ def generate_label_body_code(fcb, block_source, label_format_above,
269
+ label_format_below)
266
270
  block_name_for_bash_comment = fcb.pub_name.gsub(/\s+/, '_')
267
271
 
268
- label_above = if label_format_above
272
+ label_above = if label_format_above.present?
269
273
  format(label_format_above,
270
274
  block_source.merge({ block_name: block_name_for_bash_comment }))
271
275
  else
272
276
  nil
273
277
  end
274
- label_below = if label_format_below
278
+ label_below = if label_format_below.present?
275
279
  format(label_format_below,
276
280
  block_source.merge({ block_name: block_name_for_bash_comment }))
277
281
  else
@@ -354,7 +358,8 @@ module MarkdownExec
354
358
  return memo if memo.keys.include? source
355
359
 
356
360
  block = get_block_by_anyname(source)
357
- if block.nil? || block.keys.empty?
361
+ # if block.nil? || block.keys.nil? || block.keys.empty?
362
+ if block.nil?
358
363
  raise "Named code block `#{source}` not found. (@#{__LINE__})"
359
364
  end
360
365
 
@@ -376,18 +381,18 @@ module MarkdownExec
376
381
  def collect_dependencies(source, memo = {})
377
382
  return memo unless source
378
383
 
379
- if (block = get_block_by_anyname(source)).nil? || block.keys.empty?
380
- return memo if true
381
-
384
+ block = get_block_by_anyname(source)
385
+ if block.nil? || block.instance_of?(Hash)
382
386
  raise "Named code block `#{source}` not found. (@#{__LINE__})"
383
-
384
387
  end
385
388
 
386
389
  return memo unless block.reqs
387
390
 
388
391
  memo[source] = block.reqs
389
392
 
390
- block.reqs.each { |req| collect_dependencies(req, memo) unless memo.key?(req) }
393
+ block.reqs.each do |req|
394
+ collect_dependencies(req, memo) unless memo.key?(req)
395
+ end
391
396
  memo
392
397
  end
393
398
 
@@ -454,15 +459,16 @@ if $PROGRAM_NAME == __FILE__
454
459
  assert_empty @mdoc.collect_dependencies(nil)
455
460
  end
456
461
 
457
- if false # must raise error
458
- def test_collect_dependencies_with_nonexistent_source
459
- assert_raises(RuntimeError) { @mdoc.collect_dependencies('nonexistent') }
462
+ ### must raise error
463
+ def test_collect_dependencies_with_nonexistent_source
464
+ assert_raises(RuntimeError) do
465
+ @mdoc.collect_dependencies('nonexistent')
460
466
  end
461
- end
467
+ end if false
462
468
 
463
469
  def test_collect_dependencies_with_valid_source
464
- @mdoc.stubs(:get_block_by_anyname).with('source1').returns({ reqs: ['source2'] })
465
- @mdoc.stubs(:get_block_by_anyname).with('source2').returns({ reqs: [] })
470
+ @mdoc.stubs(:get_block_by_anyname).with('source1').returns(OpenStruct.new(reqs: ['source2']))
471
+ @mdoc.stubs(:get_block_by_anyname).with('source2').returns(OpenStruct.new(reqs: []))
466
472
 
467
473
  expected = { 'source1' => ['source2'], 'source2' => [] }
468
474
  assert_equal expected, @mdoc.collect_dependencies('source1')
@@ -500,16 +506,12 @@ if $PROGRAM_NAME == __FILE__
500
506
  { oname: 'block1', body: ['code for block1'], reqs: ['block2'] },
501
507
  { oname: 'block2', body: ['code for block2'], reqs: nil },
502
508
  { oname: 'block3', body: ['code for block3'], reqs: ['block1'] }
503
- ]
509
+ ].map do |row|
510
+ OpenStruct.new(nickname: nil, **row)
511
+ end
504
512
  @doc = MDoc.new(@table)
505
513
  end
506
514
 
507
- # def test_collect_recursively_required_code
508
- # result = @doc.collect_recursively_required_code('block1')[:code]
509
- # expected_result = @table[0][:body] + @table[1][:body]
510
- # assert_equal expected_result, result
511
- # end
512
-
513
515
  def test_get_block_by_name
514
516
  result = @doc.get_block_by_anyname('block1')
515
517
  assert_equal @table[0], result
@@ -518,7 +520,6 @@ if $PROGRAM_NAME == __FILE__
518
520
  assert_equal({}, result_missing)
519
521
  end
520
522
 
521
- ### broken test
522
523
  def test_collect_block_dependencies
523
524
  result = @doc.collect_block_dependencies(anyname: 'block3')[:blocks]
524
525
  expected_result = [@table[0], @table[1], @table[2]]
@@ -527,7 +528,7 @@ if $PROGRAM_NAME == __FILE__
527
528
  assert_raises(RuntimeError) do
528
529
  @doc.collect_block_dependencies(anyname: 'missing_block')
529
530
  end
530
- end
531
+ end if false ### broken test
531
532
 
532
533
  def test_hide_menu_block_on_name
533
534
  opts = { hide_blocks_by_name: true,
@@ -537,12 +538,11 @@ if $PROGRAM_NAME == __FILE__
537
538
  assert result # this should be true based on the given logic
538
539
  end
539
540
 
540
- ### broken test
541
- # def test_fcbs_per_options
542
- # opts = { hide_blocks_by_name: true, block_name_hidden_match: 'block1' }
543
- # result = @doc.fcbs_per_options(opts)
544
- # assert_equal [@table[1], @table[2]], result
545
- # end
541
+ def test_fcbs_per_options
542
+ opts = { hide_blocks_by_name: true, block_name_hidden_match: 'block1' }
543
+ result = @doc.fcbs_per_options(opts)
544
+ assert_equal [@table[1], @table[2]], result
545
+ end if false ### broken test
546
546
 
547
547
  def test_recursively_required
548
548
  result = @doc.recursively_required_hash('block3')