markdown_exec 1.8.7 → 1.8.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,8 @@
1
- # encoding=utf-8
1
+ #!/usr/bin/env bundle exec ruby
2
2
  # frozen_string_literal: true
3
3
 
4
+ # encoding=utf-8
5
+
4
6
  require 'English'
5
7
  require 'clipboard'
6
8
  require 'fileutils'
@@ -142,9 +144,9 @@ module HashDelegatorSelf
142
144
  # HashDelegator.remove_file_without_standard_errors(temp_blocks_file_path)
143
145
  # end
144
146
 
145
- def error_handler(name = '', opts = {})
147
+ def error_handler(name = '', opts = {}, error: $!)
146
148
  Exceptions.error_handler(
147
- "HashDelegator.#{name} -- #{$!}",
149
+ "HashDelegator.#{name} -- #{error}",
148
150
  opts
149
151
  )
150
152
  end
@@ -183,16 +185,20 @@ module HashDelegatorSelf
183
185
  fcb.oname = fcb.dname = fcb.title || ''
184
186
  end
185
187
 
188
+ def join_code_lines(lines)
189
+ ((lines || [])+ ['']).join("\n")
190
+ end
191
+
186
192
  def merge_lists(*args)
187
193
  # Filters out nil values, flattens the arrays, and ensures an empty list is returned if no valid lists are provided
188
194
  merged = args.compact.flatten
189
195
  merged.empty? ? [] : merged
190
196
  end
191
197
 
192
- def next_link_state(block_name_from_cli, was_using_cli, block_state)
198
+ def next_link_state(block_name_from_cli, was_using_cli, block_state, block_name: nil)
193
199
  # &bsp 'next_link_state', block_name_from_cli, was_using_cli, block_state
194
200
  # Set block_name based on block_name_from_cli
195
- block_name = block_name_from_cli ? @cli_block_name : nil
201
+ block_name = block_name_from_cli ? @cli_block_name : block_name
196
202
  # &bsp 'block_name:', block_name
197
203
 
198
204
  # Determine the state of breaker based on was_using_cli and the block type
@@ -555,6 +561,22 @@ module MarkdownExec
555
561
 
556
562
  # private
557
563
 
564
+ def calc_logged_stdout_filename
565
+ return unless @delegate_object[:saved_stdout_folder]
566
+
567
+ @delegate_object[:logged_stdout_filename] =
568
+ SavedAsset.stdout_name(blockname: @delegate_object[:block_name],
569
+ filename: File.basename(@delegate_object[:filename],
570
+ '.*'),
571
+ prefix: @delegate_object[:logged_stdout_filename_prefix],
572
+ time: Time.now.utc)
573
+
574
+ @logged_stdout_filespec =
575
+ @delegate_object[:logged_stdout_filespec] =
576
+ File.join @delegate_object[:saved_stdout_folder],
577
+ @delegate_object[:logged_stdout_filename]
578
+ end
579
+
558
580
  def cfile
559
581
  @cfile ||= CachedNestedFileReader.new(
560
582
  import_pattern: @delegate_object.fetch(:import_pattern) #, "^ *@import +(?<name>.+?) *$")
@@ -582,10 +604,8 @@ module MarkdownExec
582
604
  # @param selected [Hash] The selected block.
583
605
  # @return [Array<String>] Required code blocks as an array of lines.
584
606
  def collect_required_code_lines(mdoc, selected, link_state = LinkState.new, block_source:)
585
- set_environment_variables_for_block(selected) if selected[:shell] == BlockType::VARS
586
-
587
607
  required = mdoc.collect_recursively_required_code(
588
- @delegate_object[:block_name],
608
+ selected[:nickname] || selected[:oname],
589
609
  label_format_above: @delegate_object[:shell_code_label_format_above],
590
610
  label_format_below: @delegate_object[:shell_code_label_format_below],
591
611
  block_source: block_source
@@ -599,13 +619,16 @@ module MarkdownExec
599
619
  warn format_and_highlight_dependencies(dependencies,
600
620
  highlight: required[:unmet_dependencies])
601
621
  runtime_exception(:runtime_exception_error_level,
602
- 'unmet_dependencies, flag: runtime_exception_error_level', required[:unmet_dependencies])
622
+ 'unmet_dependencies, flag: runtime_exception_error_level',
623
+ required[:unmet_dependencies])
603
624
  elsif true
604
625
  warn format_and_highlight_dependencies(dependencies,
605
626
  highlight: [@delegate_object[:block_name]])
606
627
  end
607
628
 
608
- HashDelegator.code_merge(link_state&.inherited_lines, required[:code])
629
+ code_lines = selected[:shell] == BlockType::VARS ? set_environment_variables_for_block(selected) : []
630
+
631
+ HashDelegator.code_merge(link_state&.inherited_lines, required[:code] + code_lines)
609
632
  end
610
633
 
611
634
  def command_execute(command, args: [])
@@ -613,26 +636,54 @@ module MarkdownExec
613
636
  @run_state.options = @delegate_object
614
637
  @run_state.started_at = Time.now.utc
615
638
 
616
- Open3.popen3(@delegate_object[:shell],
617
- '-c', command,
618
- @delegate_object[:filename],
619
- *args) do |stdin, stdout, stderr, exec_thr|
620
- handle_stream(stdout, ExecutionStreams::StdOut) do |line|
621
- yield nil, line, nil, exec_thr if block_given?
622
- end
623
- handle_stream(stderr, ExecutionStreams::StdErr) do |line|
624
- yield nil, nil, line, exec_thr if block_given?
625
- end
639
+ if @delegate_object[:execute_in_own_window] &&
640
+ @delegate_object[:execute_command_format].present? &&
641
+ @run_state.saved_filespec.present?
642
+ @run_state.in_own_window = true
643
+ system(
644
+ format(
645
+ @delegate_object[:execute_command_format],
646
+ {
647
+ batch_index: @run_state.batch_index,
648
+ batch_random: @run_state.batch_random,
649
+ block_name: @delegate_object[:block_name],
650
+ document_filename: File.basename(@delegate_object[:filename]),
651
+ document_filespec: @delegate_object[:filename],
652
+ home: Dir.pwd,
653
+ output_filename: File.basename(@delegate_object[:logged_stdout_filespec]),
654
+ output_filespec: @delegate_object[:logged_stdout_filespec],
655
+ script_filename: @run_state.saved_filespec,
656
+ script_filespec: File.join(Dir.pwd, @run_state.saved_filespec),
657
+ started_at: @run_state.started_at.strftime(
658
+ @delegate_object[:execute_command_title_time_format]
659
+ )
660
+ }
661
+ )
662
+ )
626
663
 
627
- in_thr = handle_stream($stdin, ExecutionStreams::StdIn) do |line|
628
- stdin.puts(line)
629
- yield line, nil, nil, exec_thr if block_given?
630
- end
664
+ else
665
+ @run_state.in_own_window = false
666
+ Open3.popen3(@delegate_object[:shell],
667
+ '-c', command,
668
+ @delegate_object[:filename],
669
+ *args) do |stdin, stdout, stderr, exec_thr|
670
+ handle_stream(stdout, ExecutionStreams::StdOut) do |line|
671
+ yield nil, line, nil, exec_thr if block_given?
672
+ end
673
+ handle_stream(stderr, ExecutionStreams::StdErr) do |line|
674
+ yield nil, nil, line, exec_thr if block_given?
675
+ end
631
676
 
632
- wait_for_stream_processing
633
- exec_thr.join
634
- sleep 0.1
635
- in_thr.kill if in_thr&.alive?
677
+ in_thr = handle_stream($stdin, ExecutionStreams::StdIn) do |line|
678
+ stdin.puts(line)
679
+ yield line, nil, nil, exec_thr if block_given?
680
+ end
681
+
682
+ wait_for_stream_processing
683
+ exec_thr.join
684
+ sleep 0.1
685
+ in_thr.kill if in_thr&.alive?
686
+ end
636
687
  end
637
688
 
638
689
  @run_state.completed_at = Time.now.utc
@@ -681,9 +732,13 @@ module MarkdownExec
681
732
  block_source: block_source)
682
733
  output_or_approval = @delegate_object[:output_script] || @delegate_object[:user_must_approve]
683
734
  display_required_code(required_lines) if output_or_approval
684
- allow_execution = @delegate_object[:user_must_approve] ? prompt_for_user_approval(required_lines) : true
735
+ allow_execution = if @delegate_object[:user_must_approve]
736
+ prompt_for_user_approval(required_lines, selected)
737
+ else
738
+ true
739
+ end
685
740
 
686
- execute_required_lines(required_lines) if allow_execution
741
+ execute_required_lines(required_lines, selected) if allow_execution
687
742
 
688
743
  link_state.block_name = nil
689
744
  LoadFileLinkState.new(LoadFile::Reuse, link_state)
@@ -704,7 +759,8 @@ module MarkdownExec
704
759
  # @return [Integer] The count of fenced code blocks in the file.
705
760
  def count_blocks_in_filename
706
761
  regex = Regexp.new(@delegate_object[:fenced_start_and_end_regex])
707
- lines = cfile.readlines(@delegate_object[:filename])
762
+ lines = cfile.readlines(@delegate_object[:filename],
763
+ import_paths: @delegate_object[:import_paths]&.split(':'))
708
764
  HashDelegator.count_matches_in_lines(lines, regex) / 2
709
765
  end
710
766
 
@@ -734,14 +790,14 @@ module MarkdownExec
734
790
  # @param use_chrome [Boolean] Indicates if the chrome styling should be applied.
735
791
  def create_and_add_chrome_blocks(blocks, fcb)
736
792
  match_criteria = [
737
- { match: :heading1_match, format: :menu_heading1_format, color: :menu_heading1_color },
738
- { match: :heading2_match, format: :menu_heading2_format, color: :menu_heading2_color },
739
- { match: :heading3_match, format: :menu_heading3_format, color: :menu_heading3_color },
740
- { match: :menu_divider_match, format: :menu_divider_format,
741
- color: :menu_divider_color },
742
- { match: :menu_note_match, format: :menu_note_format, color: :menu_note_color },
743
- { match: :menu_task_match, format: :menu_task_format, color: :menu_task_color }
793
+ { color: :menu_heading1_color, format: :menu_heading1_format, match: :heading1_match },
794
+ { color: :menu_heading2_color, format: :menu_heading2_format, match: :heading2_match },
795
+ { color: :menu_heading3_color, format: :menu_heading3_format, match: :heading3_match },
796
+ { color: :menu_divider_color, format: :menu_divider_format, match: :menu_divider_match },
797
+ { color: :menu_note_color, format: :menu_note_format, match: :menu_note_match },
798
+ { color: :menu_task_color, format: :menu_task_format, match: :menu_task_match }
744
799
  ]
800
+ # rubocop:enable Style/UnlessElse
745
801
  match_criteria.each do |criteria|
746
802
  unless @delegate_object[criteria[:match]].present? &&
747
803
  (mbody = fcb.body[0].match @delegate_object[criteria[:match]])
@@ -767,6 +823,29 @@ module MarkdownExec
767
823
  )
768
824
  end
769
825
 
826
+ # Prompts user if named block is the same as the prior execution.
827
+ #
828
+ # @return [Boolean] Execute the named block.
829
+ def debounce_allows
830
+ return true unless @delegate_object[:debounce_execution]
831
+
832
+ # filter block if selected in menu
833
+ return true if @run_state.block_name_from_cli
834
+
835
+ # return false if @prior_execution_block == @delegate_object[:block_name]
836
+ if @prior_execution_block == @delegate_object[:block_name]
837
+ return @allowed_execution_block == @prior_execution_block || prompt_approve_repeat
838
+ end
839
+
840
+ @prior_execution_block = @delegate_object[:block_name]
841
+ @allowed_execution_block = nil
842
+ true
843
+ end
844
+
845
+ def debounce_reset
846
+ @prior_execution_block = nil
847
+ end
848
+
770
849
  # Determines the state of a selected block in the menu based on the selected option.
771
850
  # It categorizes the selected option into either EXIT, BACK, or CONTINUE state.
772
851
  #
@@ -803,15 +882,23 @@ module MarkdownExec
803
882
  @delegate_object[:menu_divider_format].present? && @delegate_object[divider_key].present?
804
883
  end
805
884
 
885
+ def do_save_execution_output
886
+ return unless @delegate_object[:save_execution_output]
887
+ return if @run_state.in_own_window
888
+
889
+ HashDelegator.write_execution_output_to_file(@run_state.files,
890
+ @delegate_object[:logged_stdout_filespec])
891
+ end
892
+
806
893
  # Executes a block of code that has been approved for execution.
807
894
  # It sets the script block name, writes command files if required, and handles the execution
808
895
  # including output formatting and summarization.
809
896
  #
810
897
  # @param required_lines [Array<String>] The lines of code to be executed.
811
898
  # @param selected [FCB] The selected functional code block object.
812
- def execute_required_lines(required_lines = [])
813
- # @run_state.script_block_name = selected[:oname]
814
- write_command_file(required_lines) if @delegate_object[:save_executed_script]
899
+ def execute_required_lines(required_lines = [], selected = FCB.new)
900
+ write_command_file(required_lines, selected) if @delegate_object[:save_executed_script]
901
+ calc_logged_stdout_filename
815
902
  format_and_execute_command(required_lines)
816
903
  post_execution_process
817
904
  end
@@ -828,21 +915,42 @@ module MarkdownExec
828
915
  def execute_shell_type(selected, mdoc, link_state = LinkState.new,
829
916
  block_source:)
830
917
  if selected.fetch(:shell, '') == BlockType::LINK
918
+ debounce_reset
831
919
  push_link_history_and_trigger_load(selected.fetch(:body, ''), mdoc, selected,
832
920
  link_state)
833
921
 
834
922
  elsif @menu_user_clicked_back_link
923
+ debounce_reset
835
924
  pop_link_history_and_trigger_load
836
925
 
837
926
  elsif selected[:shell] == BlockType::OPTS
927
+ debounce_reset
838
928
  options_state = read_show_options_and_trigger_reuse(selected, link_state)
839
929
  @menu_base_options.merge!(options_state.options)
840
930
  @delegate_object.merge!(options_state.options)
841
931
  options_state.load_file_link_state
842
932
 
843
- else
933
+ elsif selected[:shell] == BlockType::VARS
934
+ debounce_reset
935
+ block_names = []
936
+ code_lines = set_environment_variables_for_block(selected)
937
+ dependencies = {}
938
+ link_history_push_and_next(
939
+ curr_block_name: selected[:oname],
940
+ curr_document_filename: @delegate_object[:filename],
941
+ inherited_block_names: ((link_state&.inherited_block_names || []) + block_names).sort.uniq,
942
+ inherited_dependencies: (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
943
+ inherited_lines: HashDelegator.code_merge(link_state&.inherited_lines, code_lines),
944
+ next_block_name: '',
945
+ next_document_filename: @delegate_object[:filename],
946
+ next_load_file: LoadFile::Reuse
947
+ )
948
+
949
+ elsif debounce_allows
844
950
  compile_execute_and_trigger_reuse(mdoc, selected, link_state,
845
951
  block_source: block_source)
952
+ else
953
+ LoadFileLinkState.new(LoadFile::Reuse, link_state)
846
954
  end
847
955
  end
848
956
 
@@ -904,12 +1012,31 @@ module MarkdownExec
904
1012
  @delegate_object[:block_stdout_scan])
905
1013
 
906
1014
  shell_color_option = SHELL_COLOR_OPTIONS[fcb[:shell]]
907
- fcb.title = fcb.oname = bm && bm[1] ? bm[:title] : titlexcall
908
- fcb.dname = apply_shell_color_option(fcb.oname, shell_color_option)
909
1015
 
1016
+ if @delegate_object[:block_name_nick_match].present? && fcb.oname =~ Regexp.new(@delegate_object[:block_name_nick_match])
1017
+ fcb.nickname = $~[0]
1018
+ fcb.title = fcb.oname = format_multiline_body_as_title(fcb.body)
1019
+ else
1020
+ fcb.title = fcb.oname = bm && bm[1] ? bm[:title] : titlexcall
1021
+ end
1022
+
1023
+ fcb.dname = HashDelegator.indent_all_lines(
1024
+ apply_shell_color_option(fcb.oname, shell_color_option),
1025
+ fcb.fetch(:indent, nil)
1026
+ )
910
1027
  fcb
911
1028
  end
912
1029
 
1030
+ # Formats multiline body content as a title string.
1031
+ # indents all but first line with two spaces so it displays correctly in menu
1032
+ # @param body_lines [Array<String>] The lines of body content.
1033
+ # @return [String] Formatted title.
1034
+ def format_multiline_body_as_title(body_lines)
1035
+ body_lines.map.with_index do |line, index|
1036
+ index.zero? ? line : " #{line}"
1037
+ end.join("\n") + "\n"
1038
+ end
1039
+
913
1040
  # Updates the delegate object's state based on the provided block state.
914
1041
  # It sets the block name and determines if the user clicked the back link in the menu.
915
1042
  #
@@ -962,25 +1089,6 @@ module MarkdownExec
962
1089
  }
963
1090
  end
964
1091
 
965
- def initialize_and_save_execution_output
966
- return unless @delegate_object[:save_execution_output]
967
-
968
- @delegate_object[:logged_stdout_filename] =
969
- SavedAsset.stdout_name(blockname: @delegate_object[:block_name],
970
- filename: File.basename(@delegate_object[:filename],
971
- '.*'),
972
- prefix: @delegate_object[:logged_stdout_filename_prefix],
973
- time: Time.now.utc)
974
-
975
- @logged_stdout_filespec =
976
- @delegate_object[:logged_stdout_filespec] =
977
- File.join @delegate_object[:saved_stdout_folder],
978
- @delegate_object[:logged_stdout_filename]
979
- @logged_stdout_filespec = @delegate_object[:logged_stdout_filespec]
980
- HashDelegator.write_execution_output_to_file(@run_state.files,
981
- @delegate_object[:logged_stdout_filespec])
982
- end
983
-
984
1092
  # Iterates through blocks in a file, applying the provided block to each line.
985
1093
  # The iteration only occurs if the file exists.
986
1094
  # @yield [Symbol] :filter Yields to obtain selected messages for processing.
@@ -989,8 +1097,8 @@ module MarkdownExec
989
1097
 
990
1098
  state = initial_state
991
1099
  selected_messages = yield :filter
992
-
993
- cfile.readlines(@delegate_object[:filename]).each do |nested_line|
1100
+ cfile.readlines(@delegate_object[:filename],
1101
+ import_paths: @delegate_object[:import_paths]&.split(':')).each do |nested_line|
994
1102
  if nested_line
995
1103
  update_line_and_block_state(nested_line, state, selected_messages,
996
1104
  &block)
@@ -998,6 +1106,65 @@ module MarkdownExec
998
1106
  end
999
1107
  end
1000
1108
 
1109
+ def link_block_data_eval(link_state, code_lines, selected, link_block_data)
1110
+ all_code = HashDelegator.code_merge(link_state&.inherited_lines, code_lines)
1111
+
1112
+ if link_block_data.fetch(LinkKeys::Exec, false)
1113
+ @run_state.files = Hash.new([])
1114
+ output_lines = []
1115
+
1116
+ Open3.popen3(
1117
+ @delegate_object[:shell],
1118
+ '-c', all_code.join("\n")
1119
+ ) do |stdin, stdout, stderr, _exec_thr|
1120
+ handle_stream(stdout, ExecutionStreams::StdOut) do |line|
1121
+ output_lines.push(line)
1122
+ end
1123
+ handle_stream(stderr, ExecutionStreams::StdErr) do |line|
1124
+ output_lines.push(line)
1125
+ end
1126
+
1127
+ in_thr = handle_stream($stdin, ExecutionStreams::StdIn) do |line|
1128
+ stdin.puts(line)
1129
+ end
1130
+
1131
+ wait_for_stream_processing
1132
+ sleep 0.1
1133
+ in_thr.kill if in_thr&.alive?
1134
+ end
1135
+
1136
+ ## select output_lines that look like assignment or match other specs
1137
+ #
1138
+ output_lines = process_string_array(
1139
+ output_lines,
1140
+ begin_pattern: @delegate_object.fetch(:output_assignment_begin, nil),
1141
+ end_pattern: @delegate_object.fetch(:output_assignment_end, nil),
1142
+ scan1: @delegate_object.fetch(:output_assignment_match, nil),
1143
+ format1: @delegate_object.fetch(:output_assignment_format, nil)
1144
+ )
1145
+
1146
+ else
1147
+ output_lines = `#{all_code.join("\n")}`.split("\n")
1148
+ end
1149
+
1150
+ unless output_lines
1151
+ HashDelegator.error_handler('all_code eval output_lines is nil', { abort: true })
1152
+ end
1153
+
1154
+ label_format_above = @delegate_object[:shell_code_label_format_above]
1155
+ label_format_below = @delegate_object[:shell_code_label_format_below]
1156
+ block_source = { document_filename: link_state&.document_filename }
1157
+
1158
+ [label_format_above && format(label_format_above,
1159
+ block_source.merge({ block_name: selected[:oname] }))] +
1160
+ output_lines.map do |line|
1161
+ re = Regexp.new(link_block_data.fetch('pattern', '(?<line>.*)'))
1162
+ re.gsub_format(line, link_block_data.fetch('format', '%{line}')) if re =~ line
1163
+ end.compact +
1164
+ [label_format_below && format(label_format_below,
1165
+ block_source.merge({ block_name: selected[:oname] }))]
1166
+ end
1167
+
1001
1168
  def link_history_push_and_next(
1002
1169
  curr_block_name:, curr_document_filename:,
1003
1170
  inherited_block_names:, inherited_dependencies:, inherited_lines:,
@@ -1165,23 +1332,38 @@ module MarkdownExec
1165
1332
  ), level: level
1166
1333
  end
1167
1334
 
1168
- def pop_add_current_code_to_head_and_trigger_load(_link_state, block_names, code_lines,
1169
- dependencies)
1335
+ def pop_add_current_code_to_head_and_trigger_load(link_state, block_names, code_lines,
1336
+ dependencies, selected)
1170
1337
  pop = @link_history.pop # updatable
1171
- next_state = LinkState.new(
1172
- block_name: pop.block_name,
1173
- document_filename: pop.document_filename,
1174
- inherited_block_names:
1175
- (pop.inherited_block_names + block_names).sort.uniq,
1176
- inherited_dependencies:
1177
- dependencies.merge(pop.inherited_dependencies || {}), ### merge, not replace, key data
1178
- inherited_lines:
1179
- HashDelegator.code_merge(pop.inherited_lines, code_lines)
1180
- )
1181
- @link_history.push(next_state)
1338
+ if pop.document_filename
1339
+ next_state = LinkState.new(
1340
+ block_name: pop.block_name,
1341
+ document_filename: pop.document_filename,
1342
+ inherited_block_names:
1343
+ (pop.inherited_block_names + block_names).sort.uniq,
1344
+ inherited_dependencies:
1345
+ dependencies.merge(pop.inherited_dependencies || {}), ### merge, not replace, key data
1346
+ inherited_lines:
1347
+ HashDelegator.code_merge(pop.inherited_lines, code_lines)
1348
+ )
1349
+ @link_history.push(next_state)
1182
1350
 
1183
- next_state.block_name = nil
1184
- LoadFileLinkState.new(LoadFile::Load, next_state)
1351
+ next_state.block_name = nil
1352
+ LoadFileLinkState.new(LoadFile::Load, next_state)
1353
+ else
1354
+ # no history exists; must have been called independently => retain script
1355
+ link_history_push_and_next(
1356
+ curr_block_name: selected[:oname],
1357
+ curr_document_filename: @delegate_object[:filename],
1358
+ inherited_block_names: ((link_state&.inherited_block_names || []) + block_names).sort.uniq,
1359
+ inherited_dependencies: (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
1360
+ inherited_lines: HashDelegator.code_merge(link_state&.inherited_lines, code_lines),
1361
+ next_block_name: '', # not link_block_data[LinkKeys::Block] || ''
1362
+ next_document_filename: @delegate_object[:filename], # not next_document_filename
1363
+ next_load_file: LoadFile::Reuse # not next_document_filename == @delegate_object[:filename] ? LoadFile::Reuse : LoadFile::Load
1364
+ )
1365
+ # LoadFileLinkState.new(LoadFile::Reuse, link_state)
1366
+ end
1185
1367
  end
1186
1368
 
1187
1369
  # This method handles the back-link operation in the Markdown execution context.
@@ -1200,7 +1382,7 @@ module MarkdownExec
1200
1382
  end
1201
1383
 
1202
1384
  def post_execution_process
1203
- initialize_and_save_execution_output
1385
+ do_save_execution_output
1204
1386
  output_execution_summary
1205
1387
  output_execution_result
1206
1388
  end
@@ -1216,7 +1398,7 @@ module MarkdownExec
1216
1398
  %i[block_name_include_match block_name_wrapper_match])
1217
1399
 
1218
1400
  fcb.merge!(
1219
- name: HashDelegator.indent_all_lines(fcb.dname, fcb.fetch(:indent, nil)),
1401
+ name: fcb.dname,
1220
1402
  label: BlockLabel.make(
1221
1403
  body: fcb[:body],
1222
1404
  filename: @delegate_object[:filename],
@@ -1250,6 +1432,61 @@ module MarkdownExec
1250
1432
  end
1251
1433
  end
1252
1434
 
1435
+ def process_string_array(arr, begin_pattern: nil, end_pattern: nil, scan1: nil,
1436
+ format1: nil)
1437
+ in_block = !begin_pattern.present?
1438
+ collected_lines = []
1439
+
1440
+ arr.each do |line|
1441
+ if in_block
1442
+ if end_pattern.present? && line.match?(end_pattern)
1443
+ in_block = false
1444
+ elsif scan1.present?
1445
+ if format1.present?
1446
+ caps = extract_named_captures_from_option(line, scan1)
1447
+ if caps
1448
+ formatted = format(format1, caps)
1449
+ collected_lines << formatted
1450
+ end
1451
+ else
1452
+ caps = line.match(scan1)
1453
+ if caps
1454
+ formatted = caps[0]
1455
+ collected_lines << formatted
1456
+ end
1457
+ end
1458
+ else
1459
+ collected_lines << line
1460
+ end
1461
+ elsif begin_pattern.present? && line.match?(begin_pattern)
1462
+ in_block = true
1463
+ end
1464
+ end
1465
+
1466
+ collected_lines
1467
+ end
1468
+
1469
+ def prompt_approve_repeat
1470
+ sel = @prompt.select(
1471
+ string_send_color(@delegate_object[:prompt_debounce],
1472
+ :prompt_color_after_script_execution),
1473
+ default: @delegate_object[:prompt_no],
1474
+ filter: true,
1475
+ quiet: true
1476
+ ) do |menu|
1477
+ menu.choice @delegate_object[:prompt_yes]
1478
+ menu.choice @delegate_object[:prompt_no]
1479
+ menu.choice @delegate_object[:prompt_uninterrupted]
1480
+ end
1481
+ return false if sel == @delegate_object[:prompt_no]
1482
+ return true if sel == @delegate_object[:prompt_yes]
1483
+
1484
+ @allowed_execution_block = @prior_execution_block
1485
+ true
1486
+ rescue TTY::Reader::InputInterrupt
1487
+ exit 1
1488
+ end
1489
+
1253
1490
  ##
1254
1491
  # Presents a menu to the user for approving an action and performs additional tasks based on the selection.
1255
1492
  # The function provides options for approval, rejection, copying data to clipboard, or saving data to a file.
@@ -1265,7 +1502,7 @@ module MarkdownExec
1265
1502
  #
1266
1503
  # @return [Boolean] Returns true if the user approves (selects 'Yes'), false otherwise.
1267
1504
  ##
1268
- def prompt_for_user_approval(required_lines)
1505
+ def prompt_for_user_approval(required_lines, selected)
1269
1506
  # Present a selection menu for user approval.
1270
1507
  sel = @prompt.select(
1271
1508
  string_send_color(@delegate_object[:prompt_approve_block],
@@ -1285,7 +1522,7 @@ module MarkdownExec
1285
1522
  if sel == MenuOptions::SCRIPT_TO_CLIPBOARD
1286
1523
  copy_to_clipboard(required_lines)
1287
1524
  elsif sel == MenuOptions::SAVE_SCRIPT
1288
- save_to_file(required_lines)
1525
+ save_to_file(required_lines, selected)
1289
1526
  end
1290
1527
 
1291
1528
  sel == MenuOptions::YES
@@ -1322,12 +1559,6 @@ module MarkdownExec
1322
1559
  link_state = LinkState.new)
1323
1560
  link_block_data = HashDelegator.parse_yaml_data_from_body(link_block_body)
1324
1561
 
1325
- # load key and values from link block into current environment
1326
- #
1327
- (link_block_data['vars'] || []).each do |(key, value)|
1328
- ENV[key] = value.to_s
1329
- end
1330
-
1331
1562
  ## collect blocks specified by block
1332
1563
  #
1333
1564
  if mdoc
@@ -1345,33 +1576,42 @@ module MarkdownExec
1345
1576
  code_lines = []
1346
1577
  dependencies = {}
1347
1578
  end
1348
- next_document_filename = link_block_data['file'] || @delegate_object[:filename]
1579
+ next_document_filename = link_block_data[LinkKeys::File] || @delegate_object[:filename]
1580
+
1581
+ # load key and values from link block into current environment
1582
+ #
1583
+ if link_block_data[LinkKeys::Vars]
1584
+ code_lines.push "# #{selected[:oname]}"
1585
+ (link_block_data[LinkKeys::Vars] || []).each do |(key, value)|
1586
+ ENV[key] = value.to_s
1587
+ require 'shellwords'
1588
+ code_lines.push "#{key}=\"#{Shellwords.escape(value)}\""
1589
+ end
1590
+ end
1591
+
1592
+ ## append blocks loaded, apply LinkKeys::Eval
1593
+ #
1594
+ if (load_filespec = link_block_data.fetch(LinkKeys::Load, '')).present?
1595
+ code_lines += File.readlines(load_filespec, chomp: true)
1596
+ end
1349
1597
 
1350
1598
  # if an eval link block, evaluate code_lines and return its standard output
1351
1599
  #
1352
- if link_block_data.fetch('eval', false)
1353
- all_code = HashDelegator.code_merge(link_state&.inherited_lines, code_lines)
1354
- output = `#{all_code.join("\n")}`.split("\n")
1355
- label_format_above = @delegate_object[:shell_code_label_format_above]
1356
- label_format_below = @delegate_object[:shell_code_label_format_below]
1357
- block_source = { document_filename: link_state&.document_filename }
1358
-
1359
- code_lines = [label_format_above && format(label_format_above,
1360
- block_source.merge({ block_name: selected[:oname] }))] +
1361
- output.map do |line|
1362
- re = Regexp.new(link_block_data.fetch('pattern', '(?<line>.*)'))
1363
- if re =~ line
1364
- re.gsub_format(line, link_block_data.fetch('format', '%{line}'))
1365
- end
1366
- end.compact +
1367
- [label_format_below && format(label_format_below,
1368
- block_source.merge({ block_name: selected[:oname] }))]
1600
+ if link_block_data.fetch(LinkKeys::Eval,
1601
+ false) || link_block_data.fetch(LinkKeys::Exec, false)
1602
+ code_lines = link_block_data_eval(link_state, code_lines, selected, link_block_data)
1603
+ end
1369
1604
 
1605
+ ## write variables
1606
+ #
1607
+ if (save_filespec = link_block_data.fetch(LinkKeys::Save, '')).present?
1608
+ File.write(save_filespec, HashDelegator.join_code_lines(link_state&.inherited_lines))
1609
+ next_document_filename = @delegate_object[:filename]
1370
1610
  end
1371
1611
 
1372
- if link_block_data['return']
1612
+ if link_block_data[LinkKeys::Return]
1373
1613
  pop_add_current_code_to_head_and_trigger_load(link_state, block_names, code_lines,
1374
- dependencies)
1614
+ dependencies, selected)
1375
1615
 
1376
1616
  else
1377
1617
  link_history_push_and_next(
@@ -1380,7 +1620,7 @@ module MarkdownExec
1380
1620
  inherited_block_names: ((link_state&.inherited_block_names || []) + block_names).sort.uniq,
1381
1621
  inherited_dependencies: (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
1382
1622
  inherited_lines: HashDelegator.code_merge(link_state&.inherited_lines, code_lines),
1383
- next_block_name: link_block_data['block'] || '',
1623
+ next_block_name: link_block_data.fetch(LinkKeys::NextBlock, nil) || link_block_data[LinkKeys::Block] || '',
1384
1624
  next_document_filename: next_document_filename,
1385
1625
  next_load_file: next_document_filename == @delegate_object[:filename] ? LoadFile::Reuse : LoadFile::Load
1386
1626
  )
@@ -1406,8 +1646,8 @@ module MarkdownExec
1406
1646
  exit @delegate_object[exception_sym]
1407
1647
  end
1408
1648
 
1409
- def save_to_file(required_lines)
1410
- write_command_file(required_lines)
1649
+ def save_to_file(required_lines, selected)
1650
+ write_command_file(required_lines, selected)
1411
1651
  @fout.fout "File saved: #{@run_state.saved_filespec}"
1412
1652
  end
1413
1653
 
@@ -1423,21 +1663,27 @@ module MarkdownExec
1423
1663
  block_name: @delegate_object[:block_name],
1424
1664
  document_filename: @delegate_object[:filename]
1425
1665
  )
1426
- block_name_from_cli = link_state.block_name.present?
1666
+ @run_state.block_name_from_cli = link_state.block_name.present?
1427
1667
  @cli_block_name = link_state.block_name
1428
- now_using_cli = block_name_from_cli
1668
+ now_using_cli = @run_state.block_name_from_cli
1429
1669
  menu_default_dname = nil
1430
1670
 
1671
+ @run_state.batch_random = Random.new.rand
1672
+ @run_state.batch_index = 0
1673
+
1431
1674
  loop do
1675
+ @run_state.batch_index += 1
1676
+ @run_state.in_own_window = false
1677
+
1432
1678
  # &bsp 'loop', block_name_from_cli, @cli_block_name
1433
- block_name_from_cli, now_using_cli, blocks_in_file, menu_blocks, mdoc = \
1434
- set_delobj_menu_loop_vars(block_name_from_cli, now_using_cli, link_state)
1679
+ @run_state.block_name_from_cli, now_using_cli, blocks_in_file, menu_blocks, mdoc = \
1680
+ set_delobj_menu_loop_vars(@run_state.block_name_from_cli, now_using_cli, link_state)
1435
1681
 
1436
1682
  # cli or user selection
1437
1683
  #
1438
1684
  block_state = load_cli_or_user_selected_block(blocks_in_file, menu_blocks,
1439
1685
  menu_default_dname)
1440
- # &bsp 'block_name_from_cli:',block_name_from_cli
1686
+ # &bsp '@run_state.block_name_from_cli:',@run_state.block_name_from_cli
1441
1687
  if !block_state
1442
1688
  HashDelegator.error_handler('block_state missing', { abort: true })
1443
1689
  elsif block_state.state == MenuState::EXIT
@@ -1448,13 +1694,18 @@ module MarkdownExec
1448
1694
  dump_and_warn_block_state(block_state.block)
1449
1695
  link_state, menu_default_dname = exec_bash_next_state(block_state.block, mdoc,
1450
1696
  link_state)
1451
- if prompt_user_exit(block_name_from_cli, block_state.block)
1697
+ if prompt_user_exit(@run_state.block_name_from_cli, block_state.block)
1452
1698
  # &bsp 'prompt_user_exit -> break'
1453
1699
  break
1454
1700
  end
1455
1701
 
1456
- link_state.block_name, block_name_from_cli, cli_break = \
1457
- HashDelegator.next_link_state(!shift_cli_argument, now_using_cli, block_state)
1702
+ ## order of block name processing
1703
+ # from link block
1704
+ # from cli
1705
+ # from user
1706
+ #
1707
+ link_state.block_name, @run_state.block_name_from_cli, cli_break = \
1708
+ HashDelegator.next_link_state(!link_state.block_name && !shift_cli_argument, now_using_cli, block_state, block_name: link_state.block_name)
1458
1709
 
1459
1710
  if !block_state.block[:block_name_from_ui] && cli_break
1460
1711
  # &bsp '!block_name_from_ui + cli_break -> break'
@@ -1572,11 +1823,16 @@ module MarkdownExec
1572
1823
  selection = @prompt.select(prompt_text,
1573
1824
  names,
1574
1825
  opts.merge(filter: true))
1826
+
1575
1827
  item = if names.first.instance_of?(String)
1576
1828
  { dname: selection }
1577
1829
  else
1578
1830
  names.find { |item| item[:dname] == selection }
1579
1831
  end
1832
+ unless item
1833
+ HashDelegator.error_handler('select_option_with_metadata', error: 'menu item not found')
1834
+ exit 1
1835
+ end
1580
1836
 
1581
1837
  item.merge(
1582
1838
  if selection == menu_chrome_colored_option(:menu_option_back_name)
@@ -1594,14 +1850,20 @@ module MarkdownExec
1594
1850
  end
1595
1851
 
1596
1852
  def set_environment_variables_for_block(selected)
1597
- YAML.load(selected[:body].join("\n")).each do |key, value|
1853
+ code_lines = []
1854
+ YAML.load(selected[:body].join("\n"))&.each do |key, value|
1598
1855
  ENV[key] = value.to_s
1856
+
1857
+ require 'shellwords'
1858
+ code_lines.push "#{key}=\"#{Shellwords.escape(value)}\""
1859
+
1599
1860
  next unless @delegate_object[:menu_vars_set_format].present?
1600
1861
 
1601
1862
  formatted_string = format(@delegate_object[:menu_vars_set_format],
1602
1863
  { key: key, value: value })
1603
1864
  print string_send_color(formatted_string, :menu_vars_set_color)
1604
1865
  end
1866
+ code_lines
1605
1867
  end
1606
1868
 
1607
1869
  def should_add_back_option?
@@ -1623,13 +1885,22 @@ module MarkdownExec
1623
1885
  !name.match(Regexp.new(@delegate_object[:block_name_wrapper_match]))
1624
1886
  end
1625
1887
 
1888
+ dname = oname = title = ''
1889
+ nickname = nil
1890
+ if @delegate_object[:block_name_nick_match].present? && oname =~ Regexp.new(@delegate_object[:block_name_nick_match])
1891
+ nickname = $~[0]
1892
+ else
1893
+ dname = oname = title = fcb_title_groups.fetch(:name, '')
1894
+ end
1895
+
1626
1896
  MarkdownExec::FCB.new(
1627
1897
  body: [],
1628
1898
  call: rest.match(Regexp.new(@delegate_object[:block_calls_scan]))&.to_a&.first,
1629
- dname: fcb_title_groups.fetch(:name, ''),
1899
+ dname: dname,
1630
1900
  headings: headings,
1631
1901
  indent: fcb_title_groups.fetch(:indent, ''),
1632
- oname: fcb_title_groups.fetch(:name, ''),
1902
+ nickname: nickname,
1903
+ oname: oname,
1633
1904
  reqs: reqs,
1634
1905
  shell: fcb_title_groups.fetch(:shell, ''),
1635
1906
  stdin: if (tn = rest.match(/<(?<type>\$)?(?<name>[A-Za-z_-]\S+)/))
@@ -1638,7 +1909,7 @@ module MarkdownExec
1638
1909
  stdout: if (tn = rest.match(/>(?<type>\$)?(?<name>[A-Za-z_\-.\w]+)/))
1639
1910
  tn.named_captures.sym_keys
1640
1911
  end,
1641
- title: fcb_title_groups.fetch(:name, ''),
1912
+ title: title,
1642
1913
  wraps: wraps
1643
1914
  )
1644
1915
  end
@@ -1767,15 +2038,17 @@ module MarkdownExec
1767
2038
  end
1768
2039
 
1769
2040
  # Handles the core logic for generating the command file's metadata and content.
1770
- def write_command_file(required_lines)
2041
+ def write_command_file(required_lines, selected)
1771
2042
  return unless @delegate_object[:save_executed_script]
1772
2043
 
1773
2044
  time_now = Time.now.utc
1774
2045
  @run_state.saved_script_filename =
1775
- SavedAsset.script_name(blockname: @delegate_object[:block_name],
1776
- filename: @delegate_object[:filename],
1777
- prefix: @delegate_object[:saved_script_filename_prefix],
1778
- time: time_now)
2046
+ SavedAsset.script_name(
2047
+ blockname: selected[:nickname] || selected[:oname],
2048
+ filename: @delegate_object[:filename],
2049
+ prefix: @delegate_object[:saved_script_filename_prefix],
2050
+ time: time_now
2051
+ )
1779
2052
  @run_state.saved_filespec =
1780
2053
  File.join(@delegate_object[:saved_script_folder],
1781
2054
  @run_state.saved_script_filename)
@@ -1824,848 +2097,850 @@ module MarkdownExec
1824
2097
  end
1825
2098
  end
1826
2099
 
1827
- if $PROGRAM_NAME == __FILE__
1828
- require 'bundler/setup'
1829
- Bundler.require(:default)
2100
+ return if $PROGRAM_NAME != __FILE__
1830
2101
 
1831
- require 'minitest/autorun'
1832
- require 'mocha/minitest'
2102
+ require 'bundler/setup'
2103
+ Bundler.require(:default)
1833
2104
 
1834
- module MarkdownExec
1835
- class TestHashDelegator < Minitest::Test
1836
- def setup
1837
- @hd = HashDelegator.new
1838
- @mdoc = mock('MarkdownDocument')
1839
- end
2105
+ require 'minitest/autorun'
2106
+ require 'mocha/minitest'
1840
2107
 
1841
- def test_calling_execute_required_lines_calls_command_execute_with_argument_args_value
1842
- pigeon = 'E'
1843
- obj = {
1844
- output_execution_label_format: '',
1845
- output_execution_label_name_color: 'plain',
1846
- output_execution_label_value_color: 'plain'
1847
- }
2108
+ module MarkdownExec
2109
+ class TestHashDelegator < Minitest::Test
2110
+ def setup
2111
+ @hd = HashDelegator.new
2112
+ @mdoc = mock('MarkdownDocument')
2113
+ end
2114
+
2115
+ def test_calling_execute_required_lines_calls_command_execute_with_argument_args_value
2116
+ pigeon = 'E'
2117
+ obj = {
2118
+ output_execution_label_format: '',
2119
+ output_execution_label_name_color: 'plain',
2120
+ output_execution_label_value_color: 'plain'
2121
+ }
1848
2122
 
1849
- c = MarkdownExec::HashDelegator.new(obj)
1850
- c.pass_args = pigeon
2123
+ c = MarkdownExec::HashDelegator.new(obj)
2124
+ c.pass_args = pigeon
1851
2125
 
1852
- # Expect that method opts_command_execute is called with argument args having value pigeon
1853
- c.expects(:command_execute).with(
1854
- '',
1855
- args: pigeon
1856
- )
2126
+ # Expect that method opts_command_execute is called with argument args having value pigeon
2127
+ c.expects(:command_execute).with(
2128
+ '',
2129
+ args: pigeon
2130
+ )
1857
2131
 
1858
- # Call method opts_execute_required_lines
1859
- c.execute_required_lines([])
1860
- end
2132
+ # Call method opts_execute_required_lines
2133
+ c.execute_required_lines
2134
+ end
1861
2135
 
1862
- # Test case for empty body
1863
- def test_push_link_history_and_trigger_load_with_empty_body
1864
- assert_equal LoadFile::Reuse,
1865
- @hd.push_link_history_and_trigger_load([], nil, FCB.new).load_file
1866
- end
2136
+ # Test case for empty body
2137
+ def test_push_link_history_and_trigger_load_with_empty_body
2138
+ assert_equal LoadFile::Reuse,
2139
+ @hd.push_link_history_and_trigger_load([], nil, FCB.new).load_file
2140
+ end
1867
2141
 
1868
- # Test case for non-empty body without 'file' key
1869
- def test_push_link_history_and_trigger_load_without_file_key
1870
- body = ["vars:\n KEY: VALUE"]
1871
- assert_equal LoadFile::Reuse,
1872
- @hd.push_link_history_and_trigger_load(body, nil, FCB.new).load_file
1873
- end
2142
+ # Test case for non-empty body without 'file' key
2143
+ def test_push_link_history_and_trigger_load_without_file_key
2144
+ body = ["vars:\n KEY: VALUE"]
2145
+ assert_equal LoadFile::Reuse,
2146
+ @hd.push_link_history_and_trigger_load(body, nil, FCB.new).load_file
2147
+ end
1874
2148
 
1875
- # Test case for non-empty body with 'file' key
1876
- def test_push_link_history_and_trigger_load_with_file_key
1877
- body = ["file: sample_file\nblock: sample_block\nvars:\n KEY: VALUE"]
1878
- expected_result = LoadFileLinkState.new(LoadFile::Load,
1879
- LinkState.new(block_name: 'sample_block',
1880
- document_filename: 'sample_file',
1881
- inherited_dependencies: {},
1882
- inherited_lines: []))
1883
- assert_equal expected_result,
1884
- @hd.push_link_history_and_trigger_load(body, nil, FCB.new(block_name: 'sample_block',
1885
- filename: 'sample_file'))
1886
- end
2149
+ # Test case for non-empty body with 'file' key
2150
+ def test_push_link_history_and_trigger_load_with_file_key
2151
+ body = ["file: sample_file\nblock: sample_block\nvars:\n KEY: VALUE"]
2152
+ expected_result = LoadFileLinkState.new(LoadFile::Load,
2153
+ LinkState.new(block_name: 'sample_block',
2154
+ document_filename: 'sample_file',
2155
+ inherited_dependencies: {},
2156
+ inherited_lines: ['# ', 'KEY="VALUE"']))
2157
+ assert_equal expected_result,
2158
+ @hd.push_link_history_and_trigger_load(body, nil, FCB.new(block_name: 'sample_block',
2159
+ filename: 'sample_file'))
2160
+ end
1887
2161
 
1888
- def test_indent_all_lines_with_indent
1889
- body = "Line 1\nLine 2"
1890
- indent = ' ' # Two spaces
1891
- expected_result = " Line 1\n Line 2"
1892
- assert_equal expected_result, HashDelegator.indent_all_lines(body, indent)
1893
- end
2162
+ def test_indent_all_lines_with_indent
2163
+ body = "Line 1\nLine 2"
2164
+ indent = ' ' # Two spaces
2165
+ expected_result = " Line 1\n Line 2"
2166
+ assert_equal expected_result, HashDelegator.indent_all_lines(body, indent)
2167
+ end
1894
2168
 
1895
- def test_indent_all_lines_without_indent
1896
- body = "Line 1\nLine 2"
1897
- indent = nil
2169
+ def test_indent_all_lines_without_indent
2170
+ body = "Line 1\nLine 2"
2171
+ indent = nil
1898
2172
 
1899
- assert_equal body, HashDelegator.indent_all_lines(body, indent)
1900
- end
2173
+ assert_equal body, HashDelegator.indent_all_lines(body, indent)
2174
+ end
1901
2175
 
1902
- def test_indent_all_lines_with_empty_indent
1903
- body = "Line 1\nLine 2"
1904
- indent = ''
2176
+ def test_indent_all_lines_with_empty_indent
2177
+ body = "Line 1\nLine 2"
2178
+ indent = ''
1905
2179
 
1906
- assert_equal body, HashDelegator.indent_all_lines(body, indent)
1907
- end
2180
+ assert_equal body, HashDelegator.indent_all_lines(body, indent)
2181
+ end
1908
2182
 
1909
- def test_safeval_successful_evaluation
1910
- assert_equal 4, HashDelegator.safeval('2 + 2')
1911
- end
2183
+ def test_safeval_successful_evaluation
2184
+ assert_equal 4, HashDelegator.safeval('2 + 2')
2185
+ end
1912
2186
 
1913
- def test_safeval_rescue_from_error
1914
- HashDelegator.stubs(:error_handler).with('safeval')
1915
- assert_nil HashDelegator.safeval('invalid code')
1916
- end
2187
+ def test_safeval_rescue_from_error
2188
+ HashDelegator.stubs(:error_handler).with('safeval')
2189
+ assert_nil HashDelegator.safeval('invalid code')
2190
+ end
1917
2191
 
1918
- def test_set_fcb_title
1919
- # sample input and output data for testing default_block_title_from_body method
1920
- input_output_data = [
1921
- {
1922
- input: MarkdownExec::FCB.new(title: nil,
1923
- body: ["puts 'Hello, world!'"]),
1924
- output: "puts 'Hello, world!'"
1925
- },
1926
- {
1927
- input: MarkdownExec::FCB.new(title: '',
1928
- body: ['def add(x, y)',
1929
- ' x + y', 'end']),
1930
- output: "def add(x, y)\n x + y\n end\n"
1931
- },
1932
- {
1933
- input: MarkdownExec::FCB.new(title: 'foo', body: %w[bar baz]),
1934
- output: 'foo' # expect the title to remain unchanged
1935
- }
1936
- ]
2192
+ def test_set_fcb_title
2193
+ # sample input and output data for testing default_block_title_from_body method
2194
+ input_output_data = [
2195
+ {
2196
+ input: MarkdownExec::FCB.new(title: nil,
2197
+ body: ["puts 'Hello, world!'"]),
2198
+ output: "puts 'Hello, world!'"
2199
+ },
2200
+ {
2201
+ input: MarkdownExec::FCB.new(title: '',
2202
+ body: ['def add(x, y)',
2203
+ ' x + y', 'end']),
2204
+ output: "def add(x, y)\n x + y\n end\n"
2205
+ },
2206
+ {
2207
+ input: MarkdownExec::FCB.new(title: 'foo', body: %w[bar baz]),
2208
+ output: 'foo' # expect the title to remain unchanged
2209
+ }
2210
+ ]
1937
2211
 
1938
- # iterate over the input and output data and
1939
- # assert that the method sets the title as expected
1940
- input_output_data.each do |data|
1941
- input = data[:input]
1942
- output = data[:output]
1943
- HashDelegator.default_block_title_from_body(input)
1944
- assert_equal output, input.title
1945
- end
2212
+ # iterate over the input and output data and
2213
+ # assert that the method sets the title as expected
2214
+ input_output_data.each do |data|
2215
+ input = data[:input]
2216
+ output = data[:output]
2217
+ HashDelegator.default_block_title_from_body(input)
2218
+ assert_equal output, input.title
1946
2219
  end
2220
+ end
1947
2221
 
1948
- class TestHashDelegatorAppendDivider < Minitest::Test
1949
- def setup
1950
- @hd = HashDelegator.new
1951
- @hd.instance_variable_set(:@delegate_object, {
1952
- menu_divider_format: 'Format',
1953
- menu_initial_divider: 'Initial Divider',
1954
- menu_final_divider: 'Final Divider',
1955
- menu_divider_color: :color
1956
- })
1957
- @hd.stubs(:string_send_color).returns('Formatted Divider')
1958
- HashDelegator.stubs(:safeval).returns('Safe Value')
1959
- end
2222
+ class TestHashDelegatorAppendDivider < Minitest::Test
2223
+ def setup
2224
+ @hd = HashDelegator.new
2225
+ @hd.instance_variable_set(:@delegate_object, {
2226
+ menu_divider_format: 'Format',
2227
+ menu_initial_divider: 'Initial Divider',
2228
+ menu_final_divider: 'Final Divider',
2229
+ menu_divider_color: :color
2230
+ })
2231
+ @hd.stubs(:string_send_color).returns('Formatted Divider')
2232
+ HashDelegator.stubs(:safeval).returns('Safe Value')
2233
+ end
1960
2234
 
1961
- def test_append_divider_initial
1962
- menu_blocks = []
1963
- @hd.append_divider(menu_blocks, :initial)
2235
+ def test_append_divider_initial
2236
+ menu_blocks = []
2237
+ @hd.append_divider(menu_blocks, :initial)
1964
2238
 
1965
- assert_equal 1, menu_blocks.size
1966
- assert_equal 'Formatted Divider', menu_blocks.first.dname
1967
- end
2239
+ assert_equal 1, menu_blocks.size
2240
+ assert_equal 'Formatted Divider', menu_blocks.first.dname
2241
+ end
1968
2242
 
1969
- def test_append_divider_final
1970
- menu_blocks = []
1971
- @hd.append_divider(menu_blocks, :final)
2243
+ def test_append_divider_final
2244
+ menu_blocks = []
2245
+ @hd.append_divider(menu_blocks, :final)
1972
2246
 
1973
- assert_equal 1, menu_blocks.size
1974
- assert_equal 'Formatted Divider', menu_blocks.last.dname
1975
- end
2247
+ assert_equal 1, menu_blocks.size
2248
+ assert_equal 'Formatted Divider', menu_blocks.last.dname
2249
+ end
1976
2250
 
1977
- def test_append_divider_without_format
1978
- @hd.instance_variable_set(:@delegate_object, {})
1979
- menu_blocks = []
1980
- @hd.append_divider(menu_blocks, :initial)
2251
+ def test_append_divider_without_format
2252
+ @hd.instance_variable_set(:@delegate_object, {})
2253
+ menu_blocks = []
2254
+ @hd.append_divider(menu_blocks, :initial)
1981
2255
 
1982
- assert_empty menu_blocks
1983
- end
2256
+ assert_empty menu_blocks
1984
2257
  end
2258
+ end
1985
2259
 
1986
- class TestHashDelegatorBlockFind < Minitest::Test
1987
- def setup
1988
- @hd = HashDelegator.new
1989
- end
2260
+ class TestHashDelegatorBlockFind < Minitest::Test
2261
+ def setup
2262
+ @hd = HashDelegator.new
2263
+ end
1990
2264
 
1991
- def test_block_find_with_match
1992
- blocks = [{ key: 'value1' }, { key: 'value2' }]
1993
- result = HashDelegator.block_find(blocks, :key, 'value1')
1994
- assert_equal({ key: 'value1' }, result)
1995
- end
2265
+ def test_block_find_with_match
2266
+ blocks = [{ key: 'value1' }, { key: 'value2' }]
2267
+ result = HashDelegator.block_find(blocks, :key, 'value1')
2268
+ assert_equal({ key: 'value1' }, result)
2269
+ end
1996
2270
 
1997
- def test_block_find_without_match
1998
- blocks = [{ key: 'value1' }, { key: 'value2' }]
1999
- result = HashDelegator.block_find(blocks, :key, 'value3')
2000
- assert_nil result
2001
- end
2271
+ def test_block_find_without_match
2272
+ blocks = [{ key: 'value1' }, { key: 'value2' }]
2273
+ result = HashDelegator.block_find(blocks, :key, 'value3')
2274
+ assert_nil result
2275
+ end
2002
2276
 
2003
- def test_block_find_with_default
2004
- blocks = [{ key: 'value1' }, { key: 'value2' }]
2005
- result = HashDelegator.block_find(blocks, :key, 'value3', 'default')
2006
- assert_equal 'default', result
2007
- end
2277
+ def test_block_find_with_default
2278
+ blocks = [{ key: 'value1' }, { key: 'value2' }]
2279
+ result = HashDelegator.block_find(blocks, :key, 'value3', 'default')
2280
+ assert_equal 'default', result
2008
2281
  end
2282
+ end
2009
2283
 
2010
- class TestHashDelegatorBlocksFromNestedFiles < Minitest::Test
2011
- def setup
2012
- @hd = HashDelegator.new
2013
- @hd.stubs(:iter_blocks_from_nested_files).yields(:blocks, FCB.new)
2014
- @hd.stubs(:get_block_summary).returns(FCB.new)
2015
- @hd.stubs(:create_and_add_chrome_blocks)
2016
- @hd.instance_variable_set(:@delegate_object, {})
2017
- HashDelegator.stubs(:error_handler)
2018
- end
2284
+ class TestHashDelegatorBlocksFromNestedFiles < Minitest::Test
2285
+ def setup
2286
+ @hd = HashDelegator.new
2287
+ @hd.stubs(:iter_blocks_from_nested_files).yields(:blocks, FCB.new)
2288
+ @hd.stubs(:get_block_summary).returns(FCB.new)
2289
+ @hd.stubs(:create_and_add_chrome_blocks)
2290
+ @hd.instance_variable_set(:@delegate_object, {})
2291
+ HashDelegator.stubs(:error_handler)
2292
+ end
2019
2293
 
2020
- def test_blocks_from_nested_files
2021
- result = @hd.blocks_from_nested_files
2294
+ def test_blocks_from_nested_files
2295
+ result = @hd.blocks_from_nested_files
2022
2296
 
2023
- assert_kind_of Array, result
2024
- assert_kind_of FCB, result.first
2025
- end
2297
+ assert_kind_of Array, result
2298
+ assert_kind_of FCB, result.first
2299
+ end
2026
2300
 
2027
- def test_blocks_from_nested_files_with_no_chrome
2028
- @hd.instance_variable_set(:@delegate_object, { no_chrome: true })
2029
- @hd.expects(:create_and_add_chrome_blocks).never
2301
+ def test_blocks_from_nested_files_with_no_chrome
2302
+ @hd.instance_variable_set(:@delegate_object, { no_chrome: true })
2303
+ @hd.expects(:create_and_add_chrome_blocks).never
2030
2304
 
2031
- result = @hd.blocks_from_nested_files
2305
+ result = @hd.blocks_from_nested_files
2032
2306
 
2033
- assert_kind_of Array, result
2034
- end
2307
+ assert_kind_of Array, result
2035
2308
  end
2309
+ end
2036
2310
 
2037
- class TestHashDelegatorCollectRequiredCodeLines < Minitest::Test
2038
- def setup
2039
- @hd = HashDelegator.new
2040
- @hd.instance_variable_set(:@delegate_object, {})
2041
- @mdoc = mock('YourMDocClass')
2042
- @selected = { shell: BlockType::VARS, body: ['key: value'] }
2043
- HashDelegator.stubs(:read_required_blocks_from_temp_file).returns([])
2044
- @hd.stubs(:string_send_color)
2045
- @hd.stubs(:print)
2046
- end
2311
+ class TestHashDelegatorCollectRequiredCodeLines < Minitest::Test
2312
+ def setup
2313
+ @hd = HashDelegator.new
2314
+ @hd.instance_variable_set(:@delegate_object, {})
2315
+ @mdoc = mock('YourMDocClass')
2316
+ @selected = { shell: BlockType::VARS, body: ['key: value'] }
2317
+ HashDelegator.stubs(:read_required_blocks_from_temp_file).returns([])
2318
+ @hd.stubs(:string_send_color)
2319
+ @hd.stubs(:print)
2320
+ end
2047
2321
 
2048
- def test_collect_required_code_lines_with_vars
2049
- YAML.stubs(:load).returns({ 'key' => 'value' })
2050
- @mdoc.stubs(:collect_recursively_required_code).returns({ code: ['code line'] })
2051
- result = @hd.collect_required_code_lines(@mdoc, @selected, block_source: {})
2322
+ def test_collect_required_code_lines_with_vars
2323
+ YAML.stubs(:load).returns({ 'key' => 'value' })
2324
+ @mdoc.stubs(:collect_recursively_required_code).returns({ code: ['code line'] })
2325
+ result = @hd.collect_required_code_lines(@mdoc, @selected, block_source: {})
2052
2326
 
2053
- assert_equal ['code line'], result
2054
- end
2327
+ assert_equal ['code line', 'key="value"'], result
2055
2328
  end
2329
+ end
2056
2330
 
2057
- class TestHashDelegatorCommandOrUserSelectedBlock < Minitest::Test
2058
- def setup
2059
- @hd = HashDelegator.new
2060
- @hd.instance_variable_set(:@delegate_object, {})
2061
- HashDelegator.stubs(:error_handler)
2062
- @hd.stubs(:wait_for_user_selected_block)
2063
- end
2331
+ class TestHashDelegatorCommandOrUserSelectedBlock < Minitest::Test
2332
+ def setup
2333
+ @hd = HashDelegator.new
2334
+ @hd.instance_variable_set(:@delegate_object, {})
2335
+ HashDelegator.stubs(:error_handler)
2336
+ @hd.stubs(:wait_for_user_selected_block)
2337
+ end
2064
2338
 
2065
- def test_command_selected_block
2066
- all_blocks = [{ oname: 'block1' }, { oname: 'block2' }]
2067
- @hd.instance_variable_set(:@delegate_object,
2068
- { block_name: 'block1' })
2339
+ def test_command_selected_block
2340
+ all_blocks = [{ oname: 'block1' }, { oname: 'block2' }]
2341
+ @hd.instance_variable_set(:@delegate_object,
2342
+ { block_name: 'block1' })
2069
2343
 
2070
- result = @hd.load_cli_or_user_selected_block(all_blocks, [], nil)
2344
+ result = @hd.load_cli_or_user_selected_block(all_blocks, [], nil)
2071
2345
 
2072
- assert_equal all_blocks.first.merge(block_name_from_ui: false), result.block
2073
- assert_nil result.state
2074
- end
2346
+ assert_equal all_blocks.first.merge(block_name_from_ui: false), result.block
2347
+ assert_nil result.state
2348
+ end
2075
2349
 
2076
- def test_user_selected_block
2077
- block_state = SelectedBlockMenuState.new({ oname: 'block2' },
2078
- :some_state)
2079
- @hd.stubs(:wait_for_user_selected_block).returns(block_state)
2350
+ def test_user_selected_block
2351
+ block_state = SelectedBlockMenuState.new({ oname: 'block2' },
2352
+ :some_state)
2353
+ @hd.stubs(:wait_for_user_selected_block).returns(block_state)
2080
2354
 
2081
- result = @hd.load_cli_or_user_selected_block([], [], nil)
2355
+ result = @hd.load_cli_or_user_selected_block([], [], nil)
2082
2356
 
2083
- assert_equal block_state.block.merge(block_name_from_ui: true), result.block
2084
- assert_equal :some_state, result.state
2085
- end
2357
+ assert_equal block_state.block.merge(block_name_from_ui: true), result.block
2358
+ assert_equal :some_state, result.state
2086
2359
  end
2360
+ end
2087
2361
 
2088
- class TestHashDelegatorCountBlockInFilename < Minitest::Test
2089
- def setup
2090
- @hd = HashDelegator.new
2091
- @hd.instance_variable_set(:@delegate_object,
2092
- { fenced_start_and_end_regex: '^```',
2093
- filename: '/path/to/file' })
2094
- @hd.stubs(:cfile).returns(mock('cfile'))
2095
- end
2362
+ class TestHashDelegatorCountBlockInFilename < Minitest::Test
2363
+ def setup
2364
+ @hd = HashDelegator.new
2365
+ @hd.instance_variable_set(:@delegate_object,
2366
+ { fenced_start_and_end_regex: '^```',
2367
+ filename: '/path/to/file' })
2368
+ @hd.stubs(:cfile).returns(mock('cfile'))
2369
+ end
2096
2370
 
2097
- def test_count_blocks_in_filename
2098
- file_content = ["```ruby\n", "puts 'Hello'\n", "```\n",
2099
- "```python\n", "print('Hello')\n", "```\n"]
2100
- @hd.cfile.stubs(:readlines).with('/path/to/file').returns(file_content)
2371
+ def test_count_blocks_in_filename
2372
+ file_content = ["```ruby\n", "puts 'Hello'\n", "```\n",
2373
+ "```python\n", "print('Hello')\n", "```\n"]
2374
+ @hd.cfile.stubs(:readlines).with('/path/to/file',
2375
+ import_paths: nil).returns(file_content)
2101
2376
 
2102
- count = @hd.count_blocks_in_filename
2377
+ count = @hd.count_blocks_in_filename
2103
2378
 
2104
- assert_equal 2, count
2105
- end
2379
+ assert_equal 2, count
2380
+ end
2106
2381
 
2107
- def test_count_blocks_in_filename_with_no_matches
2108
- file_content = ["puts 'Hello'\n", "print('Hello')\n"]
2109
- @hd.cfile.stubs(:readlines).with('/path/to/file').returns(file_content)
2382
+ def test_count_blocks_in_filename_with_no_matches
2383
+ file_content = ["puts 'Hello'\n", "print('Hello')\n"]
2384
+ @hd.cfile.stubs(:readlines).with('/path/to/file',
2385
+ import_paths: nil).returns(file_content)
2110
2386
 
2111
- count = @hd.count_blocks_in_filename
2387
+ count = @hd.count_blocks_in_filename
2112
2388
 
2113
- assert_equal 0, count
2114
- end
2389
+ assert_equal 0, count
2115
2390
  end
2391
+ end
2116
2392
 
2117
- class TestHashDelegatorCreateAndWriteFile < Minitest::Test
2118
- def setup
2119
- @hd = HashDelegator.new
2120
- HashDelegator.stubs(:error_handler)
2121
- FileUtils.stubs(:mkdir_p)
2122
- File.stubs(:write)
2123
- File.stubs(:chmod)
2124
- end
2393
+ class TestHashDelegatorCreateAndWriteFile < Minitest::Test
2394
+ def setup
2395
+ @hd = HashDelegator.new
2396
+ HashDelegator.stubs(:error_handler)
2397
+ FileUtils.stubs(:mkdir_p)
2398
+ File.stubs(:write)
2399
+ File.stubs(:chmod)
2400
+ end
2125
2401
 
2126
- def test_create_file_and_write_string_with_permissions
2127
- file_path = '/path/to/file'
2128
- content = 'sample content'
2129
- chmod_value = 0o644
2402
+ def test_create_file_and_write_string_with_permissions
2403
+ file_path = '/path/to/file'
2404
+ content = 'sample content'
2405
+ chmod_value = 0o644
2130
2406
 
2131
- FileUtils.expects(:mkdir_p).with('/path/to').once
2132
- File.expects(:write).with(file_path, content).once
2133
- File.expects(:chmod).with(chmod_value, file_path).once
2407
+ FileUtils.expects(:mkdir_p).with('/path/to').once
2408
+ File.expects(:write).with(file_path, content).once
2409
+ File.expects(:chmod).with(chmod_value, file_path).once
2134
2410
 
2135
- HashDelegator.create_file_and_write_string_with_permissions(file_path, content,
2136
- chmod_value)
2411
+ HashDelegator.create_file_and_write_string_with_permissions(file_path, content,
2412
+ chmod_value)
2137
2413
 
2138
- assert true # Placeholder for actual test assertions
2139
- end
2414
+ assert true # Placeholder for actual test assertions
2415
+ end
2140
2416
 
2141
- def test_create_and_write_file_without_chmod
2142
- file_path = '/path/to/file'
2143
- content = 'sample content'
2144
- chmod_value = 0
2417
+ def test_create_and_write_file_without_chmod
2418
+ file_path = '/path/to/file'
2419
+ content = 'sample content'
2420
+ chmod_value = 0
2145
2421
 
2146
- FileUtils.expects(:mkdir_p).with('/path/to').once
2147
- File.expects(:write).with(file_path, content).once
2148
- File.expects(:chmod).never
2422
+ FileUtils.expects(:mkdir_p).with('/path/to').once
2423
+ File.expects(:write).with(file_path, content).once
2424
+ File.expects(:chmod).never
2149
2425
 
2150
- HashDelegator.create_file_and_write_string_with_permissions(file_path, content,
2151
- chmod_value)
2426
+ HashDelegator.create_file_and_write_string_with_permissions(file_path, content,
2427
+ chmod_value)
2152
2428
 
2153
- assert true # Placeholder for actual test assertions
2154
- end
2429
+ assert true # Placeholder for actual test assertions
2155
2430
  end
2431
+ end
2156
2432
 
2157
- class TestHashDelegatorDetermineBlockState < Minitest::Test
2158
- def setup
2159
- @hd = HashDelegator.new
2160
- @hd.stubs(:menu_chrome_formatted_option).returns('Formatted Option')
2161
- end
2162
-
2163
- def test_determine_block_state_exit
2164
- selected_option = { oname: 'Formatted Option' }
2165
- @hd.stubs(:menu_chrome_formatted_option).with(:menu_option_exit_name).returns('Formatted Option')
2166
-
2167
- result = @hd.determine_block_state(selected_option)
2168
-
2169
- assert_equal MenuState::EXIT, result.state
2170
- assert_nil result.block
2171
- end
2433
+ class TestHashDelegatorDetermineBlockState < Minitest::Test
2434
+ def setup
2435
+ @hd = HashDelegator.new
2436
+ @hd.stubs(:menu_chrome_formatted_option).returns('Formatted Option')
2437
+ end
2172
2438
 
2173
- def test_determine_block_state_back
2174
- selected_option = { oname: 'Formatted Back Option' }
2175
- @hd.stubs(:menu_chrome_formatted_option).with(:menu_option_back_name).returns('Formatted Back Option')
2176
- result = @hd.determine_block_state(selected_option)
2439
+ def test_determine_block_state_exit
2440
+ selected_option = { oname: 'Formatted Option' }
2441
+ @hd.stubs(:menu_chrome_formatted_option).with(:menu_option_exit_name).returns('Formatted Option')
2177
2442
 
2178
- assert_equal MenuState::BACK, result.state
2179
- assert_equal selected_option, result.block
2180
- end
2443
+ result = @hd.determine_block_state(selected_option)
2181
2444
 
2182
- def test_determine_block_state_continue
2183
- selected_option = { oname: 'Other Option' }
2445
+ assert_equal MenuState::EXIT, result.state
2446
+ assert_nil result.block
2447
+ end
2184
2448
 
2185
- result = @hd.determine_block_state(selected_option)
2449
+ def test_determine_block_state_back
2450
+ selected_option = { oname: 'Formatted Back Option' }
2451
+ @hd.stubs(:menu_chrome_formatted_option).with(:menu_option_back_name).returns('Formatted Back Option')
2452
+ result = @hd.determine_block_state(selected_option)
2186
2453
 
2187
- assert_equal MenuState::CONTINUE, result.state
2188
- assert_equal selected_option, result.block
2189
- end
2454
+ assert_equal MenuState::BACK, result.state
2455
+ assert_equal selected_option, result.block
2190
2456
  end
2191
2457
 
2192
- class TestHashDelegatorDisplayRequiredCode < Minitest::Test
2193
- def setup
2194
- @hd = HashDelegator.new
2195
- @hd.instance_variable_set(:@fout, mock('fout'))
2196
- @hd.instance_variable_set(:@delegate_object, {})
2197
- @hd.stubs(:string_send_color)
2198
- end
2458
+ def test_determine_block_state_continue
2459
+ selected_option = { oname: 'Other Option' }
2199
2460
 
2200
- def test_display_required_code
2201
- required_lines = %w[line1 line2]
2202
- @hd.instance_variable_get(:@delegate_object).stubs(:[]).with(:script_preview_head).returns('Header')
2203
- @hd.instance_variable_get(:@delegate_object).stubs(:[]).with(:script_preview_tail).returns('Footer')
2204
- @hd.instance_variable_get(:@fout).expects(:fout).times(4)
2461
+ result = @hd.determine_block_state(selected_option)
2205
2462
 
2206
- @hd.display_required_code(required_lines)
2463
+ assert_equal MenuState::CONTINUE, result.state
2464
+ assert_equal selected_option, result.block
2465
+ end
2466
+ end
2207
2467
 
2208
- # Verifying that fout is called for each line and for header & footer
2209
- assert true # Placeholder for actual test assertions
2210
- end
2468
+ class TestHashDelegatorDisplayRequiredCode < Minitest::Test
2469
+ def setup
2470
+ @hd = HashDelegator.new
2471
+ @hd.instance_variable_set(:@fout, mock('fout'))
2472
+ @hd.instance_variable_set(:@delegate_object, {})
2473
+ @hd.stubs(:string_send_color)
2211
2474
  end
2212
2475
 
2213
- class TestHashDelegatorFetchColor < Minitest::Test
2214
- def setup
2215
- @hd = HashDelegator.new
2216
- @hd.instance_variable_set(:@delegate_object, {})
2217
- end
2476
+ def test_display_required_code
2477
+ required_lines = %w[line1 line2]
2478
+ @hd.instance_variable_get(:@delegate_object).stubs(:[]).with(:script_preview_head).returns('Header')
2479
+ @hd.instance_variable_get(:@delegate_object).stubs(:[]).with(:script_preview_tail).returns('Footer')
2480
+ @hd.instance_variable_get(:@fout).expects(:fout).times(4)
2218
2481
 
2219
- def test_fetch_color_with_valid_data
2220
- @hd.instance_variable_get(:@delegate_object).stubs(:fetch).with(
2221
- :execution_report_preview_head, ''
2222
- ).returns('Data String')
2223
- @hd.stubs(:string_send_color).with('Data String',
2224
- :execution_report_preview_frame_color).returns('Colored Data String')
2482
+ @hd.display_required_code(required_lines)
2225
2483
 
2226
- result = @hd.fetch_color
2484
+ # Verifying that fout is called for each line and for header & footer
2485
+ assert true # Placeholder for actual test assertions
2486
+ end
2487
+ end
2227
2488
 
2228
- assert_equal 'Colored Data String', result
2229
- end
2489
+ class TestHashDelegatorFetchColor < Minitest::Test
2490
+ def setup
2491
+ @hd = HashDelegator.new
2492
+ @hd.instance_variable_set(:@delegate_object, {})
2493
+ end
2230
2494
 
2231
- def test_fetch_color_with_missing_data
2232
- @hd.instance_variable_get(:@delegate_object).stubs(:fetch).with(
2233
- :execution_report_preview_head, ''
2234
- ).returns('')
2235
- @hd.stubs(:string_send_color).with('',
2236
- :execution_report_preview_frame_color).returns('Default Colored String')
2495
+ def test_fetch_color_with_valid_data
2496
+ @hd.instance_variable_get(:@delegate_object).stubs(:fetch).with(
2497
+ :execution_report_preview_head, ''
2498
+ ).returns('Data String')
2499
+ @hd.stubs(:string_send_color).with('Data String',
2500
+ :execution_report_preview_frame_color).returns('Colored Data String')
2237
2501
 
2238
- result = @hd.fetch_color
2502
+ result = @hd.fetch_color
2239
2503
 
2240
- assert_equal 'Default Colored String', result
2241
- end
2504
+ assert_equal 'Colored Data String', result
2242
2505
  end
2243
2506
 
2244
- class TestHashDelegatorFormatReferencesSendColor < Minitest::Test
2245
- def setup
2246
- @hd = HashDelegator.new
2247
- @hd.instance_variable_set(:@delegate_object, {})
2248
- end
2507
+ def test_fetch_color_with_missing_data
2508
+ @hd.instance_variable_get(:@delegate_object).stubs(:fetch).with(
2509
+ :execution_report_preview_head, ''
2510
+ ).returns('')
2511
+ @hd.stubs(:string_send_color).with('',
2512
+ :execution_report_preview_frame_color).returns('Default Colored String')
2249
2513
 
2250
- def test_format_references_send_color_with_valid_data
2251
- @hd.instance_variable_get(:@delegate_object).stubs(:fetch).with(
2252
- :output_execution_label_format, ''
2253
- ).returns('Formatted: %{key}')
2254
- @hd.stubs(:string_send_color).returns('Colored String')
2514
+ result = @hd.fetch_color
2255
2515
 
2256
- result = @hd.format_references_send_color(context: { key: 'value' },
2257
- color_sym: :execution_report_preview_frame_color)
2516
+ assert_equal 'Default Colored String', result
2517
+ end
2518
+ end
2258
2519
 
2259
- assert_equal 'Colored String', result
2260
- end
2520
+ class TestHashDelegatorFormatReferencesSendColor < Minitest::Test
2521
+ def setup
2522
+ @hd = HashDelegator.new
2523
+ @hd.instance_variable_set(:@delegate_object, {})
2524
+ end
2261
2525
 
2262
- def test_format_references_send_color_with_missing_format
2263
- @hd.instance_variable_get(:@delegate_object).stubs(:fetch).with(
2264
- :output_execution_label_format, ''
2265
- ).returns('')
2266
- @hd.stubs(:string_send_color).returns('Default Colored String')
2526
+ def test_format_references_send_color_with_valid_data
2527
+ @hd.instance_variable_get(:@delegate_object).stubs(:fetch).with(
2528
+ :output_execution_label_format, ''
2529
+ ).returns('Formatted: %{key}')
2530
+ @hd.stubs(:string_send_color).returns('Colored String')
2267
2531
 
2268
- result = @hd.format_references_send_color(context: { key: 'value' },
2269
- color_sym: :execution_report_preview_frame_color)
2532
+ result = @hd.format_references_send_color(context: { key: 'value' },
2533
+ color_sym: :execution_report_preview_frame_color)
2270
2534
 
2271
- assert_equal 'Default Colored String', result
2272
- end
2535
+ assert_equal 'Colored String', result
2273
2536
  end
2274
2537
 
2275
- class TestHashDelegatorFormatExecutionStreams < Minitest::Test
2276
- def setup
2277
- @hd = HashDelegator.new
2278
- @hd.instance_variable_set(:@run_state, mock('run_state'))
2279
- end
2538
+ def test_format_references_send_color_with_missing_format
2539
+ @hd.instance_variable_get(:@delegate_object).stubs(:fetch).with(
2540
+ :output_execution_label_format, ''
2541
+ ).returns('')
2542
+ @hd.stubs(:string_send_color).returns('Default Colored String')
2280
2543
 
2281
- def test_format_execution_streams_with_valid_key
2282
- result = HashDelegator.format_execution_streams(:stdout,
2283
- { stdout: %w[output1 output2] })
2544
+ result = @hd.format_references_send_color(context: { key: 'value' },
2545
+ color_sym: :execution_report_preview_frame_color)
2284
2546
 
2285
- assert_equal 'output1output2', result
2286
- end
2547
+ assert_equal 'Default Colored String', result
2548
+ end
2549
+ end
2287
2550
 
2288
- def test_format_execution_streams_with_empty_key
2289
- @hd.instance_variable_get(:@run_state).stubs(:files).returns({})
2551
+ class TestHashDelegatorFormatExecutionStreams < Minitest::Test
2552
+ def setup
2553
+ @hd = HashDelegator.new
2554
+ @hd.instance_variable_set(:@run_state, mock('run_state'))
2555
+ end
2290
2556
 
2291
- result = HashDelegator.format_execution_streams(:stderr)
2557
+ def test_format_execution_streams_with_valid_key
2558
+ result = HashDelegator.format_execution_streams(:stdout,
2559
+ { stdout: %w[output1 output2] })
2292
2560
 
2293
- assert_equal '', result
2294
- end
2561
+ assert_equal 'output1output2', result
2562
+ end
2295
2563
 
2296
- def test_format_execution_streams_with_nil_files
2297
- @hd.instance_variable_get(:@run_state).stubs(:files).returns(nil)
2564
+ def test_format_execution_streams_with_empty_key
2565
+ @hd.instance_variable_get(:@run_state).stubs(:files).returns({})
2298
2566
 
2299
- result = HashDelegator.format_execution_streams(:stdin)
2567
+ result = HashDelegator.format_execution_streams(:stderr)
2300
2568
 
2301
- assert_equal '', result
2302
- end
2569
+ assert_equal '', result
2303
2570
  end
2304
2571
 
2305
- class TestHashDelegatorHandleBackLink < Minitest::Test
2306
- def setup
2307
- @hd = HashDelegator.new
2308
- @hd.stubs(:history_state_pop)
2309
- end
2572
+ def test_format_execution_streams_with_nil_files
2573
+ @hd.instance_variable_get(:@run_state).stubs(:files).returns(nil)
2310
2574
 
2311
- def test_pop_link_history_and_trigger_load
2312
- # Verifying that history_state_pop is called
2313
- # @hd.expects(:history_state_pop).once
2575
+ result = HashDelegator.format_execution_streams(:stdin)
2314
2576
 
2315
- result = @hd.pop_link_history_and_trigger_load
2577
+ assert_equal '', result
2578
+ end
2579
+ end
2316
2580
 
2317
- # Asserting the result is an instance of LoadFileLinkState
2318
- assert_instance_of LoadFileLinkState, result
2319
- assert_equal LoadFile::Load, result.load_file
2320
- assert_nil result.link_state.block_name
2321
- end
2581
+ class TestHashDelegatorHandleBackLink < Minitest::Test
2582
+ def setup
2583
+ @hd = HashDelegator.new
2584
+ @hd.stubs(:history_state_pop)
2322
2585
  end
2323
2586
 
2324
- class TestHashDelegatorHandleBlockState < Minitest::Test
2325
- def setup
2326
- @hd = HashDelegator.new
2327
- @mock_block_state = mock('block_state')
2328
- end
2587
+ def test_pop_link_history_and_trigger_load
2588
+ # Verifying that history_state_pop is called
2589
+ # @hd.expects(:history_state_pop).once
2329
2590
 
2330
- def test_handle_back_or_continue_with_back
2331
- @mock_block_state.stubs(:state).returns(MenuState::BACK)
2332
- @mock_block_state.stubs(:block).returns({ oname: 'sample_block' })
2591
+ result = @hd.pop_link_history_and_trigger_load
2333
2592
 
2334
- @hd.handle_back_or_continue(@mock_block_state)
2593
+ # Asserting the result is an instance of LoadFileLinkState
2594
+ assert_instance_of LoadFileLinkState, result
2595
+ assert_equal LoadFile::Load, result.load_file
2596
+ assert_nil result.link_state.block_name
2597
+ end
2598
+ end
2335
2599
 
2336
- assert_equal 'sample_block',
2337
- @hd.instance_variable_get(:@delegate_object)[:block_name]
2338
- assert @hd.instance_variable_get(:@menu_user_clicked_back_link)
2339
- end
2600
+ class TestHashDelegatorHandleBlockState < Minitest::Test
2601
+ def setup
2602
+ @hd = HashDelegator.new
2603
+ @mock_block_state = mock('block_state')
2604
+ end
2340
2605
 
2341
- def test_handle_back_or_continue_with_continue
2342
- @mock_block_state.stubs(:state).returns(MenuState::CONTINUE)
2343
- @mock_block_state.stubs(:block).returns({ oname: 'another_block' })
2606
+ def test_handle_back_or_continue_with_back
2607
+ @mock_block_state.stubs(:state).returns(MenuState::BACK)
2608
+ @mock_block_state.stubs(:block).returns({ oname: 'sample_block' })
2344
2609
 
2345
- @hd.handle_back_or_continue(@mock_block_state)
2610
+ @hd.handle_back_or_continue(@mock_block_state)
2346
2611
 
2347
- assert_equal 'another_block',
2348
- @hd.instance_variable_get(:@delegate_object)[:block_name]
2349
- refute @hd.instance_variable_get(:@menu_user_clicked_back_link)
2350
- end
2612
+ assert_equal 'sample_block',
2613
+ @hd.instance_variable_get(:@delegate_object)[:block_name]
2614
+ assert @hd.instance_variable_get(:@menu_user_clicked_back_link)
2615
+ end
2351
2616
 
2352
- def test_handle_back_or_continue_with_other
2353
- @mock_block_state.stubs(:state).returns(nil) # MenuState::OTHER
2354
- @mock_block_state.stubs(:block).returns({ oname: 'other_block' })
2617
+ def test_handle_back_or_continue_with_continue
2618
+ @mock_block_state.stubs(:state).returns(MenuState::CONTINUE)
2619
+ @mock_block_state.stubs(:block).returns({ oname: 'another_block' })
2355
2620
 
2356
- @hd.handle_back_or_continue(@mock_block_state)
2621
+ @hd.handle_back_or_continue(@mock_block_state)
2357
2622
 
2358
- assert_nil @hd.instance_variable_get(:@delegate_object)[:block_name]
2359
- assert_nil @hd.instance_variable_get(:@menu_user_clicked_back_link)
2360
- end
2623
+ assert_equal 'another_block',
2624
+ @hd.instance_variable_get(:@delegate_object)[:block_name]
2625
+ refute @hd.instance_variable_get(:@menu_user_clicked_back_link)
2361
2626
  end
2362
2627
 
2363
- class TestHashDelegatorHandleGenericBlock < Minitest::Test
2364
- def setup
2365
- @hd = HashDelegator.new
2366
- @mock_document = mock('MarkdownDocument')
2367
- @selected_item = mock('FCB')
2368
- end
2369
-
2370
- def test_compile_execute_and_trigger_reuse_without_user_approval
2371
- # Mock the delegate object configuration
2372
- @hd.instance_variable_set(:@delegate_object,
2373
- { output_script: false,
2374
- user_must_approve: false })
2628
+ def test_handle_back_or_continue_with_other
2629
+ @mock_block_state.stubs(:state).returns(nil) # MenuState::OTHER
2630
+ @mock_block_state.stubs(:block).returns({ oname: 'other_block' })
2375
2631
 
2376
- # Test the method without user approval
2377
- # Expectations and assertions go here
2378
- end
2632
+ @hd.handle_back_or_continue(@mock_block_state)
2379
2633
 
2380
- def test_compile_execute_and_trigger_reuse_with_user_approval
2381
- # Mock the delegate object configuration
2382
- @hd.instance_variable_set(:@delegate_object,
2383
- { output_script: false,
2384
- user_must_approve: true })
2634
+ assert_nil @hd.instance_variable_get(:@delegate_object)[:block_name]
2635
+ assert_nil @hd.instance_variable_get(:@menu_user_clicked_back_link)
2636
+ end
2637
+ end
2385
2638
 
2386
- # Test the method with user approval
2387
- # Expectations and assertions go here
2388
- end
2639
+ class TestHashDelegatorHandleGenericBlock < Minitest::Test
2640
+ def setup
2641
+ @hd = HashDelegator.new
2642
+ @mock_document = mock('MarkdownDocument')
2643
+ @selected_item = mock('FCB')
2644
+ end
2389
2645
 
2390
- def test_compile_execute_and_trigger_reuse_with_output_script
2391
- # Mock the delegate object configuration
2392
- @hd.instance_variable_set(:@delegate_object,
2393
- { output_script: true,
2394
- user_must_approve: false })
2646
+ def test_compile_execute_and_trigger_reuse_without_user_approval
2647
+ # Mock the delegate object configuration
2648
+ @hd.instance_variable_set(:@delegate_object,
2649
+ { output_script: false,
2650
+ user_must_approve: false })
2395
2651
 
2396
- # Test the method with output script option
2397
- # Expectations and assertions go here
2398
- end
2652
+ # Test the method without user approval
2653
+ # Expectations and assertions go here
2399
2654
  end
2400
2655
 
2401
- # require 'stringio'
2656
+ def test_compile_execute_and_trigger_reuse_with_user_approval
2657
+ # Mock the delegate object configuration
2658
+ @hd.instance_variable_set(:@delegate_object,
2659
+ { output_script: false,
2660
+ user_must_approve: true })
2402
2661
 
2403
- class TestHashDelegatorHandleStream < Minitest::Test
2404
- def setup
2405
- @hd = HashDelegator.new
2406
- @hd.instance_variable_set(:@run_state,
2407
- OpenStruct.new(files: { stdout: [] }))
2408
- @hd.instance_variable_set(:@delegate_object,
2409
- { output_stdout: true })
2410
- end
2662
+ # Test the method with user approval
2663
+ # Expectations and assertions go here
2664
+ end
2411
2665
 
2412
- def test_handle_stream
2413
- stream = StringIO.new("line 1\nline 2\n")
2414
- file_type = :stdout
2666
+ def test_compile_execute_and_trigger_reuse_with_output_script
2667
+ # Mock the delegate object configuration
2668
+ @hd.instance_variable_set(:@delegate_object,
2669
+ { output_script: true,
2670
+ user_must_approve: false })
2415
2671
 
2416
- Thread.new { @hd.handle_stream(stream, file_type) }
2672
+ # Test the method with output script option
2673
+ # Expectations and assertions go here
2674
+ end
2675
+ end
2417
2676
 
2418
- @hd.wait_for_stream_processing
2677
+ # require 'stringio'
2419
2678
 
2420
- assert_equal ['line 1', 'line 2'],
2421
- @hd.instance_variable_get(:@run_state).files[:stdout]
2422
- end
2679
+ class TestHashDelegatorHandleStream < Minitest::Test
2680
+ def setup
2681
+ @hd = HashDelegator.new
2682
+ @hd.instance_variable_set(:@run_state,
2683
+ OpenStruct.new(files: { stdout: [] }))
2684
+ @hd.instance_variable_set(:@delegate_object,
2685
+ { output_stdout: true })
2686
+ end
2423
2687
 
2424
- def test_handle_stream_with_io_error
2425
- stream = StringIO.new("line 1\nline 2\n")
2426
- file_type = :stdout
2427
- stream.stubs(:each_line).raises(IOError)
2688
+ def test_handle_stream
2689
+ stream = StringIO.new("line 1\nline 2\n")
2690
+ file_type = :stdout
2428
2691
 
2429
- Thread.new { @hd.handle_stream(stream, file_type) }
2692
+ Thread.new { @hd.handle_stream(stream, file_type) }
2430
2693
 
2431
- @hd.wait_for_stream_processing
2694
+ @hd.wait_for_stream_processing
2432
2695
 
2433
- assert_equal [],
2434
- @hd.instance_variable_get(:@run_state).files[:stdout]
2435
- end
2696
+ assert_equal ['line 1', 'line 2'],
2697
+ @hd.instance_variable_get(:@run_state).files[:stdout]
2436
2698
  end
2437
2699
 
2438
- class TestHashDelegatorIterBlocksFromNestedFiles < Minitest::Test
2439
- def setup
2440
- @hd = HashDelegator.new
2441
- @hd.instance_variable_set(:@delegate_object,
2442
- { filename: 'test.md' })
2443
- @hd.stubs(:check_file_existence).with('test.md').returns(true)
2444
- @hd.stubs(:initial_state).returns({})
2445
- @hd.stubs(:cfile).returns(Minitest::Mock.new)
2446
- @hd.stubs(:update_line_and_block_state)
2447
- end
2448
-
2449
- def test_iter_blocks_from_nested_files
2450
- @hd.cfile.expect(:readlines, ['line 1', 'line 2'], ['test.md'])
2451
- selected_messages = ['filtered message']
2700
+ def test_handle_stream_with_io_error
2701
+ stream = StringIO.new("line 1\nline 2\n")
2702
+ file_type = :stdout
2703
+ stream.stubs(:each_line).raises(IOError)
2452
2704
 
2453
- result = @hd.iter_blocks_from_nested_files { selected_messages }
2454
- assert_equal ['line 1', 'line 2'], result
2705
+ Thread.new { @hd.handle_stream(stream, file_type) }
2455
2706
 
2456
- @hd.cfile.verify
2457
- end
2707
+ @hd.wait_for_stream_processing
2458
2708
 
2459
- def test_iter_blocks_from_nested_files_with_no_file
2460
- @hd.stubs(:check_file_existence).with('test.md').returns(false)
2709
+ assert_equal [],
2710
+ @hd.instance_variable_get(:@run_state).files[:stdout]
2711
+ end
2712
+ end
2461
2713
 
2462
- assert_nil(@hd.iter_blocks_from_nested_files do
2463
- ['filtered message']
2464
- end)
2465
- end
2714
+ class TestHashDelegatorIterBlocksFromNestedFiles < Minitest::Test
2715
+ def setup
2716
+ @hd = HashDelegator.new
2717
+ @hd.instance_variable_set(:@delegate_object,
2718
+ { filename: 'test.md' })
2719
+ @hd.stubs(:check_file_existence).with('test.md').returns(true)
2720
+ @hd.stubs(:initial_state).returns({})
2721
+ @hd.stubs(:cfile).returns(Minitest::Mock.new)
2722
+ @hd.stubs(:update_line_and_block_state)
2466
2723
  end
2467
2724
 
2468
- class TestHashDelegatorMenuChromeColoredOption < Minitest::Test
2469
- def setup
2470
- @hd = HashDelegator.new
2471
- @hd.instance_variable_set(:@delegate_object, {
2472
- menu_option_back_name: 'Back',
2473
- menu_chrome_color: :red,
2474
- menu_chrome_format: '-- %s --'
2475
- })
2476
- @hd.stubs(:menu_chrome_formatted_option).with(:menu_option_back_name).returns('-- Back --')
2477
- @hd.stubs(:string_send_color).with('-- Back --',
2478
- :menu_chrome_color).returns('-- Back --'.red)
2479
- end
2725
+ def test_iter_blocks_from_nested_files
2726
+ @hd.cfile.expect(:readlines, ['line 1', 'line 2'], ['test.md'], import_paths: nil)
2727
+ selected_messages = ['filtered message']
2480
2728
 
2481
- def test_menu_chrome_colored_option_with_color
2482
- assert_equal '-- Back --'.red,
2483
- @hd.menu_chrome_colored_option(:menu_option_back_name)
2484
- end
2729
+ result = @hd.iter_blocks_from_nested_files { selected_messages }
2730
+ assert_equal ['line 1', 'line 2'], result
2485
2731
 
2486
- def test_menu_chrome_colored_option_without_color
2487
- @hd.instance_variable_set(:@delegate_object,
2488
- { menu_option_back_name: 'Back' })
2489
- assert_equal '-- Back --',
2490
- @hd.menu_chrome_colored_option(:menu_option_back_name)
2491
- end
2732
+ @hd.cfile.verify
2492
2733
  end
2493
2734
 
2494
- class TestHashDelegatorMenuChromeFormattedOptionWithoutFormat < Minitest::Test
2495
- def setup
2496
- @hd = HashDelegator.new
2497
- @hd.instance_variable_set(:@delegate_object, {
2498
- menu_option_back_name: "'Back'",
2499
- menu_chrome_format: '-- %s --'
2500
- })
2501
- HashDelegator.stubs(:safeval).with("'Back'").returns('Back')
2502
- end
2503
-
2504
- def test_menu_chrome_formatted_option_with_format
2505
- assert_equal '-- Back --',
2506
- @hd.menu_chrome_formatted_option(:menu_option_back_name)
2507
- end
2735
+ def test_iter_blocks_from_nested_files_with_no_file
2736
+ @hd.stubs(:check_file_existence).with('test.md').returns(false)
2508
2737
 
2509
- def test_menu_chrome_formatted_option_without_format
2510
- @hd.instance_variable_set(:@delegate_object,
2511
- { menu_option_back_name: "'Back'" })
2512
- assert_equal 'Back',
2513
- @hd.menu_chrome_formatted_option(:menu_option_back_name)
2514
- end
2738
+ assert_nil(@hd.iter_blocks_from_nested_files do
2739
+ ['filtered message']
2740
+ end)
2515
2741
  end
2742
+ end
2516
2743
 
2517
- class TestHashDelegatorStartFencedBlock < Minitest::Test
2518
- def setup
2519
- @hd = HashDelegator.new({
2520
- block_name_wrapper_match: 'WRAPPER_REGEX',
2521
- block_calls_scan: 'CALLS_REGEX'
2744
+ class TestHashDelegatorMenuChromeColoredOption < Minitest::Test
2745
+ def setup
2746
+ @hd = HashDelegator.new
2747
+ @hd.instance_variable_set(:@delegate_object, {
2748
+ menu_option_back_name: 'Back',
2749
+ menu_chrome_color: :red,
2750
+ menu_chrome_format: '-- %s --'
2522
2751
  })
2523
- end
2524
-
2525
- def test_start_fenced_block
2526
- line = '```fenced'
2527
- headings = ['Heading 1']
2528
- regex = /```(?<name>\w+)(?<rest>.*)/
2529
-
2530
- fcb = @hd.start_fenced_block(line, headings, regex)
2531
-
2532
- assert_instance_of MarkdownExec::FCB, fcb
2533
- assert_equal headings, fcb.headings
2534
- assert_equal 'fenced', fcb.dname
2535
- end
2752
+ @hd.stubs(:menu_chrome_formatted_option).with(:menu_option_back_name).returns('-- Back --')
2753
+ @hd.stubs(:string_send_color).with('-- Back --',
2754
+ :menu_chrome_color).returns('-- Back --'.red)
2536
2755
  end
2537
2756
 
2538
- class TestHashDelegatorStringSendColor < Minitest::Test
2539
- def setup
2540
- @hd = HashDelegator.new
2541
- @hd.instance_variable_set(:@delegate_object,
2542
- { red: 'red', green: 'green' })
2543
- end
2757
+ def test_menu_chrome_colored_option_with_color
2758
+ assert_equal '-- Back --'.red,
2759
+ @hd.menu_chrome_colored_option(:menu_option_back_name)
2760
+ end
2544
2761
 
2545
- def test_string_send_color
2546
- assert_equal 'Hello'.red, @hd.string_send_color('Hello', :red)
2547
- assert_equal 'World'.green,
2548
- @hd.string_send_color('World', :green)
2549
- assert_equal 'Default'.plain,
2550
- @hd.string_send_color('Default', :blue)
2551
- end
2762
+ def test_menu_chrome_colored_option_without_color
2763
+ @hd.instance_variable_set(:@delegate_object,
2764
+ { menu_option_back_name: 'Back' })
2765
+ assert_equal '-- Back --',
2766
+ @hd.menu_chrome_colored_option(:menu_option_back_name)
2552
2767
  end
2768
+ end
2553
2769
 
2554
- def test_yield_line_if_selected_with_line
2555
- block_called = false
2556
- HashDelegator.yield_line_if_selected('Test line', [:line]) do |type, content|
2557
- block_called = true
2558
- assert_equal :line, type
2559
- assert_equal 'Test line', content.body[0]
2560
- end
2561
- assert block_called
2770
+ class TestHashDelegatorMenuChromeFormattedOptionWithoutFormat < Minitest::Test
2771
+ def setup
2772
+ @hd = HashDelegator.new
2773
+ @hd.instance_variable_set(:@delegate_object, {
2774
+ menu_option_back_name: "'Back'",
2775
+ menu_chrome_format: '-- %s --'
2776
+ })
2777
+ HashDelegator.stubs(:safeval).with("'Back'").returns('Back')
2562
2778
  end
2563
2779
 
2564
- def test_yield_line_if_selected_without_line
2565
- block_called = false
2566
- HashDelegator.yield_line_if_selected('Test line', [:other]) do |_|
2567
- block_called = true
2568
- end
2569
- refute block_called
2780
+ def test_menu_chrome_formatted_option_with_format
2781
+ assert_equal '-- Back --',
2782
+ @hd.menu_chrome_formatted_option(:menu_option_back_name)
2570
2783
  end
2571
2784
 
2572
- def test_yield_line_if_selected_without_block
2573
- result = HashDelegator.yield_line_if_selected('Test line', [:line])
2574
- assert_nil result
2785
+ def test_menu_chrome_formatted_option_without_format
2786
+ @hd.instance_variable_set(:@delegate_object,
2787
+ { menu_option_back_name: "'Back'" })
2788
+ assert_equal 'Back',
2789
+ @hd.menu_chrome_formatted_option(:menu_option_back_name)
2575
2790
  end
2576
2791
  end
2577
2792
 
2578
- class TestHashDelegatorUpdateMenuAttribYieldSelectedWithBody < Minitest::Test
2793
+ class TestHashDelegatorStartFencedBlock < Minitest::Test
2579
2794
  def setup
2580
- @hd = HashDelegator.new
2581
- @fcb = mock('Fcb')
2582
- @fcb.stubs(:body).returns(true)
2583
- HashDelegator.stubs(:initialize_fcb_names)
2584
- HashDelegator.stubs(:default_block_title_from_body)
2585
- Filter.stubs(:yield_to_block_if_applicable)
2795
+ @hd = HashDelegator.new({
2796
+ block_name_wrapper_match: 'WRAPPER_REGEX',
2797
+ block_calls_scan: 'CALLS_REGEX'
2798
+ })
2586
2799
  end
2587
2800
 
2588
- def test_update_menu_attrib_yield_selected_with_body
2589
- HashDelegator.expects(:initialize_fcb_names).with(@fcb)
2590
- HashDelegator.expects(:default_block_title_from_body).with(@fcb)
2591
- Filter.expects(:yield_to_block_if_applicable).with(@fcb, [:some_message], {})
2801
+ def test_start_fenced_block
2802
+ line = '```fenced'
2803
+ headings = ['Heading 1']
2804
+ regex = /```(?<name>\w+)(?<rest>.*)/
2592
2805
 
2593
- HashDelegator.update_menu_attrib_yield_selected(@fcb, [:some_message])
2594
- end
2806
+ fcb = @hd.start_fenced_block(line, headings, regex)
2595
2807
 
2596
- def test_update_menu_attrib_yield_selected_without_body
2597
- @fcb.stubs(:body).returns(nil)
2598
- HashDelegator.expects(:initialize_fcb_names).with(@fcb)
2599
- HashDelegator.update_menu_attrib_yield_selected(@fcb, [:some_message])
2808
+ assert_instance_of MarkdownExec::FCB, fcb
2809
+ assert_equal headings, fcb.headings
2810
+ assert_equal 'fenced', fcb.dname
2600
2811
  end
2601
2812
  end
2602
2813
 
2603
- class TestHashDelegatorWaitForUserSelectedBlock < Minitest::Test
2814
+ class TestHashDelegatorStringSendColor < Minitest::Test
2604
2815
  def setup
2605
2816
  @hd = HashDelegator.new
2606
- HashDelegator.stubs(:error_handler)
2817
+ @hd.instance_variable_set(:@delegate_object,
2818
+ { red: 'red', green: 'green' })
2607
2819
  end
2608
2820
 
2609
- def test_wait_for_user_selected_block_with_back_state
2610
- mock_block_state = Struct.new(:state, :block).new(MenuState::BACK,
2611
- { oname: 'back_block' })
2612
- @hd.stubs(:wait_for_user_selection).returns(mock_block_state)
2821
+ def test_string_send_color
2822
+ assert_equal 'Hello'.red, @hd.string_send_color('Hello', :red)
2823
+ assert_equal 'World'.green,
2824
+ @hd.string_send_color('World', :green)
2825
+ assert_equal 'Default'.plain,
2826
+ @hd.string_send_color('Default', :blue)
2827
+ end
2828
+ end
2613
2829
 
2614
- result = @hd.wait_for_user_selected_block([], ['Block 1', 'Block 2'],
2615
- nil)
2830
+ def test_yield_line_if_selected_with_line
2831
+ block_called = false
2832
+ HashDelegator.yield_line_if_selected('Test line', [:line]) do |type, content|
2833
+ block_called = true
2834
+ assert_equal :line, type
2835
+ assert_equal 'Test line', content.body[0]
2836
+ end
2837
+ assert block_called
2838
+ end
2616
2839
 
2617
- assert_equal 'back_block',
2618
- @hd.instance_variable_get(:@delegate_object)[:block_name]
2619
- assert @hd.instance_variable_get(:@menu_user_clicked_back_link)
2620
- assert_equal mock_block_state, result
2840
+ def test_yield_line_if_selected_without_line
2841
+ block_called = false
2842
+ HashDelegator.yield_line_if_selected('Test line', [:other]) do |_|
2843
+ block_called = true
2621
2844
  end
2845
+ refute block_called
2846
+ end
2622
2847
 
2623
- def test_wait_for_user_selected_block_with_continue_state
2624
- mock_block_state = Struct.new(:state, :block).new(
2625
- MenuState::CONTINUE, { oname: 'continue_block' }
2626
- )
2627
- @hd.stubs(:wait_for_user_selection).returns(mock_block_state)
2848
+ def test_yield_line_if_selected_without_block
2849
+ result = HashDelegator.yield_line_if_selected('Test line', [:line])
2850
+ assert_nil result
2851
+ end
2852
+ end
2628
2853
 
2629
- result = @hd.wait_for_user_selected_block([], ['Block 1', 'Block 2'],
2630
- nil)
2854
+ class TestHashDelegatorUpdateMenuAttribYieldSelectedWithBody < Minitest::Test
2855
+ def setup
2856
+ @hd = HashDelegator.new
2857
+ @fcb = mock('Fcb')
2858
+ @fcb.stubs(:body).returns(true)
2859
+ HashDelegator.stubs(:initialize_fcb_names)
2860
+ HashDelegator.stubs(:default_block_title_from_body)
2861
+ Filter.stubs(:yield_to_block_if_applicable)
2862
+ end
2631
2863
 
2632
- assert_equal 'continue_block',
2633
- @hd.instance_variable_get(:@delegate_object)[:block_name]
2634
- refute @hd.instance_variable_get(:@menu_user_clicked_back_link)
2635
- assert_equal mock_block_state, result
2636
- end
2864
+ def test_update_menu_attrib_yield_selected_with_body
2865
+ HashDelegator.expects(:initialize_fcb_names).with(@fcb)
2866
+ HashDelegator.expects(:default_block_title_from_body).with(@fcb)
2867
+ Filter.expects(:yield_to_block_if_applicable).with(@fcb, [:some_message], {})
2868
+
2869
+ HashDelegator.update_menu_attrib_yield_selected(@fcb, [:some_message])
2637
2870
  end
2638
2871
 
2639
- class TestHashDelegatorYieldToBlock < Minitest::Test
2640
- def setup
2641
- @hd = HashDelegator.new
2642
- @fcb = mock('Fcb')
2643
- MarkdownExec::Filter.stubs(:fcb_select?).returns(true)
2644
- end
2872
+ def test_update_menu_attrib_yield_selected_without_body
2873
+ @fcb.stubs(:body).returns(nil)
2874
+ HashDelegator.expects(:initialize_fcb_names).with(@fcb)
2875
+ HashDelegator.update_menu_attrib_yield_selected(@fcb, [:some_message])
2876
+ end
2877
+ end
2645
2878
 
2646
- def test_yield_to_block_if_applicable_with_correct_conditions
2647
- block_called = false
2648
- Filter.yield_to_block_if_applicable(@fcb, [:blocks]) do |type, fcb|
2649
- block_called = true
2650
- assert_equal :blocks, type
2651
- assert_equal @fcb, fcb
2652
- end
2653
- assert block_called
2654
- end
2879
+ class TestHashDelegatorWaitForUserSelectedBlock < Minitest::Test
2880
+ def setup
2881
+ @hd = HashDelegator.new
2882
+ HashDelegator.stubs(:error_handler)
2883
+ end
2655
2884
 
2656
- def test_yield_to_block_if_applicable_without_block
2657
- result = Filter.yield_to_block_if_applicable(@fcb, [:blocks])
2658
- assert_nil result
2885
+ def test_wait_for_user_selected_block_with_back_state
2886
+ mock_block_state = Struct.new(:state, :block).new(MenuState::BACK,
2887
+ { oname: 'back_block' })
2888
+ @hd.stubs(:wait_for_user_selection).returns(mock_block_state)
2889
+
2890
+ result = @hd.wait_for_user_selected_block([], ['Block 1', 'Block 2'],
2891
+ nil)
2892
+
2893
+ assert_equal 'back_block',
2894
+ @hd.instance_variable_get(:@delegate_object)[:block_name]
2895
+ assert @hd.instance_variable_get(:@menu_user_clicked_back_link)
2896
+ assert_equal mock_block_state, result
2897
+ end
2898
+
2899
+ def test_wait_for_user_selected_block_with_continue_state
2900
+ mock_block_state = Struct.new(:state, :block).new(
2901
+ MenuState::CONTINUE, { oname: 'continue_block' }
2902
+ )
2903
+ @hd.stubs(:wait_for_user_selection).returns(mock_block_state)
2904
+
2905
+ result = @hd.wait_for_user_selected_block([], ['Block 1', 'Block 2'],
2906
+ nil)
2907
+
2908
+ assert_equal 'continue_block',
2909
+ @hd.instance_variable_get(:@delegate_object)[:block_name]
2910
+ refute @hd.instance_variable_get(:@menu_user_clicked_back_link)
2911
+ assert_equal mock_block_state, result
2912
+ end
2913
+ end
2914
+
2915
+ class TestHashDelegatorYieldToBlock < Minitest::Test
2916
+ def setup
2917
+ @hd = HashDelegator.new
2918
+ @fcb = mock('Fcb')
2919
+ MarkdownExec::Filter.stubs(:fcb_select?).returns(true)
2920
+ end
2921
+
2922
+ def test_yield_to_block_if_applicable_with_correct_conditions
2923
+ block_called = false
2924
+ Filter.yield_to_block_if_applicable(@fcb, [:blocks]) do |type, fcb|
2925
+ block_called = true
2926
+ assert_equal :blocks, type
2927
+ assert_equal @fcb, fcb
2659
2928
  end
2929
+ assert block_called
2930
+ end
2660
2931
 
2661
- def test_yield_to_block_if_applicable_with_incorrect_conditions
2662
- block_called = false
2663
- MarkdownExec::Filter.stubs(:fcb_select?).returns(false)
2664
- Filter.yield_to_block_if_applicable(@fcb, [:non_blocks]) do |_|
2665
- block_called = true
2666
- end
2667
- refute block_called
2932
+ def test_yield_to_block_if_applicable_without_block
2933
+ result = Filter.yield_to_block_if_applicable(@fcb, [:blocks])
2934
+ assert_nil result
2935
+ end
2936
+
2937
+ def test_yield_to_block_if_applicable_with_incorrect_conditions
2938
+ block_called = false
2939
+ MarkdownExec::Filter.stubs(:fcb_select?).returns(false)
2940
+ Filter.yield_to_block_if_applicable(@fcb, [:non_blocks]) do |_|
2941
+ block_called = true
2668
2942
  end
2943
+ refute block_called
2669
2944
  end
2670
- end # module MarkdownExec
2671
- end
2945
+ end
2946
+ end # module MarkdownExec