markdown_exec 2.8.4 → 2.8.5

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: 7ace0bdaa8d2925a4274a4cfc039fdde5e9aaaf8bfbd761f21e0679417f71062
4
- data.tar.gz: 0a9f38be8b322be828fe28cd19441da7a9bb032dd739aaa73ba0526456251503
3
+ metadata.gz: 718a29bb9eed1123158ffab68a01866fcdbc0126736c5305eae92dd661fb7396
4
+ data.tar.gz: 05e374bda6ac5603b13d50a33ef36cffd25d8fccdf43733107d63d19395ee9a5
5
5
  SHA512:
6
- metadata.gz: b0c0c4eea966bad0e29e0957e68049cfee1c61bd730fab880f63ea1501cba153dd1592ef415142a91a9aecd09802cf0bb48eac36607964b97ce372c9b249536f
7
- data.tar.gz: d254a22305dd0d57f2048271d40f15d22b6f2473971cc3c398a6479d439fe80255f0dabb7cb94f9df8c21bc6214b2f60b5238c102e3048cbdbd3dd3dd18b693a
6
+ metadata.gz: 18629932f2c6b095329f56ec594eb1016df88b17278ef544f6954f793f054e55c137b8240692392ebba9165c15e0f58b6c1e3883447fa740c90fa1fccb20f351
7
+ data.tar.gz: bc1e0a9ea38227dc83136f2884934ed6dfed93a4c1e73c4c1faa8a6188b2bc7a197062d356f2e3ff5665629e04de46d40904191de9d23af9b6ba31c9f26953d5
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.8.5] - 2025-04-07
4
+
5
+ ### Added
6
+
7
+ - Opts blocks can require other Opts blocks.
8
+ - Options to enable the change of shell expansion patterns.
9
+ - Default ID to each FCB.
10
+ - Convert the value of the 'echo' key to a string.
11
+ - All UX blocks are now loaded automatically.
12
+
13
+ ### Changed
14
+
15
+ - Make 'default' key optional for UX blocks.
16
+ - Use the 'default' option to specify the initial computed value.
17
+
3
18
  ## [2.8.4] - 2025-03-24
4
19
 
5
20
  ### Added
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- markdown_exec (2.8.4)
4
+ markdown_exec (2.8.5)
5
5
  clipboard (~> 1.3.6)
6
6
  open3 (~> 0.1.1)
7
7
  optparse (~> 0.1.1)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bats
2
+
3
+ load 'test_helper'
4
+
5
+ @test 'Initial values' {
6
+ spec_mde_xansi_dname_doc_blocks_expect docs/dev/block-type-ux-default.md \
7
+ 'v1 = _v2 = 11_v3 = 12_v4 = 21_v5 = markdown_exec__v6 = 31'
8
+ }
@@ -18,6 +18,7 @@ name: GENUS
18
18
  allowed:
19
19
  - Hominidae
20
20
  - Antennariidae
21
+ default: ''
21
22
  name: FAMILY
22
23
  ```
23
24
  / automatic block loads default value that is not in allowed list
@@ -40,6 +41,7 @@ name: CLASS
40
41
  / executed block presents a menu of the lines in the output of exec
41
42
  ```ux :[YEAR_DISCOVERED]
42
43
  allowed: :exec
44
+ default: ''
43
45
  exec: echo "2017\n2009"
44
46
  name: YEAR_DISCOVERED
45
47
  ```
@@ -6,7 +6,8 @@ name: v1
6
6
  / name and default
7
7
  / transform and validate options not applied to default
8
8
  ```ux
9
- default: 11
9
+ default: ''
10
+ echo: 11
10
11
  name: v2
11
12
  ```
12
13
  / name and default; auto-load
@@ -0,0 +1,42 @@
1
+ / v2025-02-08
2
+ / name only
3
+ ```ux
4
+ name: v1
5
+ ```
6
+ / name and default
7
+ / transform and validate options not applied to default
8
+ ```ux
9
+ default: 11
10
+ name: v2
11
+ ```
12
+ / name and default; auto-load
13
+ / prompt option is ignored during auto-load
14
+ ```ux :[document_ux_v3]
15
+ echo: 12
16
+ name: v3
17
+ ```
18
+ / name, default, exec; auto-load static
19
+ ```ux :[document_ux_v4]
20
+ default: 21
21
+ exec: basename $(pwd)
22
+ name: v4
23
+ ```
24
+ / name, default, exec; auto-load executed `basename $(pwd)`
25
+ / allowed is ignored by exec
26
+ ```ux :[document_ux_v5]
27
+ exec: basename $(pwd)
28
+ name: v5
29
+ ```
30
+ / name, default, allowed; auto-load static default
31
+ ```ux :[document_ux_v6]
32
+ allowed:
33
+ - 31
34
+ - 32
35
+ - 33
36
+ name: v6
37
+ ```
38
+ @import bats-document-configuration.md
39
+ ```opts :(document_opts)
40
+ menu_ux_row_format: '%{name} = ${%{name}}'
41
+ ux_auto_load_force_default: true
42
+ ```
@@ -10,16 +10,19 @@ readonly: true
10
10
  ```
11
11
  / This block displays the second variable in the first block.
12
12
  ```ux :[DOCUMENTS]
13
+ default: false
13
14
  name: DOCUMENTS
14
15
  readonly: true
15
16
  ```
16
17
  / This block displays the third variable in the first block.
17
18
  ```ux :[OPERATION]
19
+ default: false
18
20
  name: OPERATION
19
21
  readonly: true
20
22
  ```
21
23
  / Multiple UX blocks to set many variables for a specific name.
22
24
  ```ux
25
+ default: false
23
26
  echo:
24
27
  Species: Pongo tapanuliensis
25
28
  Genus: Pongo
@@ -34,6 +37,7 @@ menu_format: 'Load %{name}'
34
37
  name: Tapanuli Orangutan
35
38
  ```
36
39
  ```ux
40
+ default: false
37
41
  echo:
38
42
  Species: Histiophryne psychedelica
39
43
  Genus: Histiophryne
@@ -52,6 +56,7 @@ name: Psychedelic Frogfish
52
56
  | -| -
53
57
  / A read-only variable in a UX block in a table
54
58
  ```ux
59
+ default: false
55
60
  menu_format: '| %{name}| ${%{name}}'
56
61
  name: Species
57
62
  readonly: true
@@ -60,6 +65,7 @@ readonly: true
60
65
  | Genus| ${Genus}
61
66
  / An editable variable in a UX block in a table
62
67
  ```ux
68
+ default: false
63
69
  menu_format: '| %{name}| ${%{name}}'
64
70
  name: Family
65
71
  ```
@@ -1,6 +1,5 @@
1
1
  / This automatic block sets VAR and displays the current value in the menu.
2
2
  ```ux :[document_ux_VAR]
3
- default: :echo
4
3
  echo: $(basename `pwd`)
5
4
  name: VAR
6
5
  ```
@@ -10,11 +9,14 @@ menu_with_inherited_lines: true
10
9
  ```
11
10
  / This block is not visible. Execute to set a new value, displayed by the block above.
12
11
  ```ux :(VAR_has_count)
12
+ default: false
13
13
  echo: $(basename `pwd` | wc -c)
14
+ force: false
14
15
  name: VAR
15
16
  ```
16
17
  / This block is visible. Execute to set a new value, displayed by the block above.
17
18
  ```ux :[IAB_has_count]
19
+ default: false
18
20
  echo: $VAR$VAR
19
21
  name: IAB
20
22
  ```
@@ -1,6 +1,7 @@
1
1
  / auto-load block, does not execute command to calculate
2
2
  / click block to calculate
3
3
  ```ux :[document_ux0]
4
+ default: ''
4
5
  exec: basename $(pwd)
5
6
  name: ux0
6
7
  ```
@@ -1,32 +1,23 @@
1
- / an automatic UX block requires a shell block and another UX block
1
+ / This is an hidden shell block that is required by UX blocks.
2
2
  ``` :(shell)
3
3
  ENTITY='Pongo tapanuliensis,Pongo'
4
4
  ```
5
- ```ux :[document_ux_SPECIES] +(shell) +[ux_GENUS]
6
- default: :exec
7
- exec: echo "${ENTITY%%,*}"
5
+ ```ux +(shell)
6
+ echo: "${ENTITY%%,*}"
8
7
  name: SPECIES
9
- transform: :chomp
10
8
  ```
11
- / required ux block requires another
12
- ```ux :[ux_GENUS] +[ux_NAME]
13
- default: :exec
14
- exec: echo "${ENTITY##*,}"
9
+ ```ux +(shell)
10
+ echo: "${ENTITY##*,}"
15
11
  name: GENUS
16
- transform: :chomp
17
12
  ```
18
13
  / executed in context of prior ux blocks, uses their initial values
19
- ```ux :[ux_NAME]
20
- default: :exec
21
- exec: echo "$SPECIES - $GENUS"
14
+ ```ux
15
+ echo: "$SPECIES - $GENUS"
22
16
  name: NAME
23
- transform: :chomp
24
17
  ```
25
18
  / executed after other ux blocks, uses their initial values
26
- ```ux :[document_ux_NAME2]
27
- default: :exec
28
- exec: echo "$NAME"
19
+ ```ux
20
+ echo: "$NAME"
29
21
  name: NAME2
30
- transform: :chomp
31
22
  ```
32
23
  @import bats-document-configuration.md
data/lib/fcb.rb CHANGED
@@ -48,6 +48,7 @@ module MarkdownExec
48
48
  call: nil,
49
49
  dname: nil,
50
50
  headings: [],
51
+ id: object_id,
51
52
  indent: '',
52
53
  name: nil,
53
54
  nickname: nil,
@@ -62,6 +63,15 @@ module MarkdownExec
62
63
  }.merge(options)
63
64
  end
64
65
 
66
+ def pub_name(**kwargs)
67
+ self.class.pub_name(@attrs, **kwargs)
68
+ end
69
+
70
+ def self.pub_name(attrs, **kwargs)
71
+ full = attrs.fetch(:nickname, nil) || attrs.fetch(:oname, nil)
72
+ full&.to_s&.pub_name(**kwargs)
73
+ end
74
+
65
75
  def code_name_included?(*names)
66
76
  names.include?(@attrs[:oname])
67
77
  end
@@ -331,13 +341,15 @@ if $PROGRAM_NAME == __FILE__
331
341
  end
332
342
 
333
343
  def test_to_h_method
334
- assert_equal_hash @fcb_data.merge({ random: @fcb.random }), @fcb.to_h
344
+ assert_equal_hash @fcb_data.merge(
345
+ { id: @fcb.id, random: @fcb.random }
346
+ ), @fcb.to_h
335
347
  end
336
348
 
337
349
  def test_to_yaml_method
338
- assert_equal_hash YAML.load(@fcb_data.merge({ random: @fcb.random })
339
- .to_yaml),
340
- YAML.load(@fcb.to_yaml)
350
+ assert_equal_hash YAML.load(@fcb_data.merge(
351
+ { id: @fcb.id, random: @fcb.random }
352
+ ).to_yaml), YAML.load(@fcb.to_yaml)
341
353
  end
342
354
 
343
355
  def test_method_missing_getter
@@ -1002,6 +1002,37 @@ module MarkdownExec
1002
1002
  output.split("\n")
1003
1003
  end
1004
1004
 
1005
+ def code_from_automatic_ux_blocks(
1006
+ all_blocks,
1007
+ mdoc
1008
+ )
1009
+ unless @ux_most_recent_filename != @delegate_object[:filename]
1010
+ return
1011
+ end
1012
+
1013
+ blocks = select_automatic_ux_blocks(all_blocks)
1014
+ if blocks.empty?
1015
+ blocks = select_automatic_ux_blocks(all_blocks)
1016
+ end
1017
+ return if blocks.empty?
1018
+
1019
+ @ux_most_recent_filename = @delegate_object[:filename]
1020
+
1021
+ (blocks.each.with_object([]) do |block, merged_options|
1022
+ code = code_from_ux_block_to_set_environment_variables(
1023
+ block,
1024
+ mdoc,
1025
+ force: @delegate_object[:ux_auto_load_force_default],
1026
+ only_default: true
1027
+ )
1028
+ if code == :ux_exec_prohibited
1029
+ merged_options
1030
+ else
1031
+ merged_options.push(code)
1032
+ end
1033
+ end).to_a
1034
+ end
1035
+
1005
1036
  # parse YAML body defining the UX for a single variable
1006
1037
  # set ENV value for the variable and return code lines for the same
1007
1038
  def code_from_ux_block_to_set_environment_variables(
@@ -1300,7 +1331,7 @@ module MarkdownExec
1300
1331
  )
1301
1332
  # Initialize a counter for named group occurrences
1302
1333
  occurrence_count = Hash.new(0)
1303
- return occurrence_count if pattern == //
1334
+ return occurrence_count if pattern.nil? || pattern == //
1304
1335
 
1305
1336
  blocks.each do |block|
1306
1337
  # Skip processing for shell-type blocks
@@ -1318,7 +1349,7 @@ module MarkdownExec
1318
1349
 
1319
1350
  def count_named_group_occurrences_block_body_fix_indent(block)
1320
1351
  ### actually double the entries, but not a problem since it's used as a boolean
1321
- ([block.oname || ''] + block.body).join("\n")
1352
+ ([block.oname || ''] + (block.body || [''])).join("\n")
1322
1353
  end
1323
1354
 
1324
1355
  ##
@@ -1366,9 +1397,9 @@ module MarkdownExec
1366
1397
  # split text with newlines, from variable expansion
1367
1398
  if line_cap[:text].include?("\n")
1368
1399
  lines = line_cap[:text].split("\n")
1369
- line_caps = (lines.map do |line|
1370
- line_cap.dup.merge(text: line)
1371
- end.to_a)
1400
+ line_caps = lines.map do |line|
1401
+ line_cap.dup.merge(text: line)
1402
+ end.to_a
1372
1403
  end
1373
1404
 
1374
1405
  # wrap text on multiple lines to screen width, replacing line_caps
@@ -1376,7 +1407,7 @@ module MarkdownExec
1376
1407
  line_caps = line_caps.flat_map do |line_cap|
1377
1408
  text = line_cap[:text]
1378
1409
  wrapper = StringWrapper.new(width: screen_width_for_wrapping - line_cap[:indent].length)
1379
-
1410
+
1380
1411
  if text.length > screen_width_for_wrapping
1381
1412
  # Wrap this text and create line_cap objects for each part
1382
1413
  wrapper.wrap(text).map do |wrapped_text|
@@ -1486,7 +1517,9 @@ module MarkdownExec
1486
1517
  yield if block_given?
1487
1518
 
1488
1519
  # parse multiline to capture output of variable expansion
1489
- mbody = fcb.body[0].match Regexp.new(@delegate_object[criteria[:match]], Regexp::MULTILINE)
1520
+ mbody = fcb.body[0].match Regexp.new(
1521
+ @delegate_object[criteria[:match]], Regexp::MULTILINE
1522
+ )
1490
1523
  end
1491
1524
 
1492
1525
  create_and_add_chrome_block(
@@ -2406,14 +2439,16 @@ module MarkdownExec
2406
2439
  expand_variable_references!(
2407
2440
  blocks: [fcb],
2408
2441
  initial_code_required: false,
2409
- link_state: link_state
2442
+ key_format: @delegate_object[:variable_expression_format],
2443
+ link_state: link_state,
2444
+ pattern: options_variable_expression_regexp
2410
2445
  )
2411
2446
  expand_variable_references!(
2412
2447
  blocks: [fcb],
2413
2448
  echo_format: '%s',
2414
2449
  group_name: :command,
2415
2450
  initial_code_required: false,
2416
- key_format: '$(%s)',
2451
+ key_format: @delegate_object[:command_substitution_format],
2417
2452
  link_state: link_state,
2418
2453
  pattern: options_command_substitution_regexp
2419
2454
  )
@@ -2424,13 +2459,10 @@ module MarkdownExec
2424
2459
  echo_format: 'echo "$%s"',
2425
2460
  group_name: :variable,
2426
2461
  initial_code_required: false,
2427
- key_format: '${%s}',
2462
+ key_format:,
2428
2463
  link_state:,
2429
- pattern: nil
2464
+ pattern:
2430
2465
  )
2431
- pattern ||= options_variable_expression_regexp
2432
- return if pattern.nil?
2433
-
2434
2466
  variable_counts = count_named_group_occurrences(blocks, pattern,
2435
2467
  group_name: group_name)
2436
2468
  return if variable_counts.nil? || variable_counts == {}
@@ -2467,8 +2499,8 @@ module MarkdownExec
2467
2499
  force:)
2468
2500
  exportable = true
2469
2501
  case export.echo
2470
- when String
2471
- value = export_echo_with_code_single(export.echo, inherited_code,
2502
+ when String, Integer, Float, TrueClass, FalseClass
2503
+ value = export_echo_with_code_single(export.echo.to_s, inherited_code,
2472
2504
  code_lines, required)
2473
2505
  when Hash
2474
2506
  # each item in the hash is a variable name and value
@@ -2952,69 +2984,45 @@ module MarkdownExec
2952
2984
  @fout.fout_list(list)
2953
2985
  end
2954
2986
 
2955
- # Loads auto blocks based on delegate object settings and updates
2956
- # if new filename is detected.
2957
- # Executes a specified block once per filename.
2958
- # @param all_blocks [Array] Array of all block elements.
2959
- # @return [Boolean, nil] True if values were modified, nil otherwise.
2987
+ # Loads and updates auto options for document blocks if the current filename has changed.
2988
+ #
2989
+ # This method checks if the delegate object specifies a document load options block name and if the filename
2990
+ # has been updated. It then selects the appropriate blocks, collects their dependencies, processes their
2991
+ # options, and updates the menu base with the merged options.
2992
+ #
2993
+ # @param all_blocks [Array] An array of all block elements.
2994
+ # @param mdoc [Object] The document object managing dependencies and options.
2995
+ # @return [Boolean, nil] Returns true if options were updated; nil otherwise.
2960
2996
  def load_auto_opts_block(all_blocks, mdoc:)
2961
- block_name = @delegate_object[:document_load_opts_block_name]
2962
- unless block_name.present? &&
2963
- @opts_most_recent_filename != @delegate_object[:filename]
2964
- return
2965
- end
2997
+ opts_block_name = @delegate_object[:document_load_opts_block_name]
2998
+ current_filename = @delegate_object[:filename]
2966
2999
 
2967
- blocks = HashDelegator.block_select(all_blocks, :oname, block_name)
2968
- return if blocks.empty?
3000
+ return unless opts_block_name.present? &&
3001
+ @opts_most_recent_filename != current_filename
3002
+
3003
+ selected_blocks = HashDelegator.block_select(all_blocks, :oname,
3004
+ opts_block_name)
3005
+ return if selected_blocks.empty?
3006
+
3007
+ dependency_map = {}
3008
+ selected_blocks.each do |block|
3009
+ mdoc.collect_dependencies(memo: dependency_map, block: block)
3010
+ end
2969
3011
 
2970
- update_menu_base(
2971
- blocks.each.with_object({}) do |block, merged_options|
3012
+ collected_options =
3013
+ dependency_map.each.with_object({}) do |(block_id, _), merged_options|
3014
+ matching_block = HashDelegator.block_find(all_blocks, :id, block_id)
2972
3015
  options_state = read_show_options_and_trigger_reuse(
2973
- mdoc: mdoc,
2974
- selected: block
3016
+ mdoc: mdoc, selected: matching_block
2975
3017
  )
2976
3018
  merged_options.merge!(options_state.options)
2977
3019
  end
2978
- )
2979
3020
 
2980
- @opts_most_recent_filename = @delegate_object[:filename]
3021
+ update_menu_base(collected_options)
3022
+ @opts_most_recent_filename = current_filename
2981
3023
  true
2982
3024
  end
2983
3025
 
2984
- def load_auto_ux_block(
2985
- all_blocks,
2986
- mdoc,
2987
- block_name: @delegate_object[:document_load_ux_block_name]
2988
- )
2989
- unless block_name.present? &&
2990
- @ux_most_recent_filename != @delegate_object[:filename]
2991
- return
2992
- end
2993
-
2994
- blocks = HashDelegator.block_select(all_blocks, :oname, block_name)
2995
- if blocks.empty?
2996
- blocks = HashDelegator.block_match(all_blocks, :nickname,
2997
- Regexp.new(block_name))
2998
- end
2999
- return if blocks.empty?
3000
-
3001
- @ux_most_recent_filename = @delegate_object[:filename]
3002
-
3003
- (blocks.each.with_object([]) do |block, merged_options|
3004
- code = code_from_ux_block_to_set_environment_variables(
3005
- block,
3006
- mdoc,
3007
- force: @delegate_object[:ux_auto_load_force_default],
3008
- only_default: true
3009
- )
3010
- if code == :ux_exec_prohibited
3011
- merged_options
3012
- else
3013
- merged_options.push(code)
3014
- end
3015
- end).to_a
3016
- end
3017
-
3018
3026
  def load_auto_vars_block(
3019
3027
  all_blocks,
3020
3028
  block_name: @delegate_object[:document_load_vars_block_name]
@@ -3175,7 +3183,7 @@ module MarkdownExec
3175
3183
 
3176
3184
  # load document ux block
3177
3185
  #
3178
- if (code_lines = load_auto_ux_block(all_blocks, mdoc))
3186
+ if (code_lines = code_from_automatic_ux_blocks(all_blocks, mdoc))
3179
3187
  new_code = HashDelegator.code_merge(link_state.inherited_lines,
3180
3188
  code_lines)
3181
3189
  next_state_set_code(nil, link_state, new_code)
@@ -3491,6 +3499,11 @@ module MarkdownExec
3491
3499
  fout_execution_report if @delegate_object[:output_execution_report]
3492
3500
  end
3493
3501
 
3502
+ # all UX blocks are automatic for the document
3503
+ def select_automatic_ux_blocks(blocks)
3504
+ blocks.select { |item| item.type == 'ux' }
3505
+ end
3506
+
3494
3507
  # Filter blocks per block_name_include_match, block_name_wrapper_match.
3495
3508
  #
3496
3509
  # @param all_blocks [Array<Hash>] The list of blocks from the file.
@@ -4481,56 +4494,75 @@ module MarkdownExec
4481
4494
  def ux_block_export_automatic(export, inherited_code, code_lines, required)
4482
4495
  transformable = true
4483
4496
  exportable = true
4484
- [case export.default
4485
- when :allowed
4486
- raise unless export.allowed.present?
4487
4497
 
4488
- if export.allowed == :echo
4489
- output, exportable = export_echo_with_code(
4490
- export, inherited_code, code_lines, required, force: false
4491
- )
4492
- return :ux_exec_prohibited if output == :invalidated
4498
+ if export.default == false
4499
+ exportable = false
4500
+ transformable = false
4501
+ value = nil
4502
+ else
4503
+ if export.default.nil?
4504
+ if export.echo.present?
4505
+ export.default = :echo
4506
+ elsif export.exec.present?
4507
+ export.default = :exec
4508
+ elsif export.allowed.present?
4509
+ export.default = export.allowed.first
4510
+ end
4511
+ end
4493
4512
 
4494
- exportable && output.split("\n").first
4513
+ value = case export.default
4514
+ when :allowed
4515
+ raise unless export.allowed.present?
4495
4516
 
4496
- elsif export.allowed == :exec
4497
- output = process_allowed_exec(export, inherited_code,
4498
- code_lines, required)
4499
- return :ux_exec_prohibited if output == :ux_exec_prohibited
4517
+ if export.allowed == :echo
4518
+ output, exportable = export_echo_with_code(
4519
+ export, inherited_code, code_lines, required, force: false
4520
+ )
4521
+ return :ux_exec_prohibited if output == :invalidated
4500
4522
 
4501
- output.first
4523
+ exportable && output.split("\n").first
4502
4524
 
4503
- else
4504
- export.allowed.first
4505
- end
4525
+ elsif export.allowed == :exec
4526
+ output = process_allowed_exec(export, inherited_code,
4527
+ code_lines, required)
4528
+ return :ux_exec_prohibited if output == :ux_exec_prohibited
4506
4529
 
4507
- # echo > default
4508
- when :echo
4509
- raise unless export.echo.present?
4530
+ output.first
4510
4531
 
4511
- output, exportable = export_echo_with_code(
4512
- export, inherited_code, code_lines, required, force: false
4513
- )
4514
- return :ux_exec_prohibited if output == :invalidated
4532
+ else
4533
+ export.allowed.first
4534
+ end
4515
4535
 
4516
- output
4536
+ # echo > default
4537
+ when :echo
4538
+ raise unless export.echo.present?
4517
4539
 
4518
- # exec > default
4519
- when :exec
4520
- raise unless export.exec.present?
4540
+ output, exportable = export_echo_with_code(
4541
+ export, inherited_code, code_lines, required, force: false
4542
+ )
4543
+ return :ux_exec_prohibited if output == :invalidated
4521
4544
 
4522
- output = export_exec_with_code(
4523
- export, inherited_code, code_lines, required
4524
- )
4525
- return :ux_exec_prohibited if output == :invalidated
4545
+ output
4526
4546
 
4527
- output
4547
+ # exec > default
4548
+ when :exec
4549
+ raise unless export.exec.present?
4528
4550
 
4529
- # default
4530
- else
4531
- transformable = false
4532
- export.default.to_s
4533
- end,
4551
+ output = export_exec_with_code(
4552
+ export, inherited_code, code_lines, required
4553
+ )
4554
+ return :ux_exec_prohibited if output == :invalidated
4555
+
4556
+ output
4557
+
4558
+ # default
4559
+ else
4560
+ transformable = false
4561
+ export.default.to_s
4562
+ end
4563
+ end
4564
+
4565
+ [value,
4534
4566
  exportable,
4535
4567
  transformable]
4536
4568
  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.8.4'
10
+ VERSION = '2.8.5'
11
11
  end
data/lib/mdoc.rb CHANGED
@@ -83,7 +83,7 @@ module MarkdownExec
83
83
 
84
84
  nickname = name_block.pub_name
85
85
 
86
- dependencies = collect_dependencies(nickname)
86
+ dependencies = collect_dependencies(source: nickname)
87
87
  # !!t dependencies.count
88
88
  all_dependency_names =
89
89
  collect_unique_names(dependencies).push(nickname).uniq
@@ -405,21 +405,23 @@ module MarkdownExec
405
405
  # @param source [String] The name of the initial source block.
406
406
  # @param memo [Hash] A memoization hash to store resolved dependencies.
407
407
  # @return [Hash] A hash mapping sources to their respective dependencies.
408
- def collect_dependencies(source, memo = {})
409
- return memo unless source
408
+ def collect_dependencies(block: nil, memo: {}, source: nil)
409
+ if block.nil?
410
+ return memo unless source
410
411
 
411
- block = get_block_by_anyname(source)
412
- if block.nil? || block.instance_of?(Hash)
413
- raise "Named code block `#{source}` not found. (@#{__LINE__})"
412
+ block = get_block_by_anyname(source)
413
+ if block.nil? || block.instance_of?(Hash)
414
+ raise "Named code block `#{source}` not found. (@#{__LINE__})"
415
+ end
414
416
  end
415
-
416
417
  return memo unless block.reqs
417
418
 
418
- memo[source] = block.reqs
419
+ memo[block.id] = block.reqs
419
420
 
420
421
  block.reqs.each do |req|
421
- collect_dependencies(req, memo) unless memo.key?(req)
422
+ collect_dependencies(source: req, memo: memo) unless memo.key?(req)
422
423
  end
424
+
423
425
  memo
424
426
  end
425
427
 
@@ -463,24 +465,24 @@ if $PROGRAM_NAME == __FILE__
463
465
  end
464
466
 
465
467
  def test_collect_dependencies_with_no_source
466
- assert_empty @mdoc.collect_dependencies(nil)
468
+ assert_empty @mdoc.collect_dependencies
467
469
  end
468
470
 
469
471
  ### must raise error
470
472
  def test_collect_dependencies_with_nonexistent_source
471
473
  assert_raises(RuntimeError) do
472
- @mdoc.collect_dependencies('nonexistent')
474
+ @mdoc.collect_dependencies(source: 'nonexistent')
473
475
  end
474
476
  end if false
475
477
 
476
478
  def test_collect_dependencies_with_valid_source
477
479
  @mdoc.stubs(:get_block_by_anyname)
478
- .with('source1').returns(OpenStruct.new(reqs: ['source2']))
480
+ .with('source1').returns(OpenStruct.new(id: 'source1', reqs: ['source2']))
479
481
  @mdoc.stubs(:get_block_by_anyname)
480
- .with('source2').returns(OpenStruct.new(reqs: []))
482
+ .with('source2').returns(OpenStruct.new(id: 'source2', reqs: []))
481
483
 
482
484
  expected = { 'source1' => ['source2'], 'source2' => [] }
483
- assert_equal expected, @mdoc.collect_dependencies('source1')
485
+ assert_equal expected, @mdoc.collect_dependencies(source: 'source1')
484
486
  end
485
487
  end
486
488
 
data/lib/menu.src.yml CHANGED
@@ -103,6 +103,12 @@
103
103
  :default: true
104
104
  :procname: val_as_bool
105
105
 
106
+ - :opt_name: command_substitution_format
107
+ :env_var: MDE_COMMAND_SUBSTITUTION_FORMAT
108
+ :description: command_substitution_format
109
+ :default: '$(%s)'
110
+ :procname: val_as_str
111
+
106
112
  - :opt_name: command_substitution_regexp
107
113
  :env_var: MDE_COMMAND_SUBSTITUTION_REGEXP
108
114
  :description: command_substitution_regexp
@@ -207,12 +213,6 @@
207
213
  :default: "(document_shell)"
208
214
  :procname: val_as_str
209
215
 
210
- - :opt_name: document_load_ux_block_name
211
- :env_var: MDE_DOCUMENT_LOAD_UX_BLOCK_NAME
212
- :description: Name of UX block to load with the document
213
- :default: "\\[.*document_ux.*\\]"
214
- :procname: val_as_str
215
-
216
216
  - :opt_name: document_load_vars_block_name
217
217
  :env_var: MDE_DOCUMENT_LOAD_VARS_BLOCK_NAME
218
218
  :description: Name of Vars block to load with the document
@@ -1663,6 +1663,12 @@
1663
1663
  :default: true
1664
1664
  :procname: val_as_bool
1665
1665
 
1666
+ - :opt_name: variable_expression_format
1667
+ :env_var: MDE_VARIABLE_EXPRESSION_FORMAT
1668
+ :description: variable_expression_format
1669
+ :default: '${%s}'
1670
+ :procname: val_as_str
1671
+
1666
1672
  - :opt_name: variable_expression_regexp
1667
1673
  :env_var: MDE_VARIABLE_EXPRESSION_REGEXP
1668
1674
  :description: variable_expression_regexp
data/lib/menu.yml CHANGED
@@ -84,6 +84,11 @@
84
84
  :arg_name: BOOL
85
85
  :default: true
86
86
  :procname: val_as_bool
87
+ - :opt_name: command_substitution_format
88
+ :env_var: MDE_COMMAND_SUBSTITUTION_FORMAT
89
+ :description: command_substitution_format
90
+ :default: "$(%s)"
91
+ :procname: val_as_str
87
92
  - :opt_name: command_substitution_regexp
88
93
  :env_var: MDE_COMMAND_SUBSTITUTION_REGEXP
89
94
  :description: command_substitution_regexp
@@ -172,11 +177,6 @@
172
177
  :description: Name of shell block to load with the document
173
178
  :default: "(document_shell)"
174
179
  :procname: val_as_str
175
- - :opt_name: document_load_ux_block_name
176
- :env_var: MDE_DOCUMENT_LOAD_UX_BLOCK_NAME
177
- :description: Name of UX block to load with the document
178
- :default: "\\[.*document_ux.*\\]"
179
- :procname: val_as_str
180
180
  - :opt_name: document_load_vars_block_name
181
181
  :env_var: MDE_DOCUMENT_LOAD_VARS_BLOCK_NAME
182
182
  :description: Name of Vars block to load with the document
@@ -1419,6 +1419,11 @@
1419
1419
  :arg_name: BOOL
1420
1420
  :default: true
1421
1421
  :procname: val_as_bool
1422
+ - :opt_name: variable_expression_format
1423
+ :env_var: MDE_VARIABLE_EXPRESSION_FORMAT
1424
+ :description: variable_expression_format
1425
+ :default: "${%s}"
1426
+ :procname: val_as_str
1422
1427
  - :opt_name: variable_expression_regexp
1423
1428
  :env_var: MDE_VARIABLE_EXPRESSION_REGEXP
1424
1429
  :description: variable_expression_regexp
data/lib/namer.rb CHANGED
@@ -9,9 +9,7 @@ class Hash
9
9
  # block name in commands and documents
10
10
  def pub_name(**kwargs)
11
11
  full = fetch(:nickname, nil) || fetch(:oname, nil)
12
- full&.to_s&.pub_name(**kwargs).tap do |ret|
13
- pp [__LINE__, 'Hash.pub_name() ->', ret] if $pd
14
- end
12
+ full&.to_s&.pub_name(**kwargs)
15
13
  end
16
14
  end
17
15
 
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.8.4
4
+ version: 2.8.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fareed Stevenson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-03-24 00:00:00.000000000 Z
11
+ date: 2025-04-07 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
  - bats/block-type-ux-allowed.bats
116
116
  - bats/block-type-ux-auto.bats
117
117
  - bats/block-type-ux-chained.bats
118
+ - bats/block-type-ux-default.bats
118
119
  - bats/block-type-ux-echo-hash.bats
119
120
  - bats/block-type-ux-echo.bats
120
121
  - bats/block-type-ux-exec.bats
@@ -163,6 +164,7 @@ files:
163
164
  - docs/dev/block-type-ux-allowed.md
164
165
  - docs/dev/block-type-ux-auto.md
165
166
  - docs/dev/block-type-ux-chained.md
167
+ - docs/dev/block-type-ux-default.md
166
168
  - docs/dev/block-type-ux-echo-hash.md
167
169
  - docs/dev/block-type-ux-echo.md
168
170
  - docs/dev/block-type-ux-exec.md