markdown_exec 1.8.2 → 1.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.
@@ -24,7 +24,9 @@ require_relative 'fcb'
24
24
  require_relative 'filter'
25
25
  require_relative 'fout'
26
26
  require_relative 'hash'
27
+ require_relative 'link_history'
27
28
  require_relative 'mdoc'
29
+ require_relative 'regexp'
28
30
  require_relative 'string_util'
29
31
 
30
32
  class String
@@ -115,6 +117,7 @@ module MarkdownExec
115
117
  @run_state = OpenStruct.new(
116
118
  link_history: []
117
119
  )
120
+ @link_history = LinkHistory.new
118
121
  @fout = FOut.new(@delegate_object) ### slice only relevant keys
119
122
 
120
123
  @process_mutex = Mutex.new
@@ -167,9 +170,7 @@ module MarkdownExec
167
170
  def append_chrome_block(menu_blocks, type)
168
171
  case type
169
172
  when MenuState::BACK
170
- state = history_state_partition
171
- @hs_curr = state[:unit]
172
- @hs_rest = state[:rest]
173
+ history_state_partition
173
174
  option_name = @delegate_object[:menu_option_back_name]
174
175
  insert_at_top = @delegate_object[:menu_back_at_top]
175
176
  when MenuState::EXIT
@@ -181,13 +182,9 @@ module MarkdownExec
181
182
  safeval(option_name))
182
183
  chrome_block = FCB.new(
183
184
  chrome: true,
184
-
185
- # dname: formatted_name.send(@delegate_object[:menu_link_color].to_sym),
186
185
  dname: HashDelegator.new(@delegate_object).string_send_color(
187
186
  formatted_name, :menu_link_color
188
187
  ),
189
- #dname: @delegate_object.string_send_color(formatted_name, :menu_link_color),
190
-
191
188
  oname: formatted_name
192
189
  )
193
190
 
@@ -276,30 +273,46 @@ module MarkdownExec
276
273
  true
277
274
  end
278
275
 
276
+ def code_join(*bodies)
277
+ bc = bodies&.compact
278
+ bc.count.positive? ? bc.join("\n") : nil
279
+ end
280
+
281
+ def code_merge(*bodies)
282
+ merge_lists(*bodies)
283
+ end
284
+
279
285
  # Collects required code lines based on the selected block and the delegate object's configuration.
280
286
  # If the block type is VARS, it also sets environment variables based on the block's content.
281
287
  #
282
288
  # @param mdoc [YourMDocClass] An instance of the MDoc class.
283
289
  # @param selected [Hash] The selected block.
284
290
  # @return [Array<String>] Required code blocks as an array of lines.
285
- def collect_required_code_lines(mdoc, selected)
291
+ def collect_required_code_lines(mdoc, selected, link_state = LinkState.new, block_source:)
286
292
  set_environment_variables_for_block(selected) if selected[:shell] == BlockType::VARS
287
293
 
288
294
  required = mdoc.collect_recursively_required_code(
289
295
  @delegate_object[:block_name],
290
296
  label_format_above: @delegate_object[:shell_code_label_format_above],
291
- label_format_below: @delegate_object[:shell_code_label_format_below]
297
+ label_format_below: @delegate_object[:shell_code_label_format_below],
298
+ block_source: block_source
292
299
  )
300
+ dependencies = (link_state&.inherited_dependencies || {}).merge(required[:dependencies] || {})
301
+ required[:unmet_dependencies] =
302
+ (required[:unmet_dependencies] || []) - (link_state&.inherited_block_names || [])
293
303
  if required[:unmet_dependencies].present?
294
- warn format_and_highlight_dependencies(required[:dependencies],
304
+ ### filter against link_state.inherited_block_names
305
+
306
+ warn format_and_highlight_dependencies(dependencies,
295
307
  highlight: required[:unmet_dependencies])
296
308
  runtime_exception(:runtime_exception_error_level,
297
309
  'unmet_dependencies, flag: runtime_exception_error_level', required[:unmet_dependencies])
298
310
  elsif true
299
- warn format_and_highlight_dependencies(required[:dependencies],
311
+ warn format_and_highlight_dependencies(dependencies,
300
312
  highlight: [@delegate_object[:block_name]])
301
313
  end
302
- read_required_blocks_from_temp_file + required[:code]
314
+
315
+ code_merge link_state&.inherited_lines, required[:code]
303
316
  end
304
317
 
305
318
  def command_execute(command, args: [])
@@ -369,15 +382,19 @@ module MarkdownExec
369
382
  #
370
383
  # @param mdoc [Object] The markdown document object containing code blocks.
371
384
  # @param selected [Hash] The selected item from the menu to be executed.
372
- # @return [LoadFileNextBlock] An object indicating whether to load the next block or reuse the current one.
373
- def compile_execute_bash_and_special_blocks_and_trigger_reuse(mdoc, selected)
374
- required_lines = collect_required_code_lines(mdoc, selected)
385
+ # @return [LoadFileLinkState] An object indicating whether to load the next block or reuse the current one.
386
+ def compile_execute_bash_and_special_blocks_and_trigger_reuse(mdoc, selected,
387
+ link_state = nil, block_source:)
388
+ required_lines = collect_required_code_lines(mdoc, selected, link_state,
389
+ block_source: block_source)
375
390
  output_or_approval = @delegate_object[:output_script] || @delegate_object[:user_must_approve]
376
391
  display_required_code(required_lines) if output_or_approval
377
392
  allow_execution = @delegate_object[:user_must_approve] ? prompt_for_user_approval(required_lines) : true
378
- execute_approved_block(required_lines, selected) if allow_execution
379
393
 
380
- LoadFileNextBlock.new(LoadFile::Reuse, '')
394
+ execute_required_lines(required_lines) if allow_execution
395
+
396
+ link_state.block_name = nil
397
+ LoadFileLinkState.new(LoadFile::Reuse, link_state)
381
398
  end
382
399
 
383
400
  def copy_to_clipboard(required_lines)
@@ -458,13 +475,13 @@ module MarkdownExec
458
475
  # @param file_path [String] The path where the file will be created.
459
476
  # @param content [String] The content to write into the file.
460
477
  # @param chmod_value [Integer] The file permission value to set; skips if zero.
461
- def create_and_write_file_with_permissions(file_path, content,
462
- chmod_value)
478
+ def create_file_and_write_string_with_permissions(file_path, content,
479
+ chmod_value)
463
480
  create_directory_for_file(file_path)
464
- write_file_content(file_path, content)
481
+ File.write(file_path, content)
465
482
  set_file_permissions(file_path, chmod_value) unless chmod_value.zero?
466
483
  rescue StandardError
467
- error_handler('create_and_write_file_with_permissions')
484
+ error_handler('create_file_and_write_string_with_permissions')
468
485
  end
469
486
 
470
487
  # private
@@ -486,15 +503,6 @@ module MarkdownExec
486
503
  )
487
504
  end
488
505
 
489
- # Creates a temporary file, writes the provided code blocks into it,
490
- # and sets an environment variable with the file path.
491
- # @param code_blocks [String] Code blocks to write into the file.
492
- def create_temp_file_with_code(code_blocks)
493
- temp_file_path = create_temp_file
494
- write_to_file(temp_file_path, code_blocks)
495
- set_environment_variable(temp_file_path)
496
- end
497
-
498
506
  # private
499
507
 
500
508
  def create_temp_file
@@ -519,13 +527,10 @@ module MarkdownExec
519
527
  # Deletes a temporary file specified by an environment variable.
520
528
  # Checks if the file exists before attempting to delete it and clears the environment variable afterward.
521
529
  # Any errors encountered during deletion are handled gracefully.
522
- def delete_required_temp_file
523
- temp_blocks_file_path = fetch_temp_blocks_file_path
524
-
530
+ def delete_required_temp_file(temp_blocks_file_path)
525
531
  return if temp_blocks_file_path.nil? || temp_blocks_file_path.empty?
526
532
 
527
533
  safely_remove_file(temp_blocks_file_path)
528
- clear_required_file
529
534
  rescue StandardError
530
535
  error_handler('delete_required_temp_file')
531
536
  end
@@ -581,9 +586,9 @@ module MarkdownExec
581
586
  #
582
587
  # @param required_lines [Array<String>] The lines of code to be executed.
583
588
  # @param selected [FCB] The selected functional code block object.
584
- def execute_approved_block(required_lines = [], _selected = FCB.new)
589
+ def execute_required_lines(required_lines = [])
585
590
  # set_script_block_name(selected)
586
- write_command_file_if_needed(required_lines)
591
+ save_executed_script_if_specified(required_lines)
587
592
  format_and_execute_command(required_lines)
588
593
  post_execution_process
589
594
  end
@@ -597,15 +602,24 @@ module MarkdownExec
597
602
  # @param opts [Hash] Options hash containing configuration settings.
598
603
  # @param mdoc [YourMDocClass] An instance of the MDoc class.
599
604
  #
600
- def execute_bash_and_special_blocks(selected, mdoc)
605
+ def execute_bash_and_special_blocks(selected, mdoc, link_state = LinkState.new,
606
+ block_source:)
601
607
  if selected.fetch(:shell, '') == BlockType::LINK
602
- push_link_history_and_trigger_load(selected.fetch(:body, ''), mdoc, selected)
608
+ push_link_history_and_trigger_load(selected.fetch(:body, ''), mdoc, selected,
609
+ link_state)
610
+
603
611
  elsif @menu_user_clicked_back_link
604
612
  pop_link_history_and_trigger_load
613
+
605
614
  elsif selected[:shell] == BlockType::OPTS
606
- update_options_and_trigger_reuse(selected, @menu_base_options)
615
+ options_state = read_show_options_and_trigger_reuse(selected, link_state)
616
+ @menu_base_options.merge!(options_state.options)
617
+ @delegate_object.merge!(options_state.options)
618
+ options_state.load_file_link_state
619
+
607
620
  else
608
- compile_execute_bash_and_special_blocks_and_trigger_reuse(mdoc, selected)
621
+ compile_execute_bash_and_special_blocks_and_trigger_reuse(mdoc, selected, link_state,
622
+ block_source: block_source)
609
623
  end
610
624
  end
611
625
 
@@ -623,13 +637,8 @@ module MarkdownExec
623
637
  string_send_color(data_string, color_sym)
624
638
  end
625
639
 
626
- def fetch_temp_blocks_file_path
627
- ENV.fetch('MDE_LINK_REQUIRED_FILE', nil)
628
- end
629
-
630
640
  # DebugHelper.d ["HDmm method_name: #{method_name}", "#{first_n_caller_items 1}"]
631
641
  def first_n_caller_items(n)
632
- # Get the call stack
633
642
  call_stack = caller
634
643
  base_path = File.realpath('.')
635
644
 
@@ -704,6 +713,7 @@ module MarkdownExec
704
713
  #
705
714
  # @param block_state [Object] An object representing the state of a block in the menu.
706
715
  def handle_block_state(block_state)
716
+ return if block_state.nil?
707
717
  unless [MenuState::BACK,
708
718
  MenuState::CONTINUE].include?(block_state.state)
709
719
  return
@@ -735,52 +745,6 @@ module MarkdownExec
735
745
  end
736
746
  end
737
747
 
738
- # Checks if a history environment variable is set and returns its value if present.
739
- # @return [String, nil] The value of the history environment variable or nil if not present.
740
- def history_env_state_exist?
741
- ENV.fetch(MDE_HISTORY_ENV_NAME, '').present?
742
- end
743
-
744
- # Partitions the history state from the environment variable based on the document separator.
745
- # @return [Hash] A hash containing two parts: :unit (first part) and :rest (remaining part).
746
- def history_state_partition
747
- history_env_value = ENV.fetch(MDE_HISTORY_ENV_NAME, '')
748
- separator = @delegate_object[:history_document_separator]
749
-
750
- unit, rest = StringUtil.partition_at_first(history_env_value, separator)
751
- { unit: unit, rest: rest }
752
- end
753
-
754
- # Pops the last entry from the history state, updating the delegate object and environment variable.
755
- # It also deletes the required temporary file and updates the run state link history.
756
- def history_state_pop
757
- state = history_state_partition
758
- @delegate_object[:filename] = state[:unit]
759
- ENV[MDE_HISTORY_ENV_NAME] = state[:rest]
760
- delete_required_temp_file
761
- @run_state.link_history.pop
762
- end
763
-
764
- # Updates the history state by pushing a new entry and managing environment variables.
765
- # @param mdoc [Object] The Markdown document object.
766
- # @param data_file [String] The data file to be processed.
767
- # @param selected [Hash] Hash containing the selected block's name.
768
- def history_state_push(mdoc, data_file, selected)
769
- # Construct new history string
770
- new_history = [@delegate_object[:filename],
771
- @delegate_object[:history_document_separator],
772
- ENV.fetch(MDE_HISTORY_ENV_NAME, '')].join
773
-
774
- # Update delegate object and environment variable
775
- @delegate_object[:filename] = data_file
776
- ENV[MDE_HISTORY_ENV_NAME] = new_history
777
-
778
- # Write required blocks to temp file and update run state
779
- write_required_blocks_to_temp_file(mdoc, @delegate_object[:block_name])
780
- @run_state.link_history.push(block_name: selected[:oname],
781
- filename: data_file)
782
- end
783
-
784
748
  # Indents all lines in a given string with a specified indentation string.
785
749
  # @param body [String] A multi-line string to be indented.
786
750
  # @param indent [String] The string used for indentation (default is an empty string).
@@ -845,6 +809,33 @@ module MarkdownExec
845
809
  end
846
810
  end
847
811
 
812
+ def link_history_push_and_next(
813
+ curr_block_name:, curr_document_filename:,
814
+ inherited_block_names:, inherited_dependencies:, inherited_lines:,
815
+ next_block_name:, next_document_filename:,
816
+ next_load_file:
817
+ )
818
+ @link_history.push(
819
+ LinkState.new(
820
+ block_name: curr_block_name,
821
+ document_filename: curr_document_filename,
822
+ inherited_block_names: inherited_block_names,
823
+ inherited_dependencies: inherited_dependencies,
824
+ inherited_lines: inherited_lines
825
+ )
826
+ )
827
+ LoadFileLinkState.new(
828
+ next_load_file,
829
+ LinkState.new(
830
+ block_name: next_block_name,
831
+ document_filename: next_document_filename,
832
+ inherited_block_names: inherited_block_names,
833
+ inherited_dependencies: inherited_dependencies,
834
+ inherited_lines: inherited_lines
835
+ )
836
+ )
837
+ end
838
+
848
839
  # Loads auto blocks based on delegate object settings and updates if new filename is detected.
849
840
  # Executes a specified block once per filename.
850
841
  # @param all_blocks [Array] Array of all block elements.
@@ -858,7 +849,10 @@ module MarkdownExec
858
849
  block = block_find(all_blocks, :oname, block_name)
859
850
  return unless block
860
851
 
861
- update_options_and_trigger_reuse(block, @delegate_object)
852
+ options_state = read_show_options_and_trigger_reuse(block)
853
+ @menu_base_options.merge!(options_state.options)
854
+ @delegate_object.merge!(options_state.options)
855
+
862
856
  @most_recent_loaded_filename = @delegate_object[:filename]
863
857
  true
864
858
  end
@@ -910,6 +904,12 @@ module MarkdownExec
910
904
  end
911
905
  end
912
906
 
907
+ def merge_lists(*args)
908
+ # Filters out nil values, flattens the arrays, and ensures an empty list is returned if no valid lists are provided
909
+ merged = args.compact.flatten
910
+ merged.empty? ? [] : merged
911
+ end
912
+
913
913
  # If a method is missing, treat it as a key for the @delegate_object.
914
914
  def method_missing(method_name, *args, &block)
915
915
  if @delegate_object.respond_to?(method_name)
@@ -922,11 +922,11 @@ module MarkdownExec
922
922
  end
923
923
  end
924
924
 
925
- def next_block_name_from_command_line_arguments
926
- return MenuControl::Repeat unless @delegate_object[:input_cli_rest].present?
925
+ def pop_cli_argument!
926
+ return false unless @delegate_object[:input_cli_rest].present?
927
927
 
928
- @delegate_object[:block_name] = @delegate_object[:input_cli_rest].pop
929
- MenuControl::Fresh
928
+ @cli_block_name = @delegate_object[:input_cli_rest].pop
929
+ true
930
930
  end
931
931
 
932
932
  # private
@@ -989,13 +989,38 @@ module MarkdownExec
989
989
  body.any? ? YAML.load(body.join("\n")) : {}
990
990
  end
991
991
 
992
+ def pop_add_current_code_to_head_and_trigger_load(_link_state, block_names, code_lines,
993
+ dependencies)
994
+ pop = @link_history.pop # updatable
995
+ next_link_state = LinkState.new(
996
+ block_name: pop.block_name,
997
+ document_filename: pop.document_filename,
998
+ inherited_block_names:
999
+ (pop.inherited_block_names + block_names).sort.uniq,
1000
+ inherited_dependencies:
1001
+ dependencies.merge(pop.inherited_dependencies || {}), ### merge, not replace, key data
1002
+ inherited_lines:
1003
+ code_merge(pop.inherited_lines, code_lines)
1004
+ )
1005
+ @link_history.push(next_link_state)
1006
+
1007
+ next_link_state.block_name = nil
1008
+ LoadFileLinkState.new(LoadFile::Load, next_link_state)
1009
+ end
1010
+
992
1011
  # This method handles the back-link operation in the Markdown execution context.
993
1012
  # It updates the history state and prepares to load the next block.
994
1013
  #
995
- # @return [LoadFileNextBlock] An object indicating the action to load the next block.
1014
+ # @return [LoadFileLinkState] An object indicating the action to load the next block.
996
1015
  def pop_link_history_and_trigger_load
997
- history_state_pop
998
- LoadFileNextBlock.new(LoadFile::Load, '')
1016
+ pop = @link_history.pop
1017
+ peek = @link_history.peek
1018
+ LoadFileLinkState.new(LoadFile::Load, LinkState.new(
1019
+ document_filename: pop.document_filename,
1020
+ inherited_block_names: peek.inherited_block_names,
1021
+ inherited_dependencies: peek.inherited_dependencies,
1022
+ inherited_lines: peek.inherited_lines
1023
+ ))
999
1024
  end
1000
1025
 
1001
1026
  def post_execution_process
@@ -1010,7 +1035,6 @@ module MarkdownExec
1010
1035
  # @param opts [Hash] The options hash.
1011
1036
  # @return [Array<Hash>] The updated blocks menu.
1012
1037
  def prepare_blocks_menu(menu_blocks)
1013
- ### replace_consecutive_blanks(menu_blocks).map do |fcb|
1014
1038
  menu_blocks.map do |fcb|
1015
1039
  next if Filter.prepared_not_in_menu?(@delegate_object, fcb,
1016
1040
  %i[block_name_include_match block_name_wrapper_match])
@@ -1114,28 +1138,85 @@ module MarkdownExec
1114
1138
  # public
1115
1139
 
1116
1140
  # Handles the processing of a link block in Markdown Execution.
1117
- # It loads YAML data from the body content, pushes the state to history,
1141
+ # It loads YAML data from the link_block_body content, pushes the state to history,
1118
1142
  # sets environment variables, and decides on the next block to load.
1119
1143
  #
1120
- # @param body [Array<String>] The body content as an array of strings.
1144
+ # @param link_block_body [Array<String>] The body content as an array of strings.
1121
1145
  # @param mdoc [Object] Markdown document object.
1122
- # @param selected [Boolean] Selected state.
1123
- # @return [LoadFileNextBlock] Object indicating the next action for file loading.
1124
- def push_link_history_and_trigger_load(body, mdoc, selected)
1125
- data = parse_yaml_data_from_body(body)
1126
- data_file = data['file']
1127
- return LoadFileNextBlock.new(LoadFile::Reuse, '') unless data_file
1146
+ # @param selected [FCB] Selected code block.
1147
+ # @return [LoadFileLinkState] Object indicating the next action for file loading.
1148
+ def push_link_history_and_trigger_load(link_block_body, mdoc, selected,
1149
+ link_state = LinkState.new)
1150
+ link_block_data = parse_yaml_data_from_body(link_block_body)
1151
+
1152
+ # load key and values from link block into current environment
1153
+ #
1154
+ (link_block_data['vars'] || []).each do |(key, value)|
1155
+ ENV[key] = value.to_s
1156
+ end
1128
1157
 
1129
- history_state_push(mdoc, data_file, selected)
1130
- set_environment_variables_per_array(data['vars'])
1158
+ ## collect blocks specified by block
1159
+ #
1160
+ if mdoc
1161
+ code_info = mdoc.collect_recursively_required_code(
1162
+ selected[:oname],
1163
+ label_format_above: @delegate_object[:shell_code_label_format_above],
1164
+ label_format_below: @delegate_object[:shell_code_label_format_below],
1165
+ block_source: { document_filename: link_state.document_filename }
1166
+ )
1167
+ code_lines = code_info[:code]
1168
+ block_names = code_info[:block_names]
1169
+ dependencies = code_info[:dependencies]
1170
+ else
1171
+ block_names = []
1172
+ code_lines = []
1173
+ dependencies = {}
1174
+ end
1175
+ next_document_filename = link_block_data['file'] || @delegate_object[:filename]
1176
+
1177
+ # if an eval link block, evaluate code_lines and return its standard output
1178
+ #
1179
+ if link_block_data.fetch('eval', false)
1180
+ all_code = code_merge(link_state&.inherited_lines, code_lines)
1181
+ output = `#{all_code.join("\n")}`.split("\n")
1182
+ label_format_above = @delegate_object[:shell_code_label_format_above]
1183
+ label_format_below = @delegate_object[:shell_code_label_format_below]
1184
+ block_source = { document_filename: link_state&.document_filename }
1185
+
1186
+ code_lines = [label_format_above && format(label_format_above,
1187
+ block_source.merge({ block_name: selected[:oname] }))] +
1188
+ output.map do |line|
1189
+ re = Regexp.new(link_block_data.fetch('pattern', '(?<line>.*)'))
1190
+ if re =~ line
1191
+ re.gsub_format(line, link_block_data.fetch('format', '%{line}'))
1192
+ end
1193
+ end.compact +
1194
+ [label_format_below && format(label_format_below,
1195
+ block_source.merge({ block_name: selected[:oname] }))]
1131
1196
 
1132
- LoadFileNextBlock.new(LoadFile::Load, data['block'] || '')
1197
+ end
1198
+
1199
+ if link_block_data['return']
1200
+ pop_add_current_code_to_head_and_trigger_load(link_state, block_names, code_lines,
1201
+ dependencies)
1202
+
1203
+ else
1204
+ link_history_push_and_next(
1205
+ curr_block_name: selected[:oname],
1206
+ curr_document_filename: @delegate_object[:filename],
1207
+ inherited_block_names: ((link_state&.inherited_block_names || []) + block_names).sort.uniq,
1208
+ inherited_dependencies: (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
1209
+ inherited_lines: code_merge(link_state&.inherited_lines, code_lines),
1210
+ next_block_name: link_block_data['block'] || '',
1211
+ next_document_filename: next_document_filename,
1212
+ next_load_file: next_document_filename == @delegate_object[:filename] ? LoadFile::Reuse : LoadFile::Load
1213
+ )
1214
+ end
1133
1215
  end
1134
1216
 
1135
1217
  # Reads required code blocks from a temporary file specified by an environment variable.
1136
1218
  # @return [Array<String>] Lines read from the temporary file, or an empty array if file is not found or path is empty.
1137
- def read_required_blocks_from_temp_file
1138
- temp_blocks_file_path = ENV.fetch('MDE_LINK_REQUIRED_FILE', nil)
1219
+ def read_required_blocks_from_temp_file(temp_blocks_file_path)
1139
1220
  return [] if temp_blocks_file_path.to_s.empty?
1140
1221
 
1141
1222
  if File.exist?(temp_blocks_file_path)
@@ -1180,12 +1261,6 @@ module MarkdownExec
1180
1261
  error_handler('safeval')
1181
1262
  end
1182
1263
 
1183
- # def safeval(str)
1184
- # eval(str)
1185
- # rescue StandardError
1186
- # error_handler('safeval')
1187
- # end
1188
-
1189
1264
  def save_to_file(required_lines)
1190
1265
  write_command_file(required_lines)
1191
1266
  @fout.fout "File saved: #{@run_state.saved_filespec}"
@@ -1199,23 +1274,34 @@ module MarkdownExec
1199
1274
  # @return [Nil] Returns nil if no code block is selected or an error occurs.
1200
1275
  def select_execute_bash_and_special_blocks(_execute: true)
1201
1276
  @menu_base_options = @delegate_object
1202
- repeat_menu = @menu_base_options[:block_name].present? ? MenuControl::Fresh : MenuControl::Repeat
1203
- load_file_next_block = LoadFileNextBlock.new(LoadFile::Reuse)
1277
+ link_state = LinkState.new(
1278
+ block_name: @delegate_object[:block_name],
1279
+ document_filename: @delegate_object[:filename]
1280
+ )
1281
+ block_name_from_cli = link_state.block_name.present?
1282
+ @cli_block_name = link_state.block_name
1283
+ load_file = nil
1204
1284
  menu_default_dname = nil
1205
1285
 
1206
- @menu_state_filename = @menu_base_options[:filename]
1207
- @menu_state_block_name = @menu_base_options[:block_name]
1208
-
1209
1286
  loop do
1210
1287
  loop do
1211
1288
  @delegate_object = @menu_base_options.dup
1212
- @menu_base_options[:filename] = @menu_state_filename
1213
- @menu_base_options[:block_name] = @menu_state_block_name
1214
- @menu_state_filename = nil
1215
- @menu_state_block_name = nil
1216
1289
  @menu_user_clicked_back_link = false
1290
+ @delegate_object[:filename] = link_state.document_filename
1291
+ link_state.block_name = @delegate_object[:block_name] =
1292
+ block_name_from_cli ? @cli_block_name : link_state.block_name
1217
1293
 
1294
+ # update @delegate_object and @menu_base_options in auto_load
1295
+ #
1218
1296
  blocks_in_file, menu_blocks, mdoc = mdoc_menu_and_blocks_from_nested_files
1297
+
1298
+ if @delegate_object[:dump_delegate_object]
1299
+ warn format_and_highlight_hash(
1300
+ @delegate_object,
1301
+ label: '@delegate_object'
1302
+ )
1303
+ end
1304
+
1219
1305
  if @delegate_object[:dump_blocks_in_file]
1220
1306
  warn format_and_highlight_dependencies(
1221
1307
  compact_and_index_hash(blocks_in_file),
@@ -1228,6 +1314,13 @@ module MarkdownExec
1228
1314
  label: 'menu_blocks'
1229
1315
  )
1230
1316
  end
1317
+ if @delegate_object[:dump_inherited_lines]
1318
+ warn format_and_highlight_lines(
1319
+ link_state.inherited_lines,
1320
+ label: 'inherited_lines'
1321
+ )
1322
+ end
1323
+
1231
1324
  block_state = command_or_user_selected_block(blocks_in_file,
1232
1325
  menu_blocks, menu_default_dname)
1233
1326
  return if block_state.state == MenuState::EXIT
@@ -1242,20 +1335,21 @@ module MarkdownExec
1242
1335
  warn block_state.block.to_yaml.sub(/^(?:---\n)?/, "Block:\n")
1243
1336
  end
1244
1337
 
1245
- load_file_next_block = execute_bash_and_special_blocks(block_state.block,
1246
- mdoc)
1247
- # if the same menu is being displayed,
1248
- # collect the display name of the selected menu item
1249
- # for use as the default item
1250
- menu_default_dname = load_file_next_block.load_file == LoadFile::Load ? nil : block_state.block[:dname]
1338
+ load_file_link_state = execute_bash_and_special_blocks(
1339
+ block_state.block,
1340
+ mdoc,
1341
+ link_state,
1342
+ block_source: { document_filename: @delegate_object[:filename] }
1343
+ )
1344
+ load_file = load_file_link_state.load_file
1345
+ link_state = load_file_link_state.link_state
1251
1346
 
1252
- @menu_base_options[:block_name] =
1253
- @delegate_object[:block_name] = load_file_next_block.next_block
1254
- @menu_base_options[:filename] = @delegate_object[:filename]
1347
+ # if the same menu is being displayed, collect the display name of the selected menu item for use as the default item
1348
+ menu_default_dname = load_file == LoadFile::Load ? nil : block_state.block[:dname]
1255
1349
 
1256
1350
  # user prompt to exit if the menu will be displayed again
1257
1351
  #
1258
- if repeat_menu == MenuControl::Repeat &&
1352
+ if !block_name_from_cli &&
1259
1353
  block_state.block[:shell] == BlockType::BASH &&
1260
1354
  @delegate_object[:pause_after_script_execution] &&
1261
1355
  prompt_select_continue == MenuState::EXIT
@@ -1264,16 +1358,12 @@ module MarkdownExec
1264
1358
 
1265
1359
  # exit current document/menu if loading next document or single block_name was specified
1266
1360
  #
1267
- if block_state.state == MenuState::CONTINUE && load_file_next_block.load_file == LoadFile::Load
1268
- break
1269
- end
1270
- break if repeat_menu == MenuControl::Fresh
1361
+ break if block_state.state == MenuState::CONTINUE && load_file == LoadFile::Load
1362
+ break if block_name_from_cli
1271
1363
  end
1272
- break if load_file_next_block.load_file == LoadFile::Reuse
1364
+ break if load_file == LoadFile::Reuse
1273
1365
 
1274
- repeat_menu = next_block_name_from_command_line_arguments
1275
- @menu_state_filename = @menu_base_options[:filename]
1276
- @menu_state_block_name = @menu_base_options[:block_name]
1366
+ block_name_from_cli = pop_cli_argument!
1277
1367
  end
1278
1368
  rescue StandardError
1279
1369
  error_handler('select_execute_bash_and_special_blocks',
@@ -1293,8 +1383,7 @@ module MarkdownExec
1293
1383
 
1294
1384
  item.merge(
1295
1385
  if selection == menu_chrome_colored_option(:menu_option_back_name)
1296
- { option: selection, curr: @hs_curr, rest: @hs_rest,
1297
- shell: BlockType::LINK }
1386
+ { option: selection, shell: BlockType::LINK }
1298
1387
  elsif selection == menu_chrome_colored_option(:menu_option_exit_name)
1299
1388
  { option: selection }
1300
1389
  else
@@ -1307,10 +1396,6 @@ module MarkdownExec
1307
1396
  error_handler('select_option_with_metadata')
1308
1397
  end
1309
1398
 
1310
- def set_environment_variable(path)
1311
- ENV['MDE_LINK_REQUIRED_FILE'] = path
1312
- end
1313
-
1314
1399
  def set_environment_variables_for_block(selected)
1315
1400
  YAML.load(selected[:body].join("\n")).each do |key, value|
1316
1401
  ENV[key] = value.to_s
@@ -1336,7 +1421,8 @@ module MarkdownExec
1336
1421
  end
1337
1422
 
1338
1423
  def should_add_back_option?
1339
- @delegate_object[:menu_with_back] && history_env_state_exist?
1424
+ @delegate_object[:menu_with_back] && @link_history.prior_state_exist?
1425
+ # @delegate_object[:menu_with_back] && link_history_prior_state_exist?
1340
1426
  end
1341
1427
 
1342
1428
  # Initializes a new fenced code block (FCB) object based on the provided line and heading information.
@@ -1397,13 +1483,6 @@ module MarkdownExec
1397
1483
  symbols: { cross: ' ' }
1398
1484
  )
1399
1485
  end
1400
- # private
1401
-
1402
- def update_delegate_and_target(key, value, tgt2)
1403
- sym_key = key.to_sym
1404
- @delegate_object[sym_key] = value
1405
- tgt2[sym_key] = value if tgt2
1406
- end
1407
1486
 
1408
1487
  # Updates the hierarchy of document headings based on the given line.
1409
1488
  # Utilizes regular expressions to identify heading levels.
@@ -1473,16 +1552,17 @@ module MarkdownExec
1473
1552
  ## add line to fenced code block
1474
1553
  # remove fcb indent if possible
1475
1554
  #
1476
- # if nested_line[:depth].zero? || opts[:menu_include_imported_blocks]
1477
- # if add_import_block?(nested_line)
1478
1555
  state[:fcb].body += [
1479
1556
  line.chomp.sub(/^#{state[:fcb].indent}/, '')
1480
1557
  ]
1481
- # end
1482
1558
  elsif nested_line[:depth].zero? || @delegate_object[:menu_include_imported_notes]
1483
1559
  # add line if it is depth 0 or option allows it
1484
1560
  #
1485
1561
  yield_line_if_selected(line, selected_messages, &block)
1562
+
1563
+ else
1564
+ # 'rejected'
1565
+
1486
1566
  end
1487
1567
  end
1488
1568
 
@@ -1504,14 +1584,22 @@ module MarkdownExec
1504
1584
  # Processes YAML data from the selected menu item, updating delegate objects and optionally printing formatted output.
1505
1585
  # @param selected [Hash] Selected item from the menu containing a YAML body.
1506
1586
  # @param tgt2 [Hash, nil] An optional target hash to update with YAML data.
1507
- # @return [LoadFileNextBlock] An instance indicating the next action for loading files.
1508
- def update_options_and_trigger_reuse(selected, tgt2 = nil)
1587
+ # @return [LoadFileLinkState] An instance indicating the next action for loading files.
1588
+ def read_show_options_and_trigger_reuse(selected, link_state = LinkState.new)
1589
+ obj = {}
1509
1590
  data = YAML.load(selected[:body].join("\n"))
1510
1591
  (data || []).each do |key, value|
1511
- update_delegate_and_target(key, value, tgt2)
1592
+ sym_key = key.to_sym
1593
+ obj[sym_key] = value
1594
+
1512
1595
  print_formatted_option(key, value) if @delegate_object[:menu_opts_set_format].present?
1513
1596
  end
1514
- LoadFileNextBlock.new(LoadFile::Reuse, '')
1597
+
1598
+ link_state.block_name = nil
1599
+ OpenStruct.new(options: obj,
1600
+ load_file_link_state: LoadFileLinkState.new(
1601
+ LoadFile::Reuse, link_state
1602
+ ))
1515
1603
  end
1516
1604
 
1517
1605
  def wait_for_stream_processing
@@ -1523,7 +1611,6 @@ module MarkdownExec
1523
1611
  def wait_for_user_selected_block(all_blocks, menu_blocks, default)
1524
1612
  block_state = wait_for_user_selection(all_blocks, menu_blocks, default)
1525
1613
  handle_block_state(block_state)
1526
-
1527
1614
  block_state
1528
1615
  rescue StandardError
1529
1616
  error_handler('wait_for_user_selected_block')
@@ -1577,7 +1664,7 @@ module MarkdownExec
1577
1664
  "# time: #{time_now}\n" \
1578
1665
  "#{required_lines.flatten.join("\n")}\n"
1579
1666
 
1580
- create_and_write_file_with_permissions(
1667
+ create_file_and_write_string_with_permissions(
1581
1668
  @run_state.saved_filespec,
1582
1669
  content,
1583
1670
  @delegate_object[:saved_script_chmod]
@@ -1586,7 +1673,7 @@ module MarkdownExec
1586
1673
  error_handler('write_command_file')
1587
1674
  end
1588
1675
 
1589
- def write_command_file_if_needed(lines)
1676
+ def save_executed_script_if_specified(lines)
1590
1677
  write_command_file(lines) if @delegate_object[:save_executed_script]
1591
1678
  end
1592
1679
 
@@ -1605,15 +1692,11 @@ module MarkdownExec
1605
1692
  )
1606
1693
  end
1607
1694
 
1608
- def write_file_content(file_path, content)
1609
- File.write(file_path, content)
1610
- end
1611
-
1612
1695
  # Writes required code blocks to a temporary file and sets an environment variable with its path.
1613
1696
  #
1614
1697
  # @param mdoc [Object] The Markdown document object.
1615
1698
  # @param block_name [String] The name of the block to collect code for.
1616
- def write_required_blocks_to_temp_file(mdoc, block_name)
1699
+ def write_required_blocks_to_file(mdoc, block_name, temp_file_path, import_filename: nil)
1617
1700
  c1 = if mdoc
1618
1701
  mdoc.collect_recursively_required_code(
1619
1702
  block_name,
@@ -1624,13 +1707,15 @@ module MarkdownExec
1624
1707
  []
1625
1708
  end
1626
1709
 
1627
- code_blocks = (read_required_blocks_from_temp_file +
1710
+ code_blocks = (read_required_blocks_from_temp_file(import_filename) +
1628
1711
  c1).join("\n")
1629
1712
 
1630
- create_temp_file_with_code(code_blocks)
1713
+ write_code_to_file(code_blocks, temp_file_path)
1631
1714
  end
1632
1715
 
1633
- def write_to_file(path, content)
1716
+ # Writes the provided code blocks to a file.
1717
+ # @param code_blocks [String] Code blocks to write into the file.
1718
+ def write_code_to_file(content, path)
1634
1719
  File.write(path, content)
1635
1720
  end
1636
1721
 
@@ -1674,7 +1759,7 @@ if $PROGRAM_NAME == __FILE__
1674
1759
  @mdoc = mock('MarkdownDocument')
1675
1760
  end
1676
1761
 
1677
- def test_calling_execute_approved_block_calls_command_execute_with_argument_args_value
1762
+ def test_calling_execute_required_lines_calls_command_execute_with_argument_args_value
1678
1763
  pigeon = 'E'
1679
1764
  obj = {
1680
1765
  output_execution_label_format: '',
@@ -1691,46 +1776,34 @@ if $PROGRAM_NAME == __FILE__
1691
1776
  args: pigeon
1692
1777
  )
1693
1778
 
1694
- # Call method opts_execute_approved_block
1695
- c.execute_approved_block([], MarkdownExec::FCB.new)
1779
+ # Call method opts_execute_required_lines
1780
+ c.execute_required_lines([])
1696
1781
  end
1697
1782
 
1698
1783
  # Test case for empty body
1699
1784
  def test_push_link_history_and_trigger_load_with_empty_body
1700
- assert_equal LoadFileNextBlock.new(LoadFile::Reuse, ''),
1701
- @hd.push_link_history_and_trigger_load([], nil, false)
1785
+ assert_equal LoadFile::Reuse,
1786
+ @hd.push_link_history_and_trigger_load([], nil, FCB.new).load_file
1702
1787
  end
1703
1788
 
1704
1789
  # Test case for non-empty body without 'file' key
1705
1790
  def test_push_link_history_and_trigger_load_without_file_key
1706
1791
  body = ["vars:\n KEY: VALUE"]
1707
- assert_equal LoadFileNextBlock.new(LoadFile::Reuse, ''),
1708
- @hd.push_link_history_and_trigger_load(body, nil, false)
1792
+ assert_equal LoadFile::Reuse,
1793
+ @hd.push_link_history_and_trigger_load(body, nil, FCB.new).load_file
1709
1794
  end
1710
1795
 
1711
1796
  # Test case for non-empty body with 'file' key
1712
1797
  def test_push_link_history_and_trigger_load_with_file_key
1713
1798
  body = ["file: sample_file\nblock: sample_block\nvars:\n KEY: VALUE"]
1714
- expected_result = LoadFileNextBlock.new(LoadFile::Load,
1715
- 'sample_block')
1716
- # mdoc = MDoc.new()
1799
+ expected_result = LoadFileLinkState.new(LoadFile::Load,
1800
+ LinkState.new(block_name: 'sample_block',
1801
+ document_filename: 'sample_file',
1802
+ inherited_dependencies: {},
1803
+ inherited_lines: []))
1717
1804
  assert_equal expected_result,
1718
- @hd.push_link_history_and_trigger_load(body, nil, FCB.new)
1719
- end
1720
-
1721
- def test_history_env_state_exist_with_value
1722
- ENV[MDE_HISTORY_ENV_NAME] = 'history_value'
1723
- assert @hd.history_env_state_exist?
1724
- end
1725
-
1726
- def test_history_env_state_exist_without_value
1727
- ENV[MDE_HISTORY_ENV_NAME] = ''
1728
- refute @hd.history_env_state_exist?
1729
- end
1730
-
1731
- def test_history_env_state_exist_not_set
1732
- ENV.delete(MDE_HISTORY_ENV_NAME)
1733
- refute @hd.history_env_state_exist?
1805
+ @hd.push_link_history_and_trigger_load(body, nil, FCB.new(block_name: 'sample_block',
1806
+ filename: 'sample_file'))
1734
1807
  end
1735
1808
 
1736
1809
  def test_indent_all_lines_with_indent
@@ -1754,22 +1827,6 @@ if $PROGRAM_NAME == __FILE__
1754
1827
  assert_equal body, @hd.indent_all_lines(body, indent)
1755
1828
  end
1756
1829
 
1757
- def test_read_required_blocks_from_temp_file
1758
- Tempfile.create do |file|
1759
- file.write("Line 1\nLine 2")
1760
- file.rewind
1761
- ENV['MDE_LINK_REQUIRED_FILE'] = file.path
1762
-
1763
- result = @hd.read_required_blocks_from_temp_file
1764
- assert_equal ['Line 1', 'Line 2'], result
1765
- end
1766
- end
1767
-
1768
- def test_read_required_blocks_from_temp_file_no_file
1769
- ENV['MDE_LINK_REQUIRED_FILE'] = nil
1770
- assert_empty @hd.read_required_blocks_from_temp_file
1771
- end
1772
-
1773
1830
  def test_safeval_successful_evaluation
1774
1831
  assert_equal 4, @hd.safeval('2 + 2')
1775
1832
  end
@@ -1799,8 +1856,6 @@ if $PROGRAM_NAME == __FILE__
1799
1856
  }
1800
1857
  ]
1801
1858
 
1802
- # hd = HashDelegator.new
1803
-
1804
1859
  # iterate over the input and output data and
1805
1860
  # assert that the method sets the title as expected
1806
1861
  input_output_data.each do |data|
@@ -1847,7 +1902,7 @@ if $PROGRAM_NAME == __FILE__
1847
1902
 
1848
1903
  assert_empty menu_blocks
1849
1904
  end
1850
- end # class TestHashDelegator
1905
+ end
1851
1906
 
1852
1907
  class TestHashDelegatorBlockFind < Minitest::Test
1853
1908
  def setup
@@ -1871,7 +1926,7 @@ if $PROGRAM_NAME == __FILE__
1871
1926
  result = @hd.block_find(blocks, :key, 'value3', 'default')
1872
1927
  assert_equal 'default', result
1873
1928
  end
1874
- end # class TestHashDelegator
1929
+ end
1875
1930
 
1876
1931
  class TestHashDelegatorBlocksFromNestedFiles < Minitest::Test
1877
1932
  def setup
@@ -1898,7 +1953,7 @@ if $PROGRAM_NAME == __FILE__
1898
1953
 
1899
1954
  assert_kind_of Array, result
1900
1955
  end
1901
- end # class TestHashDelegator
1956
+ end
1902
1957
 
1903
1958
  class TestHashDelegatorCollectRequiredCodeLines < Minitest::Test
1904
1959
  def setup
@@ -1914,13 +1969,11 @@ if $PROGRAM_NAME == __FILE__
1914
1969
  def test_collect_required_code_lines_with_vars
1915
1970
  YAML.stubs(:load).returns({ 'key' => 'value' })
1916
1971
  @mdoc.stubs(:collect_recursively_required_code).returns({ code: ['code line'] })
1917
- ENV.stubs(:[]=)
1918
-
1919
- result = @hd.collect_required_code_lines(@mdoc, @selected)
1972
+ result = @hd.collect_required_code_lines(@mdoc, @selected, block_source: {})
1920
1973
 
1921
1974
  assert_equal ['code line'], result
1922
1975
  end
1923
- end # class TestHashDelegator
1976
+ end
1924
1977
 
1925
1978
  class TestHashDelegatorCommandOrUserSelectedBlock < Minitest::Test
1926
1979
  def setup
@@ -1951,7 +2004,7 @@ if $PROGRAM_NAME == __FILE__
1951
2004
  assert_equal block_state.block, result.block
1952
2005
  assert_equal :some_state, result.state
1953
2006
  end
1954
- end # class TestHashDelegator
2007
+ end
1955
2008
 
1956
2009
  class TestHashDelegatorCountBlockInFilename < Minitest::Test
1957
2010
  def setup
@@ -1980,7 +2033,7 @@ if $PROGRAM_NAME == __FILE__
1980
2033
 
1981
2034
  assert_equal 0, count
1982
2035
  end
1983
- end # class TestHashDelegator
2036
+ end
1984
2037
 
1985
2038
  class TestHashDelegatorCreateAndWriteFile < Minitest::Test
1986
2039
  def setup
@@ -1991,7 +2044,7 @@ if $PROGRAM_NAME == __FILE__
1991
2044
  File.stubs(:chmod)
1992
2045
  end
1993
2046
 
1994
- def test_create_and_write_file_with_permissions
2047
+ def test_create_file_and_write_string_with_permissions
1995
2048
  file_path = '/path/to/file'
1996
2049
  content = 'sample content'
1997
2050
  chmod_value = 0o644
@@ -2000,8 +2053,8 @@ if $PROGRAM_NAME == __FILE__
2000
2053
  File.expects(:write).with(file_path, content).once
2001
2054
  File.expects(:chmod).with(chmod_value, file_path).once
2002
2055
 
2003
- @hd.create_and_write_file_with_permissions(file_path, content,
2004
- chmod_value)
2056
+ @hd.create_file_and_write_string_with_permissions(file_path, content,
2057
+ chmod_value)
2005
2058
 
2006
2059
  assert true # Placeholder for actual test assertions
2007
2060
  end
@@ -2015,70 +2068,12 @@ if $PROGRAM_NAME == __FILE__
2015
2068
  File.expects(:write).with(file_path, content).once
2016
2069
  File.expects(:chmod).never
2017
2070
 
2018
- @hd.create_and_write_file_with_permissions(file_path, content,
2019
- chmod_value)
2020
-
2021
- assert true # Placeholder for actual test assertions
2022
- end
2023
- end # class TestHashDelegator
2024
-
2025
- class TestHashDelegatorCreateTempFile < Minitest::Test
2026
- def setup
2027
- @hd = HashDelegator.new
2028
- @temp_file_path = '/tmp/tempfile'
2029
- end
2030
-
2031
- def test_create_temp_file_with_code
2032
- Dir::Tmpname.stubs(:create).returns(@temp_file_path)
2033
- File.stubs(:write).with(@temp_file_path, 'code_blocks')
2034
- # ENV.expects(:[]=).with('MDE_LINK_REQUIRED_FILE', @temp_file_path)
2035
-
2036
- @hd.create_temp_file_with_code('code_blocks')
2037
-
2038
- assert true # Placeholder for actual test assertions
2039
- end
2040
- end # class TestHashDelegator
2041
-
2042
- class TestHashDelegatorDeleteRequiredTempFile < Minitest::Test
2043
- def setup
2044
- @hd = HashDelegator.new
2045
- @hd.stubs(:error_handler)
2046
- @hd.stubs(:clear_required_file)
2047
- FileUtils.stubs(:rm_f)
2048
- end
2049
-
2050
- def test_delete_required_temp_file_with_existing_file
2051
- ENV.stubs(:fetch).with('MDE_LINK_REQUIRED_FILE',
2052
- nil).returns('/path/to/temp_file')
2053
- FileUtils.expects(:rm_f).with('/path/to/temp_file').once
2054
- @hd.expects(:clear_required_file).once
2055
-
2056
- @hd.delete_required_temp_file
2057
-
2058
- assert true # Placeholder for actual test assertions
2059
- end
2060
-
2061
- def test_delete_required_temp_file_with_no_file
2062
- ENV.stubs(:fetch).with('MDE_LINK_REQUIRED_FILE', nil).returns(nil)
2063
- FileUtils.expects(:rm_f).never
2064
- @hd.expects(:clear_required_file).never
2065
-
2066
- @hd.delete_required_temp_file
2067
-
2068
- assert true # Placeholder for actual test assertions
2069
- end
2070
-
2071
- def test_delete_required_temp_file_with_error
2072
- ENV.stubs(:fetch).with('MDE_LINK_REQUIRED_FILE',
2073
- nil).returns('/path/to/temp_file')
2074
- FileUtils.stubs(:rm_f).raises(StandardError)
2075
- @hd.expects(:error_handler).with('delete_required_temp_file').once
2076
-
2077
- @hd.delete_required_temp_file
2071
+ @hd.create_file_and_write_string_with_permissions(file_path, content,
2072
+ chmod_value)
2078
2073
 
2079
2074
  assert true # Placeholder for actual test assertions
2080
2075
  end
2081
- end # class TestHashDelegator
2076
+ end
2082
2077
 
2083
2078
  class TestHashDelegatorDetermineBlockState < Minitest::Test
2084
2079
  def setup
@@ -2113,7 +2108,7 @@ if $PROGRAM_NAME == __FILE__
2113
2108
  assert_equal MenuState::CONTINUE, result.state
2114
2109
  assert_equal selected_option, result.block
2115
2110
  end
2116
- end # class TestHashDelegator
2111
+ end
2117
2112
 
2118
2113
  class TestHashDelegatorDisplayRequiredCode < Minitest::Test
2119
2114
  def setup
@@ -2134,7 +2129,7 @@ if $PROGRAM_NAME == __FILE__
2134
2129
  # Verifying that fout is called for each line and for header & footer
2135
2130
  assert true # Placeholder for actual test assertions
2136
2131
  end
2137
- end # class TestHashDelegator
2132
+ end
2138
2133
 
2139
2134
  class TestHashDelegatorFetchColor < Minitest::Test
2140
2135
  def setup
@@ -2165,7 +2160,7 @@ if $PROGRAM_NAME == __FILE__
2165
2160
 
2166
2161
  assert_equal 'Default Colored String', result
2167
2162
  end
2168
- end # class TestHashDelegator
2163
+ end
2169
2164
 
2170
2165
  class TestHashDelegatorFormatReferencesSendColor < Minitest::Test
2171
2166
  def setup
@@ -2196,7 +2191,7 @@ if $PROGRAM_NAME == __FILE__
2196
2191
 
2197
2192
  assert_equal 'Default Colored String', result
2198
2193
  end
2199
- end # class TestHashDelegator
2194
+ end
2200
2195
 
2201
2196
  class TestHashDelegatorFormatExecutionStreams < Minitest::Test
2202
2197
  def setup
@@ -2229,7 +2224,7 @@ if $PROGRAM_NAME == __FILE__
2229
2224
 
2230
2225
  assert_equal '', result
2231
2226
  end
2232
- end # class TestHashDelegator
2227
+ end
2233
2228
 
2234
2229
  class TestHashDelegatorHandleBackLink < Minitest::Test
2235
2230
  def setup
@@ -2239,16 +2234,16 @@ if $PROGRAM_NAME == __FILE__
2239
2234
 
2240
2235
  def test_pop_link_history_and_trigger_load
2241
2236
  # Verifying that history_state_pop is called
2242
- @hd.expects(:history_state_pop).once
2237
+ # @hd.expects(:history_state_pop).once
2243
2238
 
2244
2239
  result = @hd.pop_link_history_and_trigger_load
2245
2240
 
2246
- # Asserting the result is an instance of LoadFileNextBlock
2247
- assert_instance_of LoadFileNextBlock, result
2241
+ # Asserting the result is an instance of LoadFileLinkState
2242
+ assert_instance_of LoadFileLinkState, result
2248
2243
  assert_equal LoadFile::Load, result.load_file
2249
- assert_equal '', result.next_block
2244
+ assert_nil result.link_state.block_name
2250
2245
  end
2251
- end # class TestHashDelegator
2246
+ end
2252
2247
 
2253
2248
  class TestHashDelegatorHandleBlockState < Minitest::Test
2254
2249
  def setup
@@ -2287,7 +2282,7 @@ if $PROGRAM_NAME == __FILE__
2287
2282
  assert_nil @hd.instance_variable_get(:@delegate_object)[:block_name]
2288
2283
  assert_nil @hd.instance_variable_get(:@menu_user_clicked_back_link)
2289
2284
  end
2290
- end # class TestHashDelegator
2285
+ end
2291
2286
 
2292
2287
  class TestHashDelegatorHandleGenericBlock < Minitest::Test
2293
2288
  def setup
@@ -2327,40 +2322,6 @@ if $PROGRAM_NAME == __FILE__
2327
2322
  end
2328
2323
  end
2329
2324
 
2330
- class TestHashDelegatorHandleOptsBlock < Minitest::Test
2331
- def setup
2332
- @hd = HashDelegator.new
2333
- @hd.instance_variable_set(:@delegate_object,
2334
- { menu_opts_set_format: 'Option: %<key>s, Value: %<value>s',
2335
- menu_opts_set_color: :blue })
2336
- @hd.stubs(:string_send_color)
2337
- @hd.stubs(:print)
2338
- end
2339
-
2340
- def test_update_options_and_trigger_reuse
2341
- selected = { body: ['option1: value1'] }
2342
- tgt2 = {}
2343
-
2344
- result = @hd.update_options_and_trigger_reuse(selected, tgt2)
2345
-
2346
- assert_instance_of LoadFileNextBlock, result
2347
- assert_equal 'value1',
2348
- @hd.instance_variable_get(:@delegate_object)[:option1]
2349
- assert_equal 'value1', tgt2[:option1]
2350
- end
2351
-
2352
- def test_update_options_and_trigger_reuse_without_format
2353
- selected = { body: ['option2: value2'] }
2354
- @hd.instance_variable_set(:@delegate_object, {})
2355
-
2356
- result = @hd.update_options_and_trigger_reuse(selected)
2357
-
2358
- assert_instance_of LoadFileNextBlock, result
2359
- assert_equal 'value2',
2360
- @hd.instance_variable_get(:@delegate_object)[:option2]
2361
- end
2362
- end
2363
-
2364
2325
  # require 'stringio'
2365
2326
 
2366
2327
  class TestHashDelegatorHandleStream < Minitest::Test
@@ -2398,94 +2359,6 @@ if $PROGRAM_NAME == __FILE__
2398
2359
  end
2399
2360
  end
2400
2361
 
2401
- class TestHashDelegatorHistoryStatePartition < Minitest::Test
2402
- def setup
2403
- @hd = HashDelegator.new
2404
- @hd.instance_variable_set(:@delegate_object, {
2405
- history_document_separator: '|'
2406
- })
2407
- end
2408
-
2409
- def test_history_state_partition_with_value
2410
- ENV[MDE_HISTORY_ENV_NAME] = 'part1|part2'
2411
-
2412
- result = @hd.history_state_partition
2413
- assert_equal({ unit: 'part1', rest: 'part2' }, result)
2414
- end
2415
-
2416
- def test_history_state_partition_with_no_separator
2417
- ENV[MDE_HISTORY_ENV_NAME] = 'onlypart'
2418
-
2419
- result = @hd.history_state_partition
2420
- assert_equal({ unit: 'onlypart', rest: '' }, result)
2421
- end
2422
-
2423
- def test_history_state_partition_with_empty_env
2424
- ENV[MDE_HISTORY_ENV_NAME] = ''
2425
-
2426
- result = @hd.history_state_partition
2427
- assert_equal({ unit: '', rest: '' }, result)
2428
- end
2429
- end
2430
-
2431
- class TestHashDelegatorHistoryStatePop < Minitest::Test
2432
- def setup
2433
- @hd = HashDelegator.new
2434
- @hd.instance_variable_set(:@delegate_object,
2435
- { filename: 'initial.md' })
2436
- @hd.instance_variable_set(:@run_state,
2437
- OpenStruct.new(link_history: [{ block_name: 'block1',
2438
- filename: 'file1.md' }]))
2439
- @hd.stubs(:history_state_partition).returns({ unit: 'file2.md',
2440
- rest: 'history_data' })
2441
- @hd.stubs(:delete_required_temp_file)
2442
- end
2443
-
2444
- def test_history_state_pop
2445
- ENV[MDE_HISTORY_ENV_NAME] = 'some_history'
2446
-
2447
- @hd.history_state_pop
2448
-
2449
- assert_equal 'file2.md',
2450
- @hd.instance_variable_get(:@delegate_object)[:filename]
2451
- assert_equal 'history_data',
2452
- ENV.fetch(MDE_HISTORY_ENV_NAME, nil)
2453
- assert_empty @hd.instance_variable_get(:@run_state).link_history
2454
- end
2455
- end
2456
-
2457
- class TestHashDelegatorHistoryStatePush < Minitest::Test
2458
- def setup
2459
- @hd = HashDelegator.new
2460
- @hd.instance_variable_set(:@delegate_object, {
2461
- filename: 'test.md',
2462
- block_name: 'test_block',
2463
- history_document_separator: '||'
2464
- })
2465
- @hd.instance_variable_set(:@run_state,
2466
- OpenStruct.new(link_history: []))
2467
- @hd.stubs(:write_required_blocks_to_temp_file)
2468
- end
2469
-
2470
- def test_history_state_push
2471
- mdoc = 'markdown content'
2472
- data_file = 'data.md'
2473
- selected = { oname: 'selected_block' }
2474
-
2475
- ENV[MDE_HISTORY_ENV_NAME] = 'existing_history'
2476
-
2477
- @hd.history_state_push(mdoc, data_file, selected)
2478
-
2479
- assert_equal 'data.md',
2480
- @hd.instance_variable_get(:@delegate_object)[:filename]
2481
- assert_equal 'test.md||existing_history',
2482
- ENV.fetch(MDE_HISTORY_ENV_NAME, nil)
2483
- assert_includes @hd.instance_variable_get(:@run_state).link_history,
2484
- { block_name: 'selected_block',
2485
- filename: 'data.md' }
2486
- end
2487
- end
2488
-
2489
2362
  class TestHashDelegatorIterBlocksFromNestedFiles < Minitest::Test
2490
2363
  def setup
2491
2364
  @hd = HashDelegator.new
@@ -2516,39 +2389,6 @@ if $PROGRAM_NAME == __FILE__
2516
2389
  end
2517
2390
  end
2518
2391
 
2519
- class TestHashDelegatorLoadAutoBlocks < Minitest::Test
2520
- def setup
2521
- @hd = HashDelegator.new
2522
- @hd.stubs(:block_find).returns({})
2523
- @hd.stubs(:update_options_and_trigger_reuse)
2524
- end
2525
-
2526
- def test_load_auto_blocks_with_new_filename
2527
- @hd.instance_variable_set(:@delegate_object, {
2528
- document_load_opts_block_name: 'load_block',
2529
- filename: 'new_file'
2530
- })
2531
- assert @hd.load_auto_blocks([])
2532
- end
2533
-
2534
- def test_load_auto_blocks_with_same_filename
2535
- @hd.instance_variable_set(:@delegate_object, {
2536
- document_load_opts_block_name: 'load_block',
2537
- filename: 'new_file'
2538
- })
2539
- @hd.instance_variable_set(:@most_recent_loaded_filename, 'new_file')
2540
- assert_nil @hd.load_auto_blocks([])
2541
- end
2542
-
2543
- def test_load_auto_blocks_without_block_name
2544
- @hd.instance_variable_set(:@delegate_object, {
2545
- document_load_opts_block_name: nil,
2546
- filename: 'new_file'
2547
- })
2548
- assert_nil @hd.load_auto_blocks([])
2549
- end
2550
- end
2551
-
2552
2392
  class TestHashDelegatorMenuChromeColoredOption < Minitest::Test
2553
2393
  def setup
2554
2394
  @hd = HashDelegator.new
@@ -2657,7 +2497,7 @@ if $PROGRAM_NAME == __FILE__
2657
2497
  result = @hd.yield_line_if_selected('Test line', [:line])
2658
2498
  assert_nil result
2659
2499
  end
2660
- end # class TestHashDelegator
2500
+ end
2661
2501
 
2662
2502
  class TestHashDelegator < Minitest::Test
2663
2503
  def setup
@@ -2743,7 +2583,6 @@ if $PROGRAM_NAME == __FILE__
2743
2583
  end
2744
2584
  end
2745
2585
 
2746
- ####
2747
2586
  class TestHashDelegatorYieldToBlock < Minitest::Test
2748
2587
  def setup
2749
2588
  @hd = HashDelegator.new