markdown_exec 1.8.2 → 1.8.5

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