markdown_exec 1.8.2 → 1.8.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -24,6 +24,7 @@ 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'
28
29
  require_relative 'string_util'
29
30
 
@@ -115,6 +116,7 @@ module MarkdownExec
115
116
  @run_state = OpenStruct.new(
116
117
  link_history: []
117
118
  )
119
+ @link_history = LinkHistory.new
118
120
  @fout = FOut.new(@delegate_object) ### slice only relevant keys
119
121
 
120
122
  @process_mutex = Mutex.new
@@ -167,9 +169,7 @@ module MarkdownExec
167
169
  def append_chrome_block(menu_blocks, type)
168
170
  case type
169
171
  when MenuState::BACK
170
- state = history_state_partition
171
- @hs_curr = state[:unit]
172
- @hs_rest = state[:rest]
172
+ history_state_partition
173
173
  option_name = @delegate_object[:menu_option_back_name]
174
174
  insert_at_top = @delegate_object[:menu_back_at_top]
175
175
  when MenuState::EXIT
@@ -181,13 +181,9 @@ module MarkdownExec
181
181
  safeval(option_name))
182
182
  chrome_block = FCB.new(
183
183
  chrome: true,
184
-
185
- # dname: formatted_name.send(@delegate_object[:menu_link_color].to_sym),
186
184
  dname: HashDelegator.new(@delegate_object).string_send_color(
187
185
  formatted_name, :menu_link_color
188
186
  ),
189
- #dname: @delegate_object.string_send_color(formatted_name, :menu_link_color),
190
-
191
187
  oname: formatted_name
192
188
  )
193
189
 
@@ -276,21 +272,35 @@ module MarkdownExec
276
272
  true
277
273
  end
278
274
 
275
+ def code_join(*bodies)
276
+ bc = bodies&.compact
277
+ bc.count.positive? ? bc.join("\n") : nil
278
+ end
279
+
280
+ def code_merge(*bodies)
281
+ merge_lists(*bodies)
282
+ end
283
+
279
284
  # Collects required code lines based on the selected block and the delegate object's configuration.
280
285
  # If the block type is VARS, it also sets environment variables based on the block's content.
281
286
  #
282
287
  # @param mdoc [YourMDocClass] An instance of the MDoc class.
283
288
  # @param selected [Hash] The selected block.
284
289
  # @return [Array<String>] Required code blocks as an array of lines.
285
- def collect_required_code_lines(mdoc, selected)
290
+ def collect_required_code_lines(mdoc, selected, link_state = LinkState.new, block_source:)
286
291
  set_environment_variables_for_block(selected) if selected[:shell] == BlockType::VARS
287
292
 
288
293
  required = mdoc.collect_recursively_required_code(
289
294
  @delegate_object[:block_name],
290
295
  label_format_above: @delegate_object[:shell_code_label_format_above],
291
- label_format_below: @delegate_object[:shell_code_label_format_below]
296
+ label_format_below: @delegate_object[:shell_code_label_format_below],
297
+ block_source: block_source
292
298
  )
299
+ required[:unmet_dependencies] =
300
+ (required[:unmet_dependencies] || []) - (link_state&.inherited_block_names || [])
293
301
  if required[:unmet_dependencies].present?
302
+ ### filter against link_state.inherited_block_names
303
+
294
304
  warn format_and_highlight_dependencies(required[:dependencies],
295
305
  highlight: required[:unmet_dependencies])
296
306
  runtime_exception(:runtime_exception_error_level,
@@ -299,7 +309,8 @@ module MarkdownExec
299
309
  warn format_and_highlight_dependencies(required[:dependencies],
300
310
  highlight: [@delegate_object[:block_name]])
301
311
  end
302
- read_required_blocks_from_temp_file + required[:code]
312
+
313
+ code_merge link_state&.inherited_lines, required[:code]
303
314
  end
304
315
 
305
316
  def command_execute(command, args: [])
@@ -369,15 +380,18 @@ module MarkdownExec
369
380
  #
370
381
  # @param mdoc [Object] The markdown document object containing code blocks.
371
382
  # @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)
383
+ # @return [LoadFileLinkState] An object indicating whether to load the next block or reuse the current one.
384
+ def compile_execute_bash_and_special_blocks_and_trigger_reuse(mdoc, selected,
385
+ link_state = nil, block_source:)
386
+ required_lines = collect_required_code_lines(mdoc, selected, link_state,
387
+ block_source: block_source)
375
388
  output_or_approval = @delegate_object[:output_script] || @delegate_object[:user_must_approve]
376
389
  display_required_code(required_lines) if output_or_approval
377
390
  allow_execution = @delegate_object[:user_must_approve] ? prompt_for_user_approval(required_lines) : true
378
- execute_approved_block(required_lines, selected) if allow_execution
391
+ execute_required_lines(required_lines) if allow_execution
379
392
 
380
- LoadFileNextBlock.new(LoadFile::Reuse, '')
393
+ link_state.block_name = nil
394
+ LoadFileLinkState.new(LoadFile::Reuse, link_state)
381
395
  end
382
396
 
383
397
  def copy_to_clipboard(required_lines)
@@ -458,13 +472,13 @@ module MarkdownExec
458
472
  # @param file_path [String] The path where the file will be created.
459
473
  # @param content [String] The content to write into the file.
460
474
  # @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)
475
+ def create_file_and_write_string_with_permissions(file_path, content,
476
+ chmod_value)
463
477
  create_directory_for_file(file_path)
464
- write_file_content(file_path, content)
478
+ File.write(file_path, content)
465
479
  set_file_permissions(file_path, chmod_value) unless chmod_value.zero?
466
480
  rescue StandardError
467
- error_handler('create_and_write_file_with_permissions')
481
+ error_handler('create_file_and_write_string_with_permissions')
468
482
  end
469
483
 
470
484
  # private
@@ -486,15 +500,6 @@ module MarkdownExec
486
500
  )
487
501
  end
488
502
 
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
503
  # private
499
504
 
500
505
  def create_temp_file
@@ -519,13 +524,10 @@ module MarkdownExec
519
524
  # Deletes a temporary file specified by an environment variable.
520
525
  # Checks if the file exists before attempting to delete it and clears the environment variable afterward.
521
526
  # 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
-
527
+ def delete_required_temp_file(temp_blocks_file_path)
525
528
  return if temp_blocks_file_path.nil? || temp_blocks_file_path.empty?
526
529
 
527
530
  safely_remove_file(temp_blocks_file_path)
528
- clear_required_file
529
531
  rescue StandardError
530
532
  error_handler('delete_required_temp_file')
531
533
  end
@@ -581,9 +583,9 @@ module MarkdownExec
581
583
  #
582
584
  # @param required_lines [Array<String>] The lines of code to be executed.
583
585
  # @param selected [FCB] The selected functional code block object.
584
- def execute_approved_block(required_lines = [], _selected = FCB.new)
586
+ def execute_required_lines(required_lines = [])
585
587
  # set_script_block_name(selected)
586
- write_command_file_if_needed(required_lines)
588
+ save_executed_script_if_specified(required_lines)
587
589
  format_and_execute_command(required_lines)
588
590
  post_execution_process
589
591
  end
@@ -597,15 +599,21 @@ module MarkdownExec
597
599
  # @param opts [Hash] Options hash containing configuration settings.
598
600
  # @param mdoc [YourMDocClass] An instance of the MDoc class.
599
601
  #
600
- def execute_bash_and_special_blocks(selected, mdoc)
602
+ def execute_bash_and_special_blocks(selected, mdoc, link_state = LinkState.new,
603
+ block_source:)
601
604
  if selected.fetch(:shell, '') == BlockType::LINK
602
- push_link_history_and_trigger_load(selected.fetch(:body, ''), mdoc, selected)
605
+ push_link_history_and_trigger_load(selected.fetch(:body, ''), mdoc, selected,
606
+ link_state)
607
+
603
608
  elsif @menu_user_clicked_back_link
604
609
  pop_link_history_and_trigger_load
610
+
605
611
  elsif selected[:shell] == BlockType::OPTS
606
- update_options_and_trigger_reuse(selected, @menu_base_options)
612
+ update_options_and_trigger_reuse(selected, @menu_base_options, link_state)
613
+
607
614
  else
608
- compile_execute_bash_and_special_blocks_and_trigger_reuse(mdoc, selected)
615
+ compile_execute_bash_and_special_blocks_and_trigger_reuse(mdoc, selected, link_state,
616
+ block_source: block_source)
609
617
  end
610
618
  end
611
619
 
@@ -623,13 +631,8 @@ module MarkdownExec
623
631
  string_send_color(data_string, color_sym)
624
632
  end
625
633
 
626
- def fetch_temp_blocks_file_path
627
- ENV.fetch('MDE_LINK_REQUIRED_FILE', nil)
628
- end
629
-
630
634
  # DebugHelper.d ["HDmm method_name: #{method_name}", "#{first_n_caller_items 1}"]
631
635
  def first_n_caller_items(n)
632
- # Get the call stack
633
636
  call_stack = caller
634
637
  base_path = File.realpath('.')
635
638
 
@@ -704,6 +707,7 @@ module MarkdownExec
704
707
  #
705
708
  # @param block_state [Object] An object representing the state of a block in the menu.
706
709
  def handle_block_state(block_state)
710
+ return if block_state.nil?
707
711
  unless [MenuState::BACK,
708
712
  MenuState::CONTINUE].include?(block_state.state)
709
713
  return
@@ -735,52 +739,6 @@ module MarkdownExec
735
739
  end
736
740
  end
737
741
 
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
742
  # Indents all lines in a given string with a specified indentation string.
785
743
  # @param body [String] A multi-line string to be indented.
786
744
  # @param indent [String] The string used for indentation (default is an empty string).
@@ -845,6 +803,31 @@ module MarkdownExec
845
803
  end
846
804
  end
847
805
 
806
+ def link_history_push_and_next(
807
+ curr_block_name:, curr_document_filename:,
808
+ inherited_block_names:, inherited_lines:,
809
+ next_block_name:, next_document_filename:,
810
+ next_load_file:
811
+ )
812
+ @link_history.push(
813
+ LinkState.new(
814
+ block_name: curr_block_name,
815
+ document_filename: curr_document_filename,
816
+ inherited_block_names: inherited_block_names,
817
+ inherited_lines: inherited_lines
818
+ )
819
+ )
820
+ LoadFileLinkState.new(
821
+ next_load_file,
822
+ LinkState.new(
823
+ block_name: next_block_name,
824
+ document_filename: next_document_filename,
825
+ inherited_block_names: inherited_block_names,
826
+ inherited_lines: inherited_lines
827
+ )
828
+ )
829
+ end
830
+
848
831
  # Loads auto blocks based on delegate object settings and updates if new filename is detected.
849
832
  # Executes a specified block once per filename.
850
833
  # @param all_blocks [Array] Array of all block elements.
@@ -910,6 +893,12 @@ module MarkdownExec
910
893
  end
911
894
  end
912
895
 
896
+ def merge_lists(*args)
897
+ # Filters out nil values, flattens the arrays, and ensures an empty list is returned if no valid lists are provided
898
+ merged = args.compact.flatten
899
+ merged.empty? ? [] : merged
900
+ end
901
+
913
902
  # If a method is missing, treat it as a key for the @delegate_object.
914
903
  def method_missing(method_name, *args, &block)
915
904
  if @delegate_object.respond_to?(method_name)
@@ -922,11 +911,11 @@ module MarkdownExec
922
911
  end
923
912
  end
924
913
 
925
- def next_block_name_from_command_line_arguments
926
- return MenuControl::Repeat unless @delegate_object[:input_cli_rest].present?
914
+ def pop_cli_argument!
915
+ return false unless @delegate_object[:input_cli_rest].present?
927
916
 
928
- @delegate_object[:block_name] = @delegate_object[:input_cli_rest].pop
929
- MenuControl::Fresh
917
+ @cli_block_name = @delegate_object[:input_cli_rest].pop
918
+ true
930
919
  end
931
920
 
932
921
  # private
@@ -992,10 +981,15 @@ module MarkdownExec
992
981
  # This method handles the back-link operation in the Markdown execution context.
993
982
  # It updates the history state and prepares to load the next block.
994
983
  #
995
- # @return [LoadFileNextBlock] An object indicating the action to load the next block.
984
+ # @return [LoadFileLinkState] An object indicating the action to load the next block.
996
985
  def pop_link_history_and_trigger_load
997
- history_state_pop
998
- LoadFileNextBlock.new(LoadFile::Load, '')
986
+ pop = @link_history.pop
987
+ peek = @link_history.peek
988
+ LoadFileLinkState.new(LoadFile::Load, LinkState.new(
989
+ document_filename: pop.document_filename,
990
+ inherited_block_names: peek.inherited_block_names,
991
+ inherited_lines: peek.inherited_lines
992
+ ))
999
993
  end
1000
994
 
1001
995
  def post_execution_process
@@ -1010,7 +1004,6 @@ module MarkdownExec
1010
1004
  # @param opts [Hash] The options hash.
1011
1005
  # @return [Array<Hash>] The updated blocks menu.
1012
1006
  def prepare_blocks_menu(menu_blocks)
1013
- ### replace_consecutive_blanks(menu_blocks).map do |fcb|
1014
1007
  menu_blocks.map do |fcb|
1015
1008
  next if Filter.prepared_not_in_menu?(@delegate_object, fcb,
1016
1009
  %i[block_name_include_match block_name_wrapper_match])
@@ -1114,28 +1107,54 @@ module MarkdownExec
1114
1107
  # public
1115
1108
 
1116
1109
  # Handles the processing of a link block in Markdown Execution.
1117
- # It loads YAML data from the body content, pushes the state to history,
1110
+ # It loads YAML data from the link_block_body content, pushes the state to history,
1118
1111
  # sets environment variables, and decides on the next block to load.
1119
1112
  #
1120
- # @param body [Array<String>] The body content as an array of strings.
1113
+ # @param link_block_body [Array<String>] The body content as an array of strings.
1121
1114
  # @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
1115
+ # @param selected [FCB] Selected code block.
1116
+ # @return [LoadFileLinkState] Object indicating the next action for file loading.
1117
+ def push_link_history_and_trigger_load(link_block_body, mdoc, selected,
1118
+ link_state = LinkState.new)
1119
+ link_block_data = parse_yaml_data_from_body(link_block_body)
1128
1120
 
1129
- history_state_push(mdoc, data_file, selected)
1130
- set_environment_variables_per_array(data['vars'])
1121
+ # load key and values from link block into current environment
1122
+ #
1123
+ (link_block_data['vars'] || []).each do |(key, value)|
1124
+ ENV[key] = value.to_s
1125
+ end
1131
1126
 
1132
- LoadFileNextBlock.new(LoadFile::Load, data['block'] || '')
1127
+ ## collect blocks specified by block
1128
+ #
1129
+ if mdoc
1130
+ code_info = mdoc.collect_recursively_required_code(
1131
+ selected[:oname],
1132
+ label_format_above: @delegate_object[:shell_code_label_format_above],
1133
+ label_format_below: @delegate_object[:shell_code_label_format_below],
1134
+ block_source: { document_filename: link_state.document_filename }
1135
+ )
1136
+ code_lines = code_info[:code]
1137
+ block_names = code_info[:block_names]
1138
+ else
1139
+ block_names = []
1140
+ code_lines = []
1141
+ end
1142
+
1143
+ next_document_filename = link_block_data['file'] || @delegate_object[:filename]
1144
+ link_history_push_and_next(
1145
+ curr_block_name: selected[:oname],
1146
+ curr_document_filename: @delegate_object[:filename],
1147
+ inherited_block_names: ((link_state&.inherited_block_names || []) + block_names).sort.uniq,
1148
+ inherited_lines: code_merge(link_state&.inherited_lines, code_lines),
1149
+ next_block_name: link_block_data['block'] || '',
1150
+ next_document_filename: next_document_filename,
1151
+ next_load_file: next_document_filename == @delegate_object[:filename] ? LoadFile::Reuse : LoadFile::Load
1152
+ )
1133
1153
  end
1134
1154
 
1135
1155
  # Reads required code blocks from a temporary file specified by an environment variable.
1136
1156
  # @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)
1157
+ def read_required_blocks_from_temp_file(temp_blocks_file_path)
1139
1158
  return [] if temp_blocks_file_path.to_s.empty?
1140
1159
 
1141
1160
  if File.exist?(temp_blocks_file_path)
@@ -1180,12 +1199,6 @@ module MarkdownExec
1180
1199
  error_handler('safeval')
1181
1200
  end
1182
1201
 
1183
- # def safeval(str)
1184
- # eval(str)
1185
- # rescue StandardError
1186
- # error_handler('safeval')
1187
- # end
1188
-
1189
1202
  def save_to_file(required_lines)
1190
1203
  write_command_file(required_lines)
1191
1204
  @fout.fout "File saved: #{@run_state.saved_filespec}"
@@ -1199,23 +1212,25 @@ module MarkdownExec
1199
1212
  # @return [Nil] Returns nil if no code block is selected or an error occurs.
1200
1213
  def select_execute_bash_and_special_blocks(_execute: true)
1201
1214
  @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)
1215
+ link_state = LinkState.new(
1216
+ block_name: @delegate_object[:block_name],
1217
+ document_filename: @delegate_object[:filename]
1218
+ )
1219
+ block_name_from_cli = link_state.block_name.present?
1220
+ @cli_block_name = link_state.block_name
1221
+ load_file = nil
1204
1222
  menu_default_dname = nil
1205
1223
 
1206
- @menu_state_filename = @menu_base_options[:filename]
1207
- @menu_state_block_name = @menu_base_options[:block_name]
1208
-
1209
1224
  loop do
1210
1225
  loop do
1211
1226
  @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
1227
  @menu_user_clicked_back_link = false
1228
+ @delegate_object[:filename] = link_state.document_filename
1229
+ link_state.block_name = @delegate_object[:block_name] =
1230
+ block_name_from_cli ? @cli_block_name : link_state.block_name
1217
1231
 
1218
1232
  blocks_in_file, menu_blocks, mdoc = mdoc_menu_and_blocks_from_nested_files
1233
+
1219
1234
  if @delegate_object[:dump_blocks_in_file]
1220
1235
  warn format_and_highlight_dependencies(
1221
1236
  compact_and_index_hash(blocks_in_file),
@@ -1228,6 +1243,7 @@ module MarkdownExec
1228
1243
  label: 'menu_blocks'
1229
1244
  )
1230
1245
  end
1246
+
1231
1247
  block_state = command_or_user_selected_block(blocks_in_file,
1232
1248
  menu_blocks, menu_default_dname)
1233
1249
  return if block_state.state == MenuState::EXIT
@@ -1242,20 +1258,20 @@ module MarkdownExec
1242
1258
  warn block_state.block.to_yaml.sub(/^(?:---\n)?/, "Block:\n")
1243
1259
  end
1244
1260
 
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]
1251
-
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]
1261
+ load_file_link_state = execute_bash_and_special_blocks(
1262
+ block_state.block,
1263
+ mdoc,
1264
+ link_state,
1265
+ block_source: { document_filename: @delegate_object[:filename] }
1266
+ )
1267
+ load_file = load_file_link_state.load_file
1268
+ link_state = load_file_link_state.link_state
1269
+ # if the same menu is being displayed, collect the display name of the selected menu item for use as the default item
1270
+ menu_default_dname = load_file == LoadFile::Load ? nil : block_state.block[:dname]
1255
1271
 
1256
1272
  # user prompt to exit if the menu will be displayed again
1257
1273
  #
1258
- if repeat_menu == MenuControl::Repeat &&
1274
+ if !block_name_from_cli &&
1259
1275
  block_state.block[:shell] == BlockType::BASH &&
1260
1276
  @delegate_object[:pause_after_script_execution] &&
1261
1277
  prompt_select_continue == MenuState::EXIT
@@ -1264,16 +1280,12 @@ module MarkdownExec
1264
1280
 
1265
1281
  # exit current document/menu if loading next document or single block_name was specified
1266
1282
  #
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
1283
+ break if block_state.state == MenuState::CONTINUE && load_file == LoadFile::Load
1284
+ break if block_name_from_cli
1271
1285
  end
1272
- break if load_file_next_block.load_file == LoadFile::Reuse
1286
+ break if load_file == LoadFile::Reuse
1273
1287
 
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]
1288
+ block_name_from_cli = pop_cli_argument!
1277
1289
  end
1278
1290
  rescue StandardError
1279
1291
  error_handler('select_execute_bash_and_special_blocks',
@@ -1293,8 +1305,7 @@ module MarkdownExec
1293
1305
 
1294
1306
  item.merge(
1295
1307
  if selection == menu_chrome_colored_option(:menu_option_back_name)
1296
- { option: selection, curr: @hs_curr, rest: @hs_rest,
1297
- shell: BlockType::LINK }
1308
+ { option: selection, shell: BlockType::LINK }
1298
1309
  elsif selection == menu_chrome_colored_option(:menu_option_exit_name)
1299
1310
  { option: selection }
1300
1311
  else
@@ -1307,10 +1318,6 @@ module MarkdownExec
1307
1318
  error_handler('select_option_with_metadata')
1308
1319
  end
1309
1320
 
1310
- def set_environment_variable(path)
1311
- ENV['MDE_LINK_REQUIRED_FILE'] = path
1312
- end
1313
-
1314
1321
  def set_environment_variables_for_block(selected)
1315
1322
  YAML.load(selected[:body].join("\n")).each do |key, value|
1316
1323
  ENV[key] = value.to_s
@@ -1336,7 +1343,8 @@ module MarkdownExec
1336
1343
  end
1337
1344
 
1338
1345
  def should_add_back_option?
1339
- @delegate_object[:menu_with_back] && history_env_state_exist?
1346
+ @delegate_object[:menu_with_back] && @link_history.prior_state_exist?
1347
+ # @delegate_object[:menu_with_back] && link_history_prior_state_exist?
1340
1348
  end
1341
1349
 
1342
1350
  # Initializes a new fenced code block (FCB) object based on the provided line and heading information.
@@ -1397,7 +1405,6 @@ module MarkdownExec
1397
1405
  symbols: { cross: ' ' }
1398
1406
  )
1399
1407
  end
1400
- # private
1401
1408
 
1402
1409
  def update_delegate_and_target(key, value, tgt2)
1403
1410
  sym_key = key.to_sym
@@ -1473,12 +1480,9 @@ module MarkdownExec
1473
1480
  ## add line to fenced code block
1474
1481
  # remove fcb indent if possible
1475
1482
  #
1476
- # if nested_line[:depth].zero? || opts[:menu_include_imported_blocks]
1477
- # if add_import_block?(nested_line)
1478
1483
  state[:fcb].body += [
1479
1484
  line.chomp.sub(/^#{state[:fcb].indent}/, '')
1480
1485
  ]
1481
- # end
1482
1486
  elsif nested_line[:depth].zero? || @delegate_object[:menu_include_imported_notes]
1483
1487
  # add line if it is depth 0 or option allows it
1484
1488
  #
@@ -1504,14 +1508,15 @@ module MarkdownExec
1504
1508
  # Processes YAML data from the selected menu item, updating delegate objects and optionally printing formatted output.
1505
1509
  # @param selected [Hash] Selected item from the menu containing a YAML body.
1506
1510
  # @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)
1511
+ # @return [LoadFileLinkState] An instance indicating the next action for loading files.
1512
+ def update_options_and_trigger_reuse(selected, tgt2 = nil, link_state = LinkState.new)
1509
1513
  data = YAML.load(selected[:body].join("\n"))
1510
1514
  (data || []).each do |key, value|
1511
1515
  update_delegate_and_target(key, value, tgt2)
1512
1516
  print_formatted_option(key, value) if @delegate_object[:menu_opts_set_format].present?
1513
1517
  end
1514
- LoadFileNextBlock.new(LoadFile::Reuse, '')
1518
+ link_state.block_name = nil
1519
+ LoadFileLinkState.new(LoadFile::Reuse, link_state)
1515
1520
  end
1516
1521
 
1517
1522
  def wait_for_stream_processing
@@ -1523,7 +1528,6 @@ module MarkdownExec
1523
1528
  def wait_for_user_selected_block(all_blocks, menu_blocks, default)
1524
1529
  block_state = wait_for_user_selection(all_blocks, menu_blocks, default)
1525
1530
  handle_block_state(block_state)
1526
-
1527
1531
  block_state
1528
1532
  rescue StandardError
1529
1533
  error_handler('wait_for_user_selected_block')
@@ -1577,7 +1581,7 @@ module MarkdownExec
1577
1581
  "# time: #{time_now}\n" \
1578
1582
  "#{required_lines.flatten.join("\n")}\n"
1579
1583
 
1580
- create_and_write_file_with_permissions(
1584
+ create_file_and_write_string_with_permissions(
1581
1585
  @run_state.saved_filespec,
1582
1586
  content,
1583
1587
  @delegate_object[:saved_script_chmod]
@@ -1586,7 +1590,7 @@ module MarkdownExec
1586
1590
  error_handler('write_command_file')
1587
1591
  end
1588
1592
 
1589
- def write_command_file_if_needed(lines)
1593
+ def save_executed_script_if_specified(lines)
1590
1594
  write_command_file(lines) if @delegate_object[:save_executed_script]
1591
1595
  end
1592
1596
 
@@ -1605,15 +1609,11 @@ module MarkdownExec
1605
1609
  )
1606
1610
  end
1607
1611
 
1608
- def write_file_content(file_path, content)
1609
- File.write(file_path, content)
1610
- end
1611
-
1612
1612
  # Writes required code blocks to a temporary file and sets an environment variable with its path.
1613
1613
  #
1614
1614
  # @param mdoc [Object] The Markdown document object.
1615
1615
  # @param block_name [String] The name of the block to collect code for.
1616
- def write_required_blocks_to_temp_file(mdoc, block_name)
1616
+ def write_required_blocks_to_file(mdoc, block_name, temp_file_path, import_filename: nil)
1617
1617
  c1 = if mdoc
1618
1618
  mdoc.collect_recursively_required_code(
1619
1619
  block_name,
@@ -1624,13 +1624,15 @@ module MarkdownExec
1624
1624
  []
1625
1625
  end
1626
1626
 
1627
- code_blocks = (read_required_blocks_from_temp_file +
1627
+ code_blocks = (read_required_blocks_from_temp_file(import_filename) +
1628
1628
  c1).join("\n")
1629
1629
 
1630
- create_temp_file_with_code(code_blocks)
1630
+ write_code_to_file(code_blocks, temp_file_path)
1631
1631
  end
1632
1632
 
1633
- def write_to_file(path, content)
1633
+ # Writes the provided code blocks to a file.
1634
+ # @param code_blocks [String] Code blocks to write into the file.
1635
+ def write_code_to_file(content, path)
1634
1636
  File.write(path, content)
1635
1637
  end
1636
1638
 
@@ -1674,7 +1676,7 @@ if $PROGRAM_NAME == __FILE__
1674
1676
  @mdoc = mock('MarkdownDocument')
1675
1677
  end
1676
1678
 
1677
- def test_calling_execute_approved_block_calls_command_execute_with_argument_args_value
1679
+ def test_calling_execute_required_lines_calls_command_execute_with_argument_args_value
1678
1680
  pigeon = 'E'
1679
1681
  obj = {
1680
1682
  output_execution_label_format: '',
@@ -1691,46 +1693,33 @@ if $PROGRAM_NAME == __FILE__
1691
1693
  args: pigeon
1692
1694
  )
1693
1695
 
1694
- # Call method opts_execute_approved_block
1695
- c.execute_approved_block([], MarkdownExec::FCB.new)
1696
+ # Call method opts_execute_required_lines
1697
+ c.execute_required_lines([])
1696
1698
  end
1697
1699
 
1698
1700
  # Test case for empty body
1699
1701
  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)
1702
+ assert_equal LoadFile::Reuse,
1703
+ @hd.push_link_history_and_trigger_load([], nil, FCB.new).load_file
1702
1704
  end
1703
1705
 
1704
1706
  # Test case for non-empty body without 'file' key
1705
1707
  def test_push_link_history_and_trigger_load_without_file_key
1706
1708
  body = ["vars:\n KEY: VALUE"]
1707
- assert_equal LoadFileNextBlock.new(LoadFile::Reuse, ''),
1708
- @hd.push_link_history_and_trigger_load(body, nil, false)
1709
+ assert_equal LoadFile::Reuse,
1710
+ @hd.push_link_history_and_trigger_load(body, nil, FCB.new).load_file
1709
1711
  end
1710
1712
 
1711
1713
  # Test case for non-empty body with 'file' key
1712
1714
  def test_push_link_history_and_trigger_load_with_file_key
1713
1715
  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()
1716
+ expected_result = LoadFileLinkState.new(LoadFile::Load,
1717
+ LinkState.new(block_name: 'sample_block',
1718
+ document_filename: 'sample_file',
1719
+ inherited_lines: []))
1717
1720
  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?
1721
+ @hd.push_link_history_and_trigger_load(body, nil, FCB.new(block_name: 'sample_block',
1722
+ filename: 'sample_file'))
1734
1723
  end
1735
1724
 
1736
1725
  def test_indent_all_lines_with_indent
@@ -1754,22 +1743,6 @@ if $PROGRAM_NAME == __FILE__
1754
1743
  assert_equal body, @hd.indent_all_lines(body, indent)
1755
1744
  end
1756
1745
 
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
1746
  def test_safeval_successful_evaluation
1774
1747
  assert_equal 4, @hd.safeval('2 + 2')
1775
1748
  end
@@ -1799,8 +1772,6 @@ if $PROGRAM_NAME == __FILE__
1799
1772
  }
1800
1773
  ]
1801
1774
 
1802
- # hd = HashDelegator.new
1803
-
1804
1775
  # iterate over the input and output data and
1805
1776
  # assert that the method sets the title as expected
1806
1777
  input_output_data.each do |data|
@@ -1847,7 +1818,7 @@ if $PROGRAM_NAME == __FILE__
1847
1818
 
1848
1819
  assert_empty menu_blocks
1849
1820
  end
1850
- end # class TestHashDelegator
1821
+ end
1851
1822
 
1852
1823
  class TestHashDelegatorBlockFind < Minitest::Test
1853
1824
  def setup
@@ -1871,7 +1842,7 @@ if $PROGRAM_NAME == __FILE__
1871
1842
  result = @hd.block_find(blocks, :key, 'value3', 'default')
1872
1843
  assert_equal 'default', result
1873
1844
  end
1874
- end # class TestHashDelegator
1845
+ end
1875
1846
 
1876
1847
  class TestHashDelegatorBlocksFromNestedFiles < Minitest::Test
1877
1848
  def setup
@@ -1898,7 +1869,7 @@ if $PROGRAM_NAME == __FILE__
1898
1869
 
1899
1870
  assert_kind_of Array, result
1900
1871
  end
1901
- end # class TestHashDelegator
1872
+ end
1902
1873
 
1903
1874
  class TestHashDelegatorCollectRequiredCodeLines < Minitest::Test
1904
1875
  def setup
@@ -1914,13 +1885,11 @@ if $PROGRAM_NAME == __FILE__
1914
1885
  def test_collect_required_code_lines_with_vars
1915
1886
  YAML.stubs(:load).returns({ 'key' => 'value' })
1916
1887
  @mdoc.stubs(:collect_recursively_required_code).returns({ code: ['code line'] })
1917
- ENV.stubs(:[]=)
1918
-
1919
- result = @hd.collect_required_code_lines(@mdoc, @selected)
1888
+ result = @hd.collect_required_code_lines(@mdoc, @selected, block_source: {})
1920
1889
 
1921
1890
  assert_equal ['code line'], result
1922
1891
  end
1923
- end # class TestHashDelegator
1892
+ end
1924
1893
 
1925
1894
  class TestHashDelegatorCommandOrUserSelectedBlock < Minitest::Test
1926
1895
  def setup
@@ -1951,7 +1920,7 @@ if $PROGRAM_NAME == __FILE__
1951
1920
  assert_equal block_state.block, result.block
1952
1921
  assert_equal :some_state, result.state
1953
1922
  end
1954
- end # class TestHashDelegator
1923
+ end
1955
1924
 
1956
1925
  class TestHashDelegatorCountBlockInFilename < Minitest::Test
1957
1926
  def setup
@@ -1980,7 +1949,7 @@ if $PROGRAM_NAME == __FILE__
1980
1949
 
1981
1950
  assert_equal 0, count
1982
1951
  end
1983
- end # class TestHashDelegator
1952
+ end
1984
1953
 
1985
1954
  class TestHashDelegatorCreateAndWriteFile < Minitest::Test
1986
1955
  def setup
@@ -1991,7 +1960,7 @@ if $PROGRAM_NAME == __FILE__
1991
1960
  File.stubs(:chmod)
1992
1961
  end
1993
1962
 
1994
- def test_create_and_write_file_with_permissions
1963
+ def test_create_file_and_write_string_with_permissions
1995
1964
  file_path = '/path/to/file'
1996
1965
  content = 'sample content'
1997
1966
  chmod_value = 0o644
@@ -2000,8 +1969,8 @@ if $PROGRAM_NAME == __FILE__
2000
1969
  File.expects(:write).with(file_path, content).once
2001
1970
  File.expects(:chmod).with(chmod_value, file_path).once
2002
1971
 
2003
- @hd.create_and_write_file_with_permissions(file_path, content,
2004
- chmod_value)
1972
+ @hd.create_file_and_write_string_with_permissions(file_path, content,
1973
+ chmod_value)
2005
1974
 
2006
1975
  assert true # Placeholder for actual test assertions
2007
1976
  end
@@ -2015,70 +1984,12 @@ if $PROGRAM_NAME == __FILE__
2015
1984
  File.expects(:write).with(file_path, content).once
2016
1985
  File.expects(:chmod).never
2017
1986
 
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
1987
+ @hd.create_file_and_write_string_with_permissions(file_path, content,
1988
+ chmod_value)
2078
1989
 
2079
1990
  assert true # Placeholder for actual test assertions
2080
1991
  end
2081
- end # class TestHashDelegator
1992
+ end
2082
1993
 
2083
1994
  class TestHashDelegatorDetermineBlockState < Minitest::Test
2084
1995
  def setup
@@ -2113,7 +2024,7 @@ if $PROGRAM_NAME == __FILE__
2113
2024
  assert_equal MenuState::CONTINUE, result.state
2114
2025
  assert_equal selected_option, result.block
2115
2026
  end
2116
- end # class TestHashDelegator
2027
+ end
2117
2028
 
2118
2029
  class TestHashDelegatorDisplayRequiredCode < Minitest::Test
2119
2030
  def setup
@@ -2134,7 +2045,7 @@ if $PROGRAM_NAME == __FILE__
2134
2045
  # Verifying that fout is called for each line and for header & footer
2135
2046
  assert true # Placeholder for actual test assertions
2136
2047
  end
2137
- end # class TestHashDelegator
2048
+ end
2138
2049
 
2139
2050
  class TestHashDelegatorFetchColor < Minitest::Test
2140
2051
  def setup
@@ -2165,7 +2076,7 @@ if $PROGRAM_NAME == __FILE__
2165
2076
 
2166
2077
  assert_equal 'Default Colored String', result
2167
2078
  end
2168
- end # class TestHashDelegator
2079
+ end
2169
2080
 
2170
2081
  class TestHashDelegatorFormatReferencesSendColor < Minitest::Test
2171
2082
  def setup
@@ -2196,7 +2107,7 @@ if $PROGRAM_NAME == __FILE__
2196
2107
 
2197
2108
  assert_equal 'Default Colored String', result
2198
2109
  end
2199
- end # class TestHashDelegator
2110
+ end
2200
2111
 
2201
2112
  class TestHashDelegatorFormatExecutionStreams < Minitest::Test
2202
2113
  def setup
@@ -2229,7 +2140,7 @@ if $PROGRAM_NAME == __FILE__
2229
2140
 
2230
2141
  assert_equal '', result
2231
2142
  end
2232
- end # class TestHashDelegator
2143
+ end
2233
2144
 
2234
2145
  class TestHashDelegatorHandleBackLink < Minitest::Test
2235
2146
  def setup
@@ -2239,16 +2150,16 @@ if $PROGRAM_NAME == __FILE__
2239
2150
 
2240
2151
  def test_pop_link_history_and_trigger_load
2241
2152
  # Verifying that history_state_pop is called
2242
- @hd.expects(:history_state_pop).once
2153
+ # @hd.expects(:history_state_pop).once
2243
2154
 
2244
2155
  result = @hd.pop_link_history_and_trigger_load
2245
2156
 
2246
- # Asserting the result is an instance of LoadFileNextBlock
2247
- assert_instance_of LoadFileNextBlock, result
2157
+ # Asserting the result is an instance of LoadFileLinkState
2158
+ assert_instance_of LoadFileLinkState, result
2248
2159
  assert_equal LoadFile::Load, result.load_file
2249
- assert_equal '', result.next_block
2160
+ assert_nil result.link_state.block_name
2250
2161
  end
2251
- end # class TestHashDelegator
2162
+ end
2252
2163
 
2253
2164
  class TestHashDelegatorHandleBlockState < Minitest::Test
2254
2165
  def setup
@@ -2287,7 +2198,7 @@ if $PROGRAM_NAME == __FILE__
2287
2198
  assert_nil @hd.instance_variable_get(:@delegate_object)[:block_name]
2288
2199
  assert_nil @hd.instance_variable_get(:@menu_user_clicked_back_link)
2289
2200
  end
2290
- end # class TestHashDelegator
2201
+ end
2291
2202
 
2292
2203
  class TestHashDelegatorHandleGenericBlock < Minitest::Test
2293
2204
  def setup
@@ -2343,7 +2254,7 @@ if $PROGRAM_NAME == __FILE__
2343
2254
 
2344
2255
  result = @hd.update_options_and_trigger_reuse(selected, tgt2)
2345
2256
 
2346
- assert_instance_of LoadFileNextBlock, result
2257
+ assert_instance_of LoadFileLinkState, result
2347
2258
  assert_equal 'value1',
2348
2259
  @hd.instance_variable_get(:@delegate_object)[:option1]
2349
2260
  assert_equal 'value1', tgt2[:option1]
@@ -2355,7 +2266,7 @@ if $PROGRAM_NAME == __FILE__
2355
2266
 
2356
2267
  result = @hd.update_options_and_trigger_reuse(selected)
2357
2268
 
2358
- assert_instance_of LoadFileNextBlock, result
2269
+ assert_instance_of LoadFileLinkState, result
2359
2270
  assert_equal 'value2',
2360
2271
  @hd.instance_variable_get(:@delegate_object)[:option2]
2361
2272
  end
@@ -2398,94 +2309,6 @@ if $PROGRAM_NAME == __FILE__
2398
2309
  end
2399
2310
  end
2400
2311
 
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
2312
  class TestHashDelegatorIterBlocksFromNestedFiles < Minitest::Test
2490
2313
  def setup
2491
2314
  @hd = HashDelegator.new
@@ -2657,7 +2480,7 @@ if $PROGRAM_NAME == __FILE__
2657
2480
  result = @hd.yield_line_if_selected('Test line', [:line])
2658
2481
  assert_nil result
2659
2482
  end
2660
- end # class TestHashDelegator
2483
+ end
2661
2484
 
2662
2485
  class TestHashDelegator < Minitest::Test
2663
2486
  def setup