markdown_exec 1.8.2 → 1.8.4

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,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