markdown_exec 1.8.6 → 1.8.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -37,6 +37,273 @@ class String
37
37
  end
38
38
  end
39
39
 
40
+ module HashDelegatorSelf
41
+ # def add_back_option(menu_blocks)
42
+ # append_chrome_block(menu_blocks, MenuState::BACK)
43
+ # end
44
+
45
+ # Applies an ANSI color method to a string using a specified color key.
46
+ # The method retrieves the color method from the provided hash. If the color key
47
+ # is not present in the hash, it uses a default color method.
48
+ # @param string [String] The string to be colored.
49
+ # @param color_methods [Hash] A hash where keys are color names (String/Symbol) and values are color methods.
50
+ # @param color_key [String, Symbol] The key representing the desired color method in the color_methods hash.
51
+ # @param default_method [String] (optional) Default color method to use if color_key is not found in color_methods. Defaults to 'plain'.
52
+ # @return [String] The colored string.
53
+ def apply_color_from_hash(string, color_methods, color_key, default_method: 'plain')
54
+ color_method = color_methods.fetch(color_key, default_method).to_sym
55
+ string.to_s.send(color_method)
56
+ end
57
+
58
+ # # Enhanced `apply_color_from_hash` method to support dynamic color transformations
59
+ # # @param string [String] The string to be colored.
60
+ # # @param color_transformations [Hash] A hash mapping color names to lambdas that apply color transformations.
61
+ # # @param color_key [String, Symbol] The key representing the desired color transformation in the color_transformations hash.
62
+ # # @param default_transformation [Proc] Default color transformation to use if color_key is not found in color_transformations.
63
+ # # @return [String] The colored string.
64
+ # def apply_color_from_hash(string, color_transformations, color_key, default_transformation: ->(str) { str })
65
+ # transformation = color_transformations.fetch(color_key.to_sym, default_transformation)
66
+ # transformation.call(string)
67
+ # end
68
+ # color_transformations = {
69
+ # red: ->(str) { "\e[31m#{str}\e[0m" }, # ANSI color code for red
70
+ # green: ->(str) { "\e[32m#{str}\e[0m" }, # ANSI color code for green
71
+ # # Add more color transformations as needed
72
+ # }
73
+ # string = "Hello, World!"
74
+ # colored_string = apply_color_from_hash(string, color_transformations, :red)
75
+ # puts colored_string # This will print the string in red
76
+
77
+ # Searches for the first element in a collection where the specified key matches a given value.
78
+ # This method is particularly useful for finding a specific hash-like object within an enumerable collection.
79
+ # If no match is found, it returns a specified default value.
80
+ #
81
+ # @param blocks [Enumerable] The collection of hash-like objects to search.
82
+ # @param key [Object] The key to search for in each element of the collection.
83
+ # @param value [Object] The value to match against each element's corresponding key value.
84
+ # @param default [Object, nil] The default value to return if no match is found (optional).
85
+ # @return [Object, nil] The first matching element or the default value if no match is found.
86
+ def block_find(blocks, key, value, default = nil)
87
+ blocks.find { |item| item[key] == value } || default
88
+ end
89
+
90
+ def code_merge(*bodies)
91
+ merge_lists(*bodies)
92
+ end
93
+
94
+ def count_matches_in_lines(lines, regex)
95
+ lines.count { |line| line.to_s.match(regex) }
96
+ end
97
+
98
+ def create_directory_for_file(file_path)
99
+ FileUtils.mkdir_p(File.dirname(file_path))
100
+ end
101
+
102
+ # Creates a file at the specified path, writes the given content to it,
103
+ # and sets file permissions if required. Handles any errors encountered during the process.
104
+ #
105
+ # @param file_path [String] The path where the file will be created.
106
+ # @param content [String] The content to write into the file.
107
+ # @param chmod_value [Integer] The file permission value to set; skips if zero.
108
+ def create_file_and_write_string_with_permissions(file_path, content,
109
+ chmod_value)
110
+ create_directory_for_file(file_path)
111
+ File.write(file_path, content)
112
+ set_file_permissions(file_path, chmod_value) unless chmod_value.zero?
113
+ rescue StandardError
114
+ error_handler('create_file_and_write_string_with_permissions')
115
+ end
116
+
117
+ # def create_temp_file
118
+ # Dir::Tmpname.create(self.class.to_s) { |path| path }
119
+ # end
120
+
121
+ # Updates the title of an FCB object from its body content if the title is nil or empty.
122
+ def default_block_title_from_body(fcb)
123
+ return unless fcb.title.nil? || fcb.title.empty?
124
+
125
+ fcb.derive_title_from_body
126
+ end
127
+
128
+ # delete the current line if it is empty and the previous is also empty
129
+ def delete_consecutive_blank_lines!(blocks_menu)
130
+ blocks_menu.process_and_conditionally_delete! do |prev_item, current_item, _next_item|
131
+ prev_item&.fetch(:chrome, nil) && !prev_item&.fetch(:oname).present? &&
132
+ current_item&.fetch(:chrome, nil) && !current_item&.fetch(:oname).present?
133
+ end
134
+ end
135
+
136
+ # # Deletes a temporary file specified by an environment variable.
137
+ # # Checks if the file exists before attempting to delete it and clears the environment variable afterward.
138
+ # # Any errors encountered during deletion are handled gracefully.
139
+ # def delete_required_temp_file(temp_blocks_file_path)
140
+ # return if temp_blocks_file_path.nil? || temp_blocks_file_path.empty?
141
+
142
+ # HashDelegator.remove_file_without_standard_errors(temp_blocks_file_path)
143
+ # end
144
+
145
+ def error_handler(name = '', opts = {})
146
+ Exceptions.error_handler(
147
+ "HashDelegator.#{name} -- #{$!}",
148
+ opts
149
+ )
150
+ end
151
+
152
+ # # DebugHelper.d ["HDmm method_name: #{method_name}", "#{first_n_caller_items 1}"]
153
+ # def first_n_caller_items(n)
154
+ # call_stack = caller
155
+ # base_path = File.realpath('.')
156
+
157
+ # # Modify the call stack to remove the base path and keep only the first n items
158
+ # call_stack.take(n + 1)[1..].map do |line|
159
+ # " . #{line.sub(/^#{Regexp.escape(base_path)}\//, '')}"
160
+ # end.join("\n")
161
+ # end
162
+
163
+ # Formats and returns the execution streams (like stdin, stdout, stderr) for a given key.
164
+ # It concatenates the array of strings found under the specified key in the run_state's files.
165
+ #
166
+ # @param key [Symbol] The key corresponding to the desired execution stream.
167
+ # @return [String] A concatenated string of the execution stream's contents.
168
+ def format_execution_streams(key, files = {})
169
+ (files || {}).fetch(key, []).join
170
+ end
171
+
172
+ # Indents all lines in a given string with a specified indentation string.
173
+ # @param body [String] A multi-line string to be indented.
174
+ # @param indent [String] The string used for indentation (default is an empty string).
175
+ # @return [String] A single string with each line indented as specified.
176
+ def indent_all_lines(body, indent = nil)
177
+ return body unless indent&.non_empty?
178
+
179
+ body.lines.map { |line| indent + line.chomp }.join("\n")
180
+ end
181
+
182
+ def initialize_fcb_names(fcb)
183
+ fcb.oname = fcb.dname = fcb.title || ''
184
+ end
185
+
186
+ def merge_lists(*args)
187
+ # Filters out nil values, flattens the arrays, and ensures an empty list is returned if no valid lists are provided
188
+ merged = args.compact.flatten
189
+ merged.empty? ? [] : merged
190
+ end
191
+
192
+ def next_link_state(block_name_from_cli, was_using_cli, block_state)
193
+ # &bsp 'next_link_state', block_name_from_cli, was_using_cli, block_state
194
+ # Set block_name based on block_name_from_cli
195
+ block_name = block_name_from_cli ? @cli_block_name : nil
196
+ # &bsp 'block_name:', block_name
197
+
198
+ # Determine the state of breaker based on was_using_cli and the block type
199
+ breaker = !block_name && !block_name_from_cli && was_using_cli && block_state.block[:shell] == BlockType::BASH
200
+ # &bsp 'breaker:', breaker
201
+
202
+ # Reset block_name_from_cli if the conditions are not met
203
+ block_name_from_cli ||= false
204
+ # &bsp 'block_name_from_cli:', block_name_from_cli
205
+
206
+ [block_name, block_name_from_cli, breaker]
207
+ end
208
+
209
+ def parse_yaml_data_from_body(body)
210
+ body.any? ? YAML.load(body.join("\n")) : {}
211
+ end
212
+
213
+ # Reads required code blocks from a temporary file specified by an environment variable.
214
+ # @return [Array<String>] Lines read from the temporary file, or an empty array if file is not found or path is empty.
215
+ def read_required_blocks_from_temp_file(temp_blocks_file_path)
216
+ return [] if temp_blocks_file_path.to_s.empty?
217
+
218
+ if File.exist?(temp_blocks_file_path)
219
+ File.readlines(
220
+ temp_blocks_file_path, chomp: true
221
+ )
222
+ else
223
+ []
224
+ end
225
+ end
226
+
227
+ def remove_file_without_standard_errors(path)
228
+ FileUtils.rm_f(path)
229
+ end
230
+
231
+ # Evaluates the given string as Ruby code and rescues any StandardErrors.
232
+ # If an error occurs, it calls the error_handler method with 'safeval'.
233
+ # @param str [String] The string to be evaluated.
234
+ # @return [Object] The result of evaluating the string.
235
+ def safeval(str)
236
+ eval(str)
237
+ rescue StandardError # catches NameError, StandardError
238
+ error_handler('safeval')
239
+ end
240
+
241
+ def set_file_permissions(file_path, chmod_value)
242
+ File.chmod(chmod_value, file_path)
243
+ end
244
+
245
+ # Creates a TTY prompt with custom settings. Specifically, it disables the default 'cross' symbol and
246
+ # defines a lambda function to handle interrupts.
247
+ # @return [TTY::Prompt] A new TTY::Prompt instance with specified configurations.
248
+ def tty_prompt_without_disabled_symbol
249
+ TTY::Prompt.new(
250
+ interrupt: lambda {
251
+ puts
252
+ raise TTY::Reader::InputInterrupt
253
+ },
254
+ symbols: { cross: ' ' }
255
+ )
256
+ end
257
+
258
+ # Updates the attributes of the given fcb object and conditionally yields to a block.
259
+ # It initializes fcb names and sets the default block title from fcb's body.
260
+ # If the fcb has a body and meets certain conditions, it yields to the given block.
261
+ #
262
+ # @param fcb [Object] The fcb object whose attributes are to be updated.
263
+ # @param selected_messages [Array<Symbol>] A list of message types to determine if yielding is applicable.
264
+ # @param block [Block] An optional block to yield to if conditions are met.
265
+ def update_menu_attrib_yield_selected(fcb, selected_messages, configuration = {}, &block)
266
+ initialize_fcb_names(fcb)
267
+ return unless fcb.body
268
+
269
+ default_block_title_from_body(fcb)
270
+ MarkdownExec::Filter.yield_to_block_if_applicable(fcb, selected_messages, configuration,
271
+ &block)
272
+ end
273
+
274
+ # Writes the provided code blocks to a file.
275
+ # @param code_blocks [String] Code blocks to write into the file.
276
+ def write_code_to_file(content, path)
277
+ File.write(path, content)
278
+ end
279
+
280
+ def write_execution_output_to_file(files, filespec)
281
+ FileUtils.mkdir_p File.dirname(filespec)
282
+
283
+ File.write(
284
+ filespec,
285
+ ["-STDOUT-\n",
286
+ format_execution_streams(ExecutionStreams::StdOut, files),
287
+ "-STDERR-\n",
288
+ format_execution_streams(ExecutionStreams::StdErr, files),
289
+ "-STDIN-\n",
290
+ format_execution_streams(ExecutionStreams::StdIn, files),
291
+ "\n"].join
292
+ )
293
+ end
294
+
295
+ # Yields a line as a new block if the selected message type includes :line.
296
+ # @param [String] line The line to be processed.
297
+ # @param [Array<Symbol>] selected_messages A list of message types to check.
298
+ # @param [Proc] block The block to be called with the line data.
299
+ def yield_line_if_selected(line, selected_messages, &block)
300
+ return unless block && selected_messages.include?(:line)
301
+
302
+ block.call(:line, MarkdownExec::FCB.new(body: [line]))
303
+ end
304
+ end
305
+ ### require_relative 'hash_delegator_self'
306
+
40
307
  # This module provides methods for compacting and converting data structures.
41
308
  module CompactionHelpers
42
309
  # Converts an array of key-value pairs into a hash, applying compaction to the values.
@@ -106,11 +373,12 @@ module MarkdownExec
106
373
  class HashDelegator
107
374
  attr_accessor :most_recent_loaded_filename, :pass_args, :run_state
108
375
 
376
+ extend HashDelegatorSelf
109
377
  include CompactionHelpers
110
378
 
111
379
  def initialize(delegate_object = {})
112
380
  @delegate_object = delegate_object
113
- @prompt = tty_prompt_without_disabled_symbol
381
+ @prompt = HashDelegator.tty_prompt_without_disabled_symbol
114
382
 
115
383
  @most_recent_loaded_filename = nil
116
384
  @pass_args = []
@@ -138,11 +406,20 @@ module MarkdownExec
138
406
  # along with initial and final dividers, based on the delegate object's configuration.
139
407
  #
140
408
  # @param menu_blocks [Array] The array of menu block elements to be modified.
141
- def add_menu_chrome_blocks!(menu_blocks)
409
+ def add_menu_chrome_blocks!(menu_blocks, link_state)
142
410
  return unless @delegate_object[:menu_link_format].present?
143
411
 
412
+ if @delegate_object[:menu_with_inherited_lines]
413
+ add_inherited_lines(menu_blocks,
414
+ link_state)
415
+ end
416
+
417
+ # back before exit
144
418
  add_back_option(menu_blocks) if should_add_back_option?
419
+
420
+ # exit after other options
145
421
  add_exit_option(menu_blocks) if @delegate_object[:menu_with_exit]
422
+
146
423
  add_dividers(menu_blocks)
147
424
  end
148
425
 
@@ -152,13 +429,17 @@ module MarkdownExec
152
429
  append_chrome_block(menu_blocks, MenuState::BACK)
153
430
  end
154
431
 
432
+ def add_dividers(menu_blocks)
433
+ append_divider(menu_blocks, :initial)
434
+ append_divider(menu_blocks, :final)
435
+ end
436
+
155
437
  def add_exit_option(menu_blocks)
156
438
  append_chrome_block(menu_blocks, MenuState::EXIT)
157
439
  end
158
440
 
159
- def add_dividers(menu_blocks)
160
- append_divider(menu_blocks, :initial)
161
- append_divider(menu_blocks, :final)
441
+ def add_inherited_lines(menu_blocks, link_state)
442
+ append_inherited_lines(menu_blocks, link_state)
162
443
  end
163
444
 
164
445
  public
@@ -179,7 +460,7 @@ module MarkdownExec
179
460
  end
180
461
 
181
462
  formatted_name = format(@delegate_object[:menu_link_format],
182
- safeval(option_name))
463
+ HashDelegator.safeval(option_name))
183
464
  chrome_block = FCB.new(
184
465
  chrome: true,
185
466
  dname: HashDelegator.new(@delegate_object).string_send_color(
@@ -195,6 +476,39 @@ module MarkdownExec
195
476
  end
196
477
  end
197
478
 
479
+ # Appends a formatted divider to the specified position in a menu block array.
480
+ # The method checks for the presence of formatting options before appending.
481
+ #
482
+ # @param menu_blocks [Array] The array of menu block elements.
483
+ # @param position [Symbol] The position to insert the divider (:initial or :final).
484
+ def append_inherited_lines(menu_blocks, link_state, position: top)
485
+ return unless link_state.inherited_lines.present?
486
+
487
+ insert_at_top = @delegate_object[:menu_inherited_lines_at_top]
488
+ chrome_blocks = link_state.inherited_lines.map do |line|
489
+ formatted = format(@delegate_object[:menu_inherited_lines_format],
490
+ { line: line })
491
+ FCB.new(
492
+ chrome: true,
493
+ disabled: '',
494
+ dname: HashDelegator.new(@delegate_object).string_send_color(
495
+ formatted, :menu_inherited_lines_color
496
+ ),
497
+ oname: formatted
498
+ )
499
+ end
500
+
501
+ if insert_at_top
502
+ # Prepend an array of elements to the beginning
503
+ menu_blocks.unshift(*chrome_blocks)
504
+ else
505
+ # Append an array of elements to the end
506
+ menu_blocks.concat(chrome_blocks)
507
+ end
508
+ rescue StandardError
509
+ HashDelegator.error_handler('append_inherited_lines')
510
+ end
511
+
198
512
  # Appends a formatted divider to the specified position in a menu block array.
199
513
  # The method checks for the presence of formatting options before appending.
200
514
  #
@@ -224,19 +538,6 @@ module MarkdownExec
224
538
 
225
539
  # private
226
540
 
227
- # Searches for the first element in a collection where the specified key matches a given value.
228
- # This method is particularly useful for finding a specific hash-like object within an enumerable collection.
229
- # If no match is found, it returns a specified default value.
230
- #
231
- # @param blocks [Enumerable] The collection of hash-like objects to search.
232
- # @param key [Object] The key to search for in each element of the collection.
233
- # @param value [Object] The value to match against each element's corresponding key value.
234
- # @param default [Object, nil] The default value to return if no match is found (optional).
235
- # @return [Object, nil] The first matching element or the default value if no match is found.
236
- def block_find(blocks, key, value, default = nil)
237
- blocks.find { |item| item[key] == value } || default
238
- end
239
-
240
541
  # Iterates through nested files to collect various types of blocks, including dividers, tasks, and others.
241
542
  # The method categorizes blocks based on their type and processes them accordingly.
242
543
  #
@@ -246,9 +547,10 @@ module MarkdownExec
246
547
  iter_blocks_from_nested_files do |btype, fcb|
247
548
  process_block_based_on_type(blocks, btype, fcb)
248
549
  end
550
+ # &bc 'blocks.count:', blocks.count
249
551
  blocks
250
552
  rescue StandardError
251
- error_handler('blocks_from_nested_files')
553
+ HashDelegator.error_handler('blocks_from_nested_files')
252
554
  end
253
555
 
254
556
  # private
@@ -273,15 +575,6 @@ module MarkdownExec
273
575
  true
274
576
  end
275
577
 
276
- def code_join(*bodies)
277
- bc = bodies&.compact
278
- bc.count.positive? ? bc.join("\n") : nil
279
- end
280
-
281
- def code_merge(*bodies)
282
- merge_lists(*bodies)
283
- end
284
-
285
578
  # Collects required code lines based on the selected block and the delegate object's configuration.
286
579
  # If the block type is VARS, it also sets environment variables based on the block's content.
287
580
  #
@@ -312,7 +605,7 @@ module MarkdownExec
312
605
  highlight: [@delegate_object[:block_name]])
313
606
  end
314
607
 
315
- code_merge link_state&.inherited_lines, required[:code]
608
+ HashDelegator.code_merge(link_state&.inherited_lines, required[:code])
316
609
  end
317
610
 
318
611
  def command_execute(command, args: [])
@@ -363,17 +656,17 @@ module MarkdownExec
363
656
  if @delegate_object[:block_name].present?
364
657
  block = all_blocks.find do |item|
365
658
  item[:oname] == @delegate_object[:block_name]
366
- end
659
+ end&.merge(block_name_from_ui: false)
367
660
  else
368
661
  block_state = wait_for_user_selected_block(all_blocks, menu_blocks,
369
662
  default)
370
- block = block_state.block
663
+ block = block_state.block&.merge(block_name_from_ui: true)
371
664
  state = block_state.state
372
665
  end
373
666
 
374
667
  SelectedBlockMenuState.new(block, state)
375
668
  rescue StandardError
376
- error_handler('load_cli_or_user_selected_block')
669
+ HashDelegator.error_handler('load_cli_or_user_selected_block')
377
670
  end
378
671
 
379
672
  # This method is responsible for handling the execution of generic blocks in a markdown document.
@@ -412,17 +705,9 @@ module MarkdownExec
412
705
  def count_blocks_in_filename
413
706
  regex = Regexp.new(@delegate_object[:fenced_start_and_end_regex])
414
707
  lines = cfile.readlines(@delegate_object[:filename])
415
- count_matches_in_lines(lines, regex) / 2
416
- end
417
-
418
- # private
419
-
420
- def count_matches_in_lines(lines, regex)
421
- lines.count { |line| line.to_s.match(regex) }
708
+ HashDelegator.count_matches_in_lines(lines, regex) / 2
422
709
  end
423
710
 
424
- # private
425
-
426
711
  ##
427
712
  # Creates and adds a formatted block to the blocks array based on the provided match and format options.
428
713
  # @param blocks [Array] The array of blocks to add the new block to.
@@ -449,12 +734,13 @@ module MarkdownExec
449
734
  # @param use_chrome [Boolean] Indicates if the chrome styling should be applied.
450
735
  def create_and_add_chrome_blocks(blocks, fcb)
451
736
  match_criteria = [
452
- { match: :menu_task_match, format: :menu_task_format,
453
- color: :menu_task_color },
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 },
454
740
  { match: :menu_divider_match, format: :menu_divider_format,
455
741
  color: :menu_divider_color },
456
- { match: :menu_note_match, format: :menu_note_format,
457
- color: :menu_note_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 }
458
744
  ]
459
745
  match_criteria.each do |criteria|
460
746
  unless @delegate_object[criteria[:match]].present? &&
@@ -468,31 +754,10 @@ module MarkdownExec
468
754
  end
469
755
  end
470
756
 
471
- # Creates a file at the specified path, writes the given content to it,
472
- # and sets file permissions if required. Handles any errors encountered during the process.
473
- #
474
- # @param file_path [String] The path where the file will be created.
475
- # @param content [String] The content to write into the file.
476
- # @param chmod_value [Integer] The file permission value to set; skips if zero.
477
- def create_file_and_write_string_with_permissions(file_path, content,
478
- chmod_value)
479
- create_directory_for_file(file_path)
480
- File.write(file_path, content)
481
- set_file_permissions(file_path, chmod_value) unless chmod_value.zero?
482
- rescue StandardError
483
- error_handler('create_file_and_write_string_with_permissions')
484
- end
485
-
486
- # private
487
-
488
- def create_directory_for_file(file_path)
489
- FileUtils.mkdir_p(File.dirname(file_path))
490
- end
491
-
492
757
  def create_divider(position)
493
758
  divider_key = position == :initial ? :menu_initial_divider : :menu_final_divider
494
759
  oname = format(@delegate_object[:menu_divider_format],
495
- safeval(@delegate_object[divider_key]))
760
+ HashDelegator.safeval(@delegate_object[divider_key]))
496
761
 
497
762
  FCB.new(
498
763
  chrome: true,
@@ -502,38 +767,6 @@ module MarkdownExec
502
767
  )
503
768
  end
504
769
 
505
- # private
506
-
507
- def create_temp_file
508
- Dir::Tmpname.create(self.class.to_s) { |path| path }
509
- end
510
-
511
- # Updates the title of an FCB object from its body content if the title is nil or empty.
512
- def default_block_title_from_body(fcb)
513
- return unless fcb.title.nil? || fcb.title.empty?
514
-
515
- fcb.derive_title_from_body
516
- end
517
-
518
- # delete the current line if it is empty and the previous is also empty
519
- def delete_consecutive_blank_lines!(blocks_menu)
520
- blocks_menu.process_and_conditionally_delete! do |prev_item, current_item, _next_item|
521
- prev_item&.fetch(:chrome, nil) && !prev_item&.fetch(:oname).present? &&
522
- current_item&.fetch(:chrome, nil) && !current_item&.fetch(:oname).present?
523
- end
524
- end
525
-
526
- # Deletes a temporary file specified by an environment variable.
527
- # Checks if the file exists before attempting to delete it and clears the environment variable afterward.
528
- # Any errors encountered during deletion are handled gracefully.
529
- def delete_required_temp_file(temp_blocks_file_path)
530
- return if temp_blocks_file_path.nil? || temp_blocks_file_path.empty?
531
-
532
- safely_remove_file(temp_blocks_file_path)
533
- rescue StandardError
534
- error_handler('delete_required_temp_file')
535
- end
536
-
537
770
  # Determines the state of a selected block in the menu based on the selected option.
538
771
  # It categorizes the selected option into either EXIT, BACK, or CONTINUE state.
539
772
  #
@@ -570,15 +803,6 @@ module MarkdownExec
570
803
  @delegate_object[:menu_divider_format].present? && @delegate_object[divider_key].present?
571
804
  end
572
805
 
573
- def error_handler(name = '', opts = {})
574
- Exceptions.error_handler(
575
- "HashDelegator.#{name} -- #{$!}",
576
- opts
577
- )
578
- end
579
-
580
- # public
581
-
582
806
  # Executes a block of code that has been approved for execution.
583
807
  # It sets the script block name, writes command files if required, and handles the execution
584
808
  # including output formatting and summarization.
@@ -586,8 +810,8 @@ module MarkdownExec
586
810
  # @param required_lines [Array<String>] The lines of code to be executed.
587
811
  # @param selected [FCB] The selected functional code block object.
588
812
  def execute_required_lines(required_lines = [])
589
- # set_script_block_name(selected)
590
- save_executed_script_if_specified(required_lines)
813
+ # @run_state.script_block_name = selected[:oname]
814
+ write_command_file(required_lines) if @delegate_object[:save_executed_script]
591
815
  format_and_execute_command(required_lines)
592
816
  post_execution_process
593
817
  end
@@ -636,17 +860,6 @@ module MarkdownExec
636
860
  string_send_color(data_string, color_sym)
637
861
  end
638
862
 
639
- # DebugHelper.d ["HDmm method_name: #{method_name}", "#{first_n_caller_items 1}"]
640
- def first_n_caller_items(n)
641
- call_stack = caller
642
- base_path = File.realpath('.')
643
-
644
- # Modify the call stack to remove the base path and keep only the first n items
645
- call_stack.take(n + 1)[1..].map do |line|
646
- " . #{line.sub(/^#{Regexp.escape(base_path)}\//, '')}"
647
- end.join("\n")
648
- end
649
-
650
863
  def format_and_execute_command(lines)
651
864
  formatted_command = lines.flatten.join("\n")
652
865
  @fout.fout fetch_color(data_sym: :script_execution_head,
@@ -672,16 +885,6 @@ module MarkdownExec
672
885
  string_send_color(formatted_string, color_sym)
673
886
  end
674
887
 
675
- # Formats and returns the execution streams (like stdin, stdout, stderr) for a given key.
676
- # It concatenates the array of strings found under the specified key in the run_state's files.
677
- #
678
- # @param key [Symbol] The key corresponding to the desired execution stream.
679
- # @return [String] A concatenated string of the execution stream's contents.
680
- def format_execution_streams(key)
681
- files = @run_state.files || {}
682
- files.fetch(key, []).join
683
- end
684
-
685
888
  # Processes a block to generate its summary, modifying its attributes based on various matching criteria.
686
889
  # It handles special formatting for bash blocks, extracting and setting properties like call, stdin, stdout, and dname.
687
890
  #
@@ -711,7 +914,7 @@ module MarkdownExec
711
914
  # It sets the block name and determines if the user clicked the back link in the menu.
712
915
  #
713
916
  # @param block_state [Object] An object representing the state of a block in the menu.
714
- def handle_block_state(block_state)
917
+ def handle_back_or_continue(block_state)
715
918
  return if block_state.nil?
716
919
  unless [MenuState::BACK,
717
920
  MenuState::CONTINUE].include?(block_state.state)
@@ -744,16 +947,6 @@ module MarkdownExec
744
947
  end
745
948
  end
746
949
 
747
- # Indents all lines in a given string with a specified indentation string.
748
- # @param body [String] A multi-line string to be indented.
749
- # @param indent [String] The string used for indentation (default is an empty string).
750
- # @return [String] A single string with each line indented as specified.
751
- def indent_all_lines(body, indent = nil)
752
- return body unless indent&.non_empty?
753
-
754
- body.lines.map { |line| indent + line.chomp }.join("\n")
755
- end
756
-
757
950
  # Initializes variables for regex and other states
758
951
  def initial_state
759
952
  {
@@ -784,11 +977,8 @@ module MarkdownExec
784
977
  File.join @delegate_object[:saved_stdout_folder],
785
978
  @delegate_object[:logged_stdout_filename]
786
979
  @logged_stdout_filespec = @delegate_object[:logged_stdout_filespec]
787
- write_execution_output_to_file
788
- end
789
-
790
- def initialize_fcb_names(fcb)
791
- fcb.oname = fcb.dname = fcb.title || ''
980
+ HashDelegator.write_execution_output_to_file(@run_state.files,
981
+ @delegate_object[:logged_stdout_filespec])
792
982
  end
793
983
 
794
984
  # Iterates through blocks in a file, applying the provided block to each line.
@@ -845,7 +1035,7 @@ module MarkdownExec
845
1035
  return
846
1036
  end
847
1037
 
848
- block = block_find(all_blocks, :oname, block_name)
1038
+ block = HashDelegator.block_find(all_blocks, :oname, block_name)
849
1039
  return unless block
850
1040
 
851
1041
  options_state = read_show_options_and_trigger_reuse(block)
@@ -866,7 +1056,7 @@ module MarkdownExec
866
1056
 
867
1057
  ## Handles the file loading and returns the blocks in the file and MDoc instance
868
1058
  #
869
- def mdoc_menu_and_blocks_from_nested_files
1059
+ def mdoc_menu_and_blocks_from_nested_files(link_state)
870
1060
  all_blocks, mdoc = mdoc_and_blocks_from_nested_files
871
1061
 
872
1062
  # recreate menu with new options
@@ -874,8 +1064,9 @@ module MarkdownExec
874
1064
  all_blocks, mdoc = mdoc_and_blocks_from_nested_files if load_auto_blocks(all_blocks)
875
1065
 
876
1066
  menu_blocks = mdoc.fcbs_per_options(@delegate_object)
877
- add_menu_chrome_blocks!(menu_blocks)
878
- delete_consecutive_blank_lines!(menu_blocks) if true ### compress empty lines
1067
+ add_menu_chrome_blocks!(menu_blocks, link_state)
1068
+ ### compress empty lines
1069
+ HashDelegator.delete_consecutive_blank_lines!(menu_blocks) if true
879
1070
  [all_blocks, menu_blocks, mdoc]
880
1071
  end
881
1072
 
@@ -894,7 +1085,7 @@ module MarkdownExec
894
1085
  # @param option_symbol [Symbol] The symbol key for the menu option in the delegate object.
895
1086
  # @return [String] The formatted or original value of the menu option.
896
1087
  def menu_chrome_formatted_option(option_symbol = :menu_option_back_name)
897
- option_value = safeval(@delegate_object.fetch(option_symbol, ''))
1088
+ option_value = HashDelegator.safeval(@delegate_object.fetch(option_symbol, ''))
898
1089
 
899
1090
  if @delegate_object[:menu_chrome_format]
900
1091
  format(@delegate_object[:menu_chrome_format], option_value)
@@ -903,12 +1094,6 @@ module MarkdownExec
903
1094
  end
904
1095
  end
905
1096
 
906
- def merge_lists(*args)
907
- # Filters out nil values, flattens the arrays, and ensures an empty list is returned if no valid lists are provided
908
- merged = args.compact.flatten
909
- merged.empty? ? [] : merged
910
- end
911
-
912
1097
  # If a method is missing, treat it as a key for the @delegate_object.
913
1098
  def method_missing(method_name, *args, &block)
914
1099
  if @delegate_object.respond_to?(method_name)
@@ -921,17 +1106,13 @@ module MarkdownExec
921
1106
  end
922
1107
  end
923
1108
 
924
- def shift_cli_argument!
925
- return false unless @menu_base_options[:input_cli_rest].present?
1109
+ def shift_cli_argument
1110
+ return true unless @menu_base_options[:input_cli_rest].present?
926
1111
 
927
1112
  @cli_block_name = @menu_base_options[:input_cli_rest].shift
928
- # @delegate_object[:input_cli_rest].shift
929
- # p [__LINE__, @cli_block_name, @menu_base_options[:input_cli_rest]]
930
- true
1113
+ false
931
1114
  end
932
1115
 
933
- # private
934
-
935
1116
  def output_color_formatted(data_sym, color_sym)
936
1117
  formatted_string = string_send_color(@delegate_object[data_sym],
937
1118
  color_sym)
@@ -984,16 +1165,10 @@ module MarkdownExec
984
1165
  ), level: level
985
1166
  end
986
1167
 
987
- # private
988
-
989
- def parse_yaml_data_from_body(body)
990
- body.any? ? YAML.load(body.join("\n")) : {}
991
- end
992
-
993
1168
  def pop_add_current_code_to_head_and_trigger_load(_link_state, block_names, code_lines,
994
1169
  dependencies)
995
1170
  pop = @link_history.pop # updatable
996
- next_link_state = LinkState.new(
1171
+ next_state = LinkState.new(
997
1172
  block_name: pop.block_name,
998
1173
  document_filename: pop.document_filename,
999
1174
  inherited_block_names:
@@ -1001,12 +1176,12 @@ module MarkdownExec
1001
1176
  inherited_dependencies:
1002
1177
  dependencies.merge(pop.inherited_dependencies || {}), ### merge, not replace, key data
1003
1178
  inherited_lines:
1004
- code_merge(pop.inherited_lines, code_lines)
1179
+ HashDelegator.code_merge(pop.inherited_lines, code_lines)
1005
1180
  )
1006
- @link_history.push(next_link_state)
1181
+ @link_history.push(next_state)
1007
1182
 
1008
- next_link_state.block_name = nil
1009
- LoadFileLinkState.new(LoadFile::Load, next_link_state)
1183
+ next_state.block_name = nil
1184
+ LoadFileLinkState.new(LoadFile::Load, next_state)
1010
1185
  end
1011
1186
 
1012
1187
  # This method handles the back-link operation in the Markdown execution context.
@@ -1041,7 +1216,7 @@ module MarkdownExec
1041
1216
  %i[block_name_include_match block_name_wrapper_match])
1042
1217
 
1043
1218
  fcb.merge!(
1044
- name: indent_all_lines(fcb.dname, fcb.fetch(:indent, nil)),
1219
+ name: HashDelegator.indent_all_lines(fcb.dname, fcb.fetch(:indent, nil)),
1045
1220
  label: BlockLabel.make(
1046
1221
  body: fcb[:body],
1047
1222
  filename: @delegate_object[:filename],
@@ -1071,10 +1246,7 @@ module MarkdownExec
1071
1246
  when :filter
1072
1247
  %i[blocks line]
1073
1248
  when :line
1074
- unless @delegate_object[:no_chrome]
1075
- create_and_add_chrome_blocks(blocks,
1076
- fcb)
1077
- end
1249
+ create_and_add_chrome_blocks(blocks, fcb) unless @delegate_object[:no_chrome]
1078
1250
  end
1079
1251
  end
1080
1252
 
@@ -1148,7 +1320,7 @@ module MarkdownExec
1148
1320
  # @return [LoadFileLinkState] Object indicating the next action for file loading.
1149
1321
  def push_link_history_and_trigger_load(link_block_body, mdoc, selected,
1150
1322
  link_state = LinkState.new)
1151
- link_block_data = parse_yaml_data_from_body(link_block_body)
1323
+ link_block_data = HashDelegator.parse_yaml_data_from_body(link_block_body)
1152
1324
 
1153
1325
  # load key and values from link block into current environment
1154
1326
  #
@@ -1178,7 +1350,7 @@ module MarkdownExec
1178
1350
  # if an eval link block, evaluate code_lines and return its standard output
1179
1351
  #
1180
1352
  if link_block_data.fetch('eval', false)
1181
- all_code = code_merge(link_state&.inherited_lines, code_lines)
1353
+ all_code = HashDelegator.code_merge(link_state&.inherited_lines, code_lines)
1182
1354
  output = `#{all_code.join("\n")}`.split("\n")
1183
1355
  label_format_above = @delegate_object[:shell_code_label_format_above]
1184
1356
  label_format_below = @delegate_object[:shell_code_label_format_below]
@@ -1207,7 +1379,7 @@ module MarkdownExec
1207
1379
  curr_document_filename: @delegate_object[:filename],
1208
1380
  inherited_block_names: ((link_state&.inherited_block_names || []) + block_names).sort.uniq,
1209
1381
  inherited_dependencies: (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
1210
- inherited_lines: code_merge(link_state&.inherited_lines, code_lines),
1382
+ inherited_lines: HashDelegator.code_merge(link_state&.inherited_lines, code_lines),
1211
1383
  next_block_name: link_block_data['block'] || '',
1212
1384
  next_document_filename: next_document_filename,
1213
1385
  next_load_file: next_document_filename == @delegate_object[:filename] ? LoadFile::Reuse : LoadFile::Load
@@ -1215,20 +1387,6 @@ module MarkdownExec
1215
1387
  end
1216
1388
  end
1217
1389
 
1218
- # Reads required code blocks from a temporary file specified by an environment variable.
1219
- # @return [Array<String>] Lines read from the temporary file, or an empty array if file is not found or path is empty.
1220
- def read_required_blocks_from_temp_file(temp_blocks_file_path)
1221
- return [] if temp_blocks_file_path.to_s.empty?
1222
-
1223
- if File.exist?(temp_blocks_file_path)
1224
- File.readlines(
1225
- temp_blocks_file_path, chomp: true
1226
- )
1227
- else
1228
- []
1229
- end
1230
- end
1231
-
1232
1390
  def runtime_exception(exception_sym, name, items)
1233
1391
  if @delegate_object[exception_sym] != 0
1234
1392
  data = { name: name, detail: items.join(', ') }
@@ -1248,20 +1406,6 @@ module MarkdownExec
1248
1406
  exit @delegate_object[exception_sym]
1249
1407
  end
1250
1408
 
1251
- def safely_remove_file(path)
1252
- FileUtils.rm_f(path)
1253
- end
1254
-
1255
- # Evaluates the given string as Ruby code and rescues any StandardErrors.
1256
- # If an error occurs, it calls the error_handler method with 'safeval'.
1257
- # @param str [String] The string to be evaluated.
1258
- # @return [Object] The result of evaluating the string.
1259
- def safeval(str)
1260
- eval(str)
1261
- rescue StandardError
1262
- error_handler('safeval')
1263
- end
1264
-
1265
1409
  def save_to_file(required_lines)
1266
1410
  write_command_file(required_lines)
1267
1411
  @fout.fout "File saved: #{@run_state.saved_filespec}"
@@ -1275,11 +1419,17 @@ module MarkdownExec
1275
1419
  # @return [Nil] Returns nil if no code block is selected or an error occurs.
1276
1420
  def document_menu_loop
1277
1421
  @menu_base_options = @delegate_object
1278
- link_state, block_name_from_cli, now_using_cli = initialize_selection_states
1422
+ link_state = LinkState.new(
1423
+ block_name: @delegate_object[:block_name],
1424
+ document_filename: @delegate_object[:filename]
1425
+ )
1426
+ block_name_from_cli = link_state.block_name.present?
1427
+ @cli_block_name = link_state.block_name
1428
+ now_using_cli = block_name_from_cli
1279
1429
  menu_default_dname = nil
1280
1430
 
1281
1431
  loop do
1282
- # @bsp 'loop',block_name_from_cli,@cli_block_name
1432
+ # &bsp 'loop', block_name_from_cli, @cli_block_name
1283
1433
  block_name_from_cli, now_using_cli, blocks_in_file, menu_blocks, mdoc = \
1284
1434
  set_delobj_menu_loop_vars(block_name_from_cli, now_using_cli, link_state)
1285
1435
 
@@ -1287,8 +1437,11 @@ module MarkdownExec
1287
1437
  #
1288
1438
  block_state = load_cli_or_user_selected_block(blocks_in_file, menu_blocks,
1289
1439
  menu_default_dname)
1290
- if block_state.state == MenuState::EXIT
1291
- # @bsp 'MenuState::EXIT -> break'
1440
+ # &bsp 'block_name_from_cli:',block_name_from_cli
1441
+ if !block_state
1442
+ HashDelegator.error_handler('block_state missing', { abort: true })
1443
+ elsif block_state.state == MenuState::EXIT
1444
+ # &bsp 'load_cli_or_user_selected_block -> break'
1292
1445
  break
1293
1446
  end
1294
1447
 
@@ -1296,30 +1449,21 @@ module MarkdownExec
1296
1449
  link_state, menu_default_dname = exec_bash_next_state(block_state.block, mdoc,
1297
1450
  link_state)
1298
1451
  if prompt_user_exit(block_name_from_cli, block_state.block)
1299
- # @bsp 'prompt_user_exit -> break'
1452
+ # &bsp 'prompt_user_exit -> break'
1300
1453
  break
1301
1454
  end
1302
1455
 
1303
1456
  link_state.block_name, block_name_from_cli, cli_break = \
1304
- next_state_from_cli(now_using_cli, block_state)
1457
+ HashDelegator.next_link_state(!shift_cli_argument, now_using_cli, block_state)
1305
1458
 
1306
- if cli_break
1307
- # @bsp 'read_block_name_from_cli + next_link_state -> break'
1459
+ if !block_state.block[:block_name_from_ui] && cli_break
1460
+ # &bsp '!block_name_from_ui + cli_break -> break'
1308
1461
  break
1309
1462
  end
1310
1463
  end
1311
1464
  rescue StandardError
1312
- error_handler('document_menu_loop',
1313
- { abort: true })
1314
- end
1315
-
1316
- def next_state_from_cli(now_using_cli, block_state)
1317
- was_using_cli = now_using_cli
1318
- block_name_from_cli, = read_block_name_from_cli(now_using_cli)
1319
- block_name, block_name_from_cli, cli_break = \
1320
- next_link_state(block_name_from_cli, was_using_cli, block_state)
1321
-
1322
- [block_name, block_name_from_cli, cli_break]
1465
+ HashDelegator.error_handler('document_menu_loop',
1466
+ { abort: true })
1323
1467
  end
1324
1468
 
1325
1469
  def exec_bash_next_state(block_state_block, mdoc, link_state)
@@ -1342,7 +1486,7 @@ module MarkdownExec
1342
1486
 
1343
1487
  # update @delegate_object and @menu_base_options in auto_load
1344
1488
  #
1345
- blocks_in_file, menu_blocks, mdoc = mdoc_menu_and_blocks_from_nested_files
1489
+ blocks_in_file, menu_blocks, mdoc = mdoc_menu_and_blocks_from_nested_files(link_state)
1346
1490
  dump_delobj(blocks_in_file, menu_blocks, link_state)
1347
1491
 
1348
1492
  [block_name_from_cli, now_using_cli, blocks_in_file, menu_blocks, mdoc]
@@ -1358,8 +1502,8 @@ module MarkdownExec
1358
1502
  end
1359
1503
 
1360
1504
  def manage_cli_selection_state(block_name_from_cli, now_using_cli, link_state)
1361
- if block_name_from_cli && @cli_block_name == '.'
1362
- # @bsp 'pause cli control, allow user to select block'
1505
+ if block_name_from_cli && @cli_block_name == @menu_base_options[:menu_persist_block_name]
1506
+ # &bsp 'pause cli control, allow user to select block'
1363
1507
  block_name_from_cli = false
1364
1508
  now_using_cli = false
1365
1509
  @menu_base_options[:block_name] = \
@@ -1373,45 +1517,6 @@ module MarkdownExec
1373
1517
  [block_name_from_cli, now_using_cli]
1374
1518
  end
1375
1519
 
1376
- def next_link_state(block_name_from_cli, was_using_cli, block_state)
1377
- # @bsp 'next_link_state',block_name_from_cli, was_using_cli, block_state
1378
- # Set block_name based on block_name_from_cli
1379
- block_name = block_name_from_cli ? @cli_block_name : nil
1380
-
1381
- # Determine the state of breaker based on was_using_cli and the block type
1382
- breaker = !block_name_from_cli && was_using_cli && block_state.block[:shell] == BlockType::BASH
1383
-
1384
- # Reset block_name_from_cli if the conditions are not met
1385
- block_name_from_cli ||= false
1386
-
1387
- [block_name, block_name_from_cli, breaker]
1388
- end
1389
-
1390
- # Initialize the selection states for the execution loop.
1391
- def initialize_selection_states
1392
- link_state = LinkState.new(
1393
- block_name: @delegate_object[:block_name],
1394
- document_filename: @delegate_object[:filename]
1395
- )
1396
- block_name_from_cli, now_using_cli = handle_cli_block_name(link_state)
1397
- [link_state, block_name_from_cli, now_using_cli]
1398
- end
1399
-
1400
- # Update the state related to CLI block name.
1401
- #
1402
- # This method updates the flags indicating whether a CLI block name is being used
1403
- # and if it was being used previously.
1404
- #
1405
- # @param block_name_from_cli [Boolean] Indicates if the block name is from CLI.
1406
- # @return [Array] Returns the updated state of block name from CLI and its usage.
1407
- def read_block_name_from_cli(block_name_from_cli)
1408
- # was_using_cli = block_name_from_cli
1409
- block_name_from_cli = shift_cli_argument!
1410
- now_using_cli = block_name_from_cli
1411
-
1412
- [block_name_from_cli, now_using_cli]
1413
- end
1414
-
1415
1520
  # Update the block name in the link state and delegate object.
1416
1521
  #
1417
1522
  # This method updates the block name based on whether it was specified
@@ -1425,21 +1530,6 @@ module MarkdownExec
1425
1530
  block_name_from_cli ? @cli_block_name : link_state.block_name
1426
1531
  end
1427
1532
 
1428
- # Handle CLI block name and determine the current CLI usage state.
1429
- #
1430
- # This method processes the CLI block name from the link state and sets
1431
- # the initial state for CLI usage.
1432
- #
1433
- # @param link_state [LinkState] The current link state object.
1434
- # @return [Array] Returns the state of block name from CLI and current usage of CLI.
1435
- def handle_cli_block_name(link_state)
1436
- block_name_from_cli = link_state.block_name.present?
1437
- @cli_block_name = link_state.block_name
1438
- now_using_cli = block_name_from_cli
1439
-
1440
- [block_name_from_cli, now_using_cli]
1441
- end
1442
-
1443
1533
  # Outputs warnings based on the delegate object's configuration
1444
1534
  #
1445
1535
  # @param delegate_object [Hash] The delegate object containing configuration flags.
@@ -1500,7 +1590,7 @@ module MarkdownExec
1500
1590
  rescue TTY::Reader::InputInterrupt
1501
1591
  exit 1
1502
1592
  rescue StandardError
1503
- error_handler('select_option_with_metadata')
1593
+ HashDelegator.error_handler('select_option_with_metadata')
1504
1594
  end
1505
1595
 
1506
1596
  def set_environment_variables_for_block(selected)
@@ -1514,22 +1604,8 @@ module MarkdownExec
1514
1604
  end
1515
1605
  end
1516
1606
 
1517
- def set_environment_variables_per_array(vars)
1518
- vars ||= []
1519
- vars.each { |key, value| ENV[key] = value.to_s }
1520
- end
1521
-
1522
- def set_file_permissions(file_path, chmod_value)
1523
- File.chmod(chmod_value, file_path)
1524
- end
1525
-
1526
- def set_script_block_name(selected)
1527
- @run_state.script_block_name = selected[:oname]
1528
- end
1529
-
1530
1607
  def should_add_back_option?
1531
1608
  @delegate_object[:menu_with_back] && @link_history.prior_state_exist?
1532
- # @delegate_object[:menu_with_back] && link_history_prior_state_exist?
1533
1609
  end
1534
1610
 
1535
1611
  # Initializes a new fenced code block (FCB) object based on the provided line and heading information.
@@ -1573,44 +1649,8 @@ module MarkdownExec
1573
1649
  # @param color_sym [Symbol] The symbol representing the color method.
1574
1650
  # @param default [String] Default color method to use if color_sym is not found in @delegate_object.
1575
1651
  # @return [String] The string with the applied color method.
1576
- def string_send_color(string, color_sym, default: 'plain')
1577
- color_method = @delegate_object.fetch(color_sym, default).to_sym
1578
- string.to_s.send(color_method)
1579
- end
1580
-
1581
- # Creates a TTY prompt with custom settings. Specifically, it disables the default 'cross' symbol and
1582
- # defines a lambda function to handle interrupts.
1583
- # @return [TTY::Prompt] A new TTY::Prompt instance with specified configurations.
1584
- def tty_prompt_without_disabled_symbol
1585
- TTY::Prompt.new(
1586
- interrupt: lambda {
1587
- puts
1588
- raise TTY::Reader::InputInterrupt
1589
- },
1590
- symbols: { cross: ' ' }
1591
- )
1592
- end
1593
-
1594
- # Updates the hierarchy of document headings based on the given line.
1595
- # Utilizes regular expressions to identify heading levels.
1596
- # @param line [String] The line of text to check for headings.
1597
- # @param headings [Array<String>] Current headings hierarchy.
1598
- # @return [Array<String>] Updated headings hierarchy.
1599
- def update_document_headings(line, headings)
1600
- heading3_match = Regexp.new(@delegate_object[:heading3_match])
1601
- heading2_match = Regexp.new(@delegate_object[:heading2_match])
1602
- heading1_match = Regexp.new(@delegate_object[:heading1_match])
1603
-
1604
- case line
1605
- when heading3_match
1606
- [headings[0], headings[1], $~[:name]]
1607
- when heading2_match
1608
- [headings[0], $~[:name]]
1609
- when heading1_match
1610
- [$~[:name]]
1611
- else
1612
- headings
1613
- end
1652
+ def string_send_color(string, color_sym)
1653
+ HashDelegator.apply_color_from_hash(string, @delegate_object, color_sym)
1614
1654
  end
1615
1655
 
1616
1656
  ##
@@ -1635,16 +1675,12 @@ module MarkdownExec
1635
1675
  def update_line_and_block_state(nested_line, state, selected_messages,
1636
1676
  &block)
1637
1677
  line = nested_line.to_s
1638
- if @delegate_object[:menu_blocks_with_headings]
1639
- state[:headings] = update_document_headings(line, state[:headings])
1640
- end
1641
-
1642
1678
  if line.match(@delegate_object[:fenced_start_and_end_regex])
1643
1679
  if state[:in_fenced_block]
1644
1680
  ## end of code block
1645
1681
  #
1646
- update_menu_attrib_yield_selected(state[:fcb], selected_messages,
1647
- &block)
1682
+ HashDelegator.update_menu_attrib_yield_selected(state[:fcb], selected_messages, @delegate_object,
1683
+ &block)
1648
1684
  state[:in_fenced_block] = false
1649
1685
  else
1650
1686
  ## start of code block
@@ -1665,29 +1701,14 @@ module MarkdownExec
1665
1701
  elsif nested_line[:depth].zero? || @delegate_object[:menu_include_imported_notes]
1666
1702
  # add line if it is depth 0 or option allows it
1667
1703
  #
1668
- yield_line_if_selected(line, selected_messages, &block)
1704
+ HashDelegator.yield_line_if_selected(line, selected_messages, &block)
1669
1705
 
1670
1706
  else
1671
- # @bsp 'line is not recognized for block state'
1707
+ # &bsp 'line is not recognized for block state'
1672
1708
 
1673
1709
  end
1674
1710
  end
1675
1711
 
1676
- # Updates the attributes of the given fcb object and conditionally yields to a block.
1677
- # It initializes fcb names and sets the default block title from fcb's body.
1678
- # If the fcb has a body and meets certain conditions, it yields to the given block.
1679
- #
1680
- # @param fcb [Object] The fcb object whose attributes are to be updated.
1681
- # @param selected_messages [Array<Symbol>] A list of message types to determine if yielding is applicable.
1682
- # @param block [Block] An optional block to yield to if conditions are met.
1683
- def update_menu_attrib_yield_selected(fcb, selected_messages, &block)
1684
- initialize_fcb_names(fcb)
1685
- return unless fcb.body
1686
-
1687
- default_block_title_from_body(fcb)
1688
- yield_to_block_if_applicable(fcb, selected_messages, &block)
1689
- end
1690
-
1691
1712
  # Processes YAML data from the selected menu item, updating delegate objects and optionally printing formatted output.
1692
1713
  # @param selected [Hash] Selected item from the menu containing a YAML body.
1693
1714
  # @param tgt2 [Hash, nil] An optional target hash to update with YAML data.
@@ -1717,10 +1738,10 @@ module MarkdownExec
1717
1738
 
1718
1739
  def wait_for_user_selected_block(all_blocks, menu_blocks, default)
1719
1740
  block_state = wait_for_user_selection(all_blocks, menu_blocks, default)
1720
- handle_block_state(block_state)
1741
+ handle_back_or_continue(block_state)
1721
1742
  block_state
1722
1743
  rescue StandardError
1723
- error_handler('wait_for_user_selected_block')
1744
+ HashDelegator.error_handler('wait_for_user_selected_block')
1724
1745
  end
1725
1746
 
1726
1747
  def wait_for_user_selection(_all_blocks, menu_blocks, default)
@@ -1771,32 +1792,13 @@ module MarkdownExec
1771
1792
  "# time: #{time_now}\n" \
1772
1793
  "#{required_lines.flatten.join("\n")}\n"
1773
1794
 
1774
- create_file_and_write_string_with_permissions(
1795
+ HashDelegator.create_file_and_write_string_with_permissions(
1775
1796
  @run_state.saved_filespec,
1776
1797
  content,
1777
1798
  @delegate_object[:saved_script_chmod]
1778
1799
  )
1779
1800
  rescue StandardError
1780
- error_handler('write_command_file')
1781
- end
1782
-
1783
- def save_executed_script_if_specified(lines)
1784
- write_command_file(lines) if @delegate_object[:save_executed_script]
1785
- end
1786
-
1787
- def write_execution_output_to_file
1788
- FileUtils.mkdir_p File.dirname(@delegate_object[:logged_stdout_filespec])
1789
-
1790
- File.write(
1791
- @delegate_object[:logged_stdout_filespec],
1792
- ["-STDOUT-\n",
1793
- format_execution_streams(ExecutionStreams::StdOut),
1794
- "-STDERR-\n",
1795
- format_execution_streams(ExecutionStreams::StdErr),
1796
- "-STDIN-\n",
1797
- format_execution_streams(ExecutionStreams::StdIn),
1798
- "\n"].join
1799
- )
1801
+ HashDelegator.error_handler('write_command_file')
1800
1802
  end
1801
1803
 
1802
1804
  # Writes required code blocks to a temporary file and sets an environment variable with its path.
@@ -1814,40 +1816,10 @@ module MarkdownExec
1814
1816
  []
1815
1817
  end
1816
1818
 
1817
- code_blocks = (read_required_blocks_from_temp_file(import_filename) +
1819
+ code_blocks = (HashDelegator.read_required_blocks_from_temp_file(import_filename) +
1818
1820
  c1).join("\n")
1819
1821
 
1820
- write_code_to_file(code_blocks, temp_file_path)
1821
- end
1822
-
1823
- # Writes the provided code blocks to a file.
1824
- # @param code_blocks [String] Code blocks to write into the file.
1825
- def write_code_to_file(content, path)
1826
- File.write(path, content)
1827
- end
1828
-
1829
- # Yields a line as a new block if the selected message type includes :line.
1830
- # @param [String] line The line to be processed.
1831
- # @param [Array<Symbol>] selected_messages A list of message types to check.
1832
- # @param [Proc] block The block to be called with the line data.
1833
- def yield_line_if_selected(line, selected_messages, &block)
1834
- return unless block && selected_messages.include?(:line)
1835
-
1836
- block.call(:line, FCB.new(body: [line]))
1837
- end
1838
-
1839
- # Yields to the provided block with specified parameters if certain conditions are met.
1840
- # The method checks if a block is given, if the selected_messages include :blocks,
1841
- # and if the fcb_select? method from MarkdownExec::Filter returns true for the given fcb.
1842
- #
1843
- # @param fcb [Object] The object to be evaluated and potentially passed to the block.
1844
- # @param selected_messages [Array<Symbol>] A collection of message types, one of which must be :blocks.
1845
- # @param block [Block] A block to be called if conditions are met.
1846
- def yield_to_block_if_applicable(fcb, selected_messages, &block)
1847
- if block_given? && selected_messages.include?(:blocks) &&
1848
- MarkdownExec::Filter.fcb_select?(@delegate_object, fcb)
1849
- block.call :blocks, fcb
1850
- end
1822
+ HashDelegator.write_code_to_file(code_blocks, temp_file_path)
1851
1823
  end
1852
1824
  end
1853
1825
  end
@@ -1917,30 +1889,30 @@ if $PROGRAM_NAME == __FILE__
1917
1889
  body = "Line 1\nLine 2"
1918
1890
  indent = ' ' # Two spaces
1919
1891
  expected_result = " Line 1\n Line 2"
1920
- assert_equal expected_result, @hd.indent_all_lines(body, indent)
1892
+ assert_equal expected_result, HashDelegator.indent_all_lines(body, indent)
1921
1893
  end
1922
1894
 
1923
1895
  def test_indent_all_lines_without_indent
1924
1896
  body = "Line 1\nLine 2"
1925
1897
  indent = nil
1926
1898
 
1927
- assert_equal body, @hd.indent_all_lines(body, indent)
1899
+ assert_equal body, HashDelegator.indent_all_lines(body, indent)
1928
1900
  end
1929
1901
 
1930
1902
  def test_indent_all_lines_with_empty_indent
1931
1903
  body = "Line 1\nLine 2"
1932
1904
  indent = ''
1933
1905
 
1934
- assert_equal body, @hd.indent_all_lines(body, indent)
1906
+ assert_equal body, HashDelegator.indent_all_lines(body, indent)
1935
1907
  end
1936
1908
 
1937
1909
  def test_safeval_successful_evaluation
1938
- assert_equal 4, @hd.safeval('2 + 2')
1910
+ assert_equal 4, HashDelegator.safeval('2 + 2')
1939
1911
  end
1940
1912
 
1941
1913
  def test_safeval_rescue_from_error
1942
- @hd.stubs(:error_handler).with('safeval')
1943
- assert_nil @hd.safeval('invalid code')
1914
+ HashDelegator.stubs(:error_handler).with('safeval')
1915
+ assert_nil HashDelegator.safeval('invalid code')
1944
1916
  end
1945
1917
 
1946
1918
  def test_set_fcb_title
@@ -1968,7 +1940,7 @@ if $PROGRAM_NAME == __FILE__
1968
1940
  input_output_data.each do |data|
1969
1941
  input = data[:input]
1970
1942
  output = data[:output]
1971
- @hd.default_block_title_from_body(input)
1943
+ HashDelegator.default_block_title_from_body(input)
1972
1944
  assert_equal output, input.title
1973
1945
  end
1974
1946
  end
@@ -1983,7 +1955,7 @@ if $PROGRAM_NAME == __FILE__
1983
1955
  menu_divider_color: :color
1984
1956
  })
1985
1957
  @hd.stubs(:string_send_color).returns('Formatted Divider')
1986
- @hd.stubs(:safeval).returns('Safe Value')
1958
+ HashDelegator.stubs(:safeval).returns('Safe Value')
1987
1959
  end
1988
1960
 
1989
1961
  def test_append_divider_initial
@@ -2018,19 +1990,19 @@ if $PROGRAM_NAME == __FILE__
2018
1990
 
2019
1991
  def test_block_find_with_match
2020
1992
  blocks = [{ key: 'value1' }, { key: 'value2' }]
2021
- result = @hd.block_find(blocks, :key, 'value1')
1993
+ result = HashDelegator.block_find(blocks, :key, 'value1')
2022
1994
  assert_equal({ key: 'value1' }, result)
2023
1995
  end
2024
1996
 
2025
1997
  def test_block_find_without_match
2026
1998
  blocks = [{ key: 'value1' }, { key: 'value2' }]
2027
- result = @hd.block_find(blocks, :key, 'value3')
1999
+ result = HashDelegator.block_find(blocks, :key, 'value3')
2028
2000
  assert_nil result
2029
2001
  end
2030
2002
 
2031
2003
  def test_block_find_with_default
2032
2004
  blocks = [{ key: 'value1' }, { key: 'value2' }]
2033
- result = @hd.block_find(blocks, :key, 'value3', 'default')
2005
+ result = HashDelegator.block_find(blocks, :key, 'value3', 'default')
2034
2006
  assert_equal 'default', result
2035
2007
  end
2036
2008
  end
@@ -2042,7 +2014,7 @@ if $PROGRAM_NAME == __FILE__
2042
2014
  @hd.stubs(:get_block_summary).returns(FCB.new)
2043
2015
  @hd.stubs(:create_and_add_chrome_blocks)
2044
2016
  @hd.instance_variable_set(:@delegate_object, {})
2045
- @hd.stubs(:error_handler)
2017
+ HashDelegator.stubs(:error_handler)
2046
2018
  end
2047
2019
 
2048
2020
  def test_blocks_from_nested_files
@@ -2068,7 +2040,7 @@ if $PROGRAM_NAME == __FILE__
2068
2040
  @hd.instance_variable_set(:@delegate_object, {})
2069
2041
  @mdoc = mock('YourMDocClass')
2070
2042
  @selected = { shell: BlockType::VARS, body: ['key: value'] }
2071
- @hd.stubs(:read_required_blocks_from_temp_file).returns([])
2043
+ HashDelegator.stubs(:read_required_blocks_from_temp_file).returns([])
2072
2044
  @hd.stubs(:string_send_color)
2073
2045
  @hd.stubs(:print)
2074
2046
  end
@@ -2086,7 +2058,7 @@ if $PROGRAM_NAME == __FILE__
2086
2058
  def setup
2087
2059
  @hd = HashDelegator.new
2088
2060
  @hd.instance_variable_set(:@delegate_object, {})
2089
- @hd.stubs(:error_handler)
2061
+ HashDelegator.stubs(:error_handler)
2090
2062
  @hd.stubs(:wait_for_user_selected_block)
2091
2063
  end
2092
2064
 
@@ -2097,7 +2069,7 @@ if $PROGRAM_NAME == __FILE__
2097
2069
 
2098
2070
  result = @hd.load_cli_or_user_selected_block(all_blocks, [], nil)
2099
2071
 
2100
- assert_equal all_blocks.first, result.block
2072
+ assert_equal all_blocks.first.merge(block_name_from_ui: false), result.block
2101
2073
  assert_nil result.state
2102
2074
  end
2103
2075
 
@@ -2108,7 +2080,7 @@ if $PROGRAM_NAME == __FILE__
2108
2080
 
2109
2081
  result = @hd.load_cli_or_user_selected_block([], [], nil)
2110
2082
 
2111
- assert_equal block_state.block, result.block
2083
+ assert_equal block_state.block.merge(block_name_from_ui: true), result.block
2112
2084
  assert_equal :some_state, result.state
2113
2085
  end
2114
2086
  end
@@ -2145,7 +2117,7 @@ if $PROGRAM_NAME == __FILE__
2145
2117
  class TestHashDelegatorCreateAndWriteFile < Minitest::Test
2146
2118
  def setup
2147
2119
  @hd = HashDelegator.new
2148
- @hd.stubs(:error_handler)
2120
+ HashDelegator.stubs(:error_handler)
2149
2121
  FileUtils.stubs(:mkdir_p)
2150
2122
  File.stubs(:write)
2151
2123
  File.stubs(:chmod)
@@ -2160,8 +2132,8 @@ if $PROGRAM_NAME == __FILE__
2160
2132
  File.expects(:write).with(file_path, content).once
2161
2133
  File.expects(:chmod).with(chmod_value, file_path).once
2162
2134
 
2163
- @hd.create_file_and_write_string_with_permissions(file_path, content,
2164
- chmod_value)
2135
+ HashDelegator.create_file_and_write_string_with_permissions(file_path, content,
2136
+ chmod_value)
2165
2137
 
2166
2138
  assert true # Placeholder for actual test assertions
2167
2139
  end
@@ -2175,8 +2147,8 @@ if $PROGRAM_NAME == __FILE__
2175
2147
  File.expects(:write).with(file_path, content).once
2176
2148
  File.expects(:chmod).never
2177
2149
 
2178
- @hd.create_file_and_write_string_with_permissions(file_path, content,
2179
- chmod_value)
2150
+ HashDelegator.create_file_and_write_string_with_permissions(file_path, content,
2151
+ chmod_value)
2180
2152
 
2181
2153
  assert true # Placeholder for actual test assertions
2182
2154
  end
@@ -2307,11 +2279,8 @@ if $PROGRAM_NAME == __FILE__
2307
2279
  end
2308
2280
 
2309
2281
  def test_format_execution_streams_with_valid_key
2310
- @hd.instance_variable_get(:@run_state).stubs(:files).returns({ stdout: %w[
2311
- output1 output2
2312
- ] })
2313
-
2314
- result = @hd.format_execution_streams(:stdout)
2282
+ result = HashDelegator.format_execution_streams(:stdout,
2283
+ { stdout: %w[output1 output2] })
2315
2284
 
2316
2285
  assert_equal 'output1output2', result
2317
2286
  end
@@ -2319,7 +2288,7 @@ if $PROGRAM_NAME == __FILE__
2319
2288
  def test_format_execution_streams_with_empty_key
2320
2289
  @hd.instance_variable_get(:@run_state).stubs(:files).returns({})
2321
2290
 
2322
- result = @hd.format_execution_streams(:stderr)
2291
+ result = HashDelegator.format_execution_streams(:stderr)
2323
2292
 
2324
2293
  assert_equal '', result
2325
2294
  end
@@ -2327,7 +2296,7 @@ if $PROGRAM_NAME == __FILE__
2327
2296
  def test_format_execution_streams_with_nil_files
2328
2297
  @hd.instance_variable_get(:@run_state).stubs(:files).returns(nil)
2329
2298
 
2330
- result = @hd.format_execution_streams(:stdin)
2299
+ result = HashDelegator.format_execution_streams(:stdin)
2331
2300
 
2332
2301
  assert_equal '', result
2333
2302
  end
@@ -2358,33 +2327,33 @@ if $PROGRAM_NAME == __FILE__
2358
2327
  @mock_block_state = mock('block_state')
2359
2328
  end
2360
2329
 
2361
- def test_handle_block_state_with_back
2330
+ def test_handle_back_or_continue_with_back
2362
2331
  @mock_block_state.stubs(:state).returns(MenuState::BACK)
2363
2332
  @mock_block_state.stubs(:block).returns({ oname: 'sample_block' })
2364
2333
 
2365
- @hd.handle_block_state(@mock_block_state)
2334
+ @hd.handle_back_or_continue(@mock_block_state)
2366
2335
 
2367
2336
  assert_equal 'sample_block',
2368
2337
  @hd.instance_variable_get(:@delegate_object)[:block_name]
2369
2338
  assert @hd.instance_variable_get(:@menu_user_clicked_back_link)
2370
2339
  end
2371
2340
 
2372
- def test_handle_block_state_with_continue
2341
+ def test_handle_back_or_continue_with_continue
2373
2342
  @mock_block_state.stubs(:state).returns(MenuState::CONTINUE)
2374
2343
  @mock_block_state.stubs(:block).returns({ oname: 'another_block' })
2375
2344
 
2376
- @hd.handle_block_state(@mock_block_state)
2345
+ @hd.handle_back_or_continue(@mock_block_state)
2377
2346
 
2378
2347
  assert_equal 'another_block',
2379
2348
  @hd.instance_variable_get(:@delegate_object)[:block_name]
2380
2349
  refute @hd.instance_variable_get(:@menu_user_clicked_back_link)
2381
2350
  end
2382
2351
 
2383
- def test_handle_block_state_with_other
2352
+ def test_handle_back_or_continue_with_other
2384
2353
  @mock_block_state.stubs(:state).returns(nil) # MenuState::OTHER
2385
2354
  @mock_block_state.stubs(:block).returns({ oname: 'other_block' })
2386
2355
 
2387
- @hd.handle_block_state(@mock_block_state)
2356
+ @hd.handle_back_or_continue(@mock_block_state)
2388
2357
 
2389
2358
  assert_nil @hd.instance_variable_get(:@delegate_object)[:block_name]
2390
2359
  assert_nil @hd.instance_variable_get(:@menu_user_clicked_back_link)
@@ -2529,7 +2498,7 @@ if $PROGRAM_NAME == __FILE__
2529
2498
  menu_option_back_name: "'Back'",
2530
2499
  menu_chrome_format: '-- %s --'
2531
2500
  })
2532
- @hd.stubs(:safeval).with("'Back'").returns('Back')
2501
+ HashDelegator.stubs(:safeval).with("'Back'").returns('Back')
2533
2502
  end
2534
2503
 
2535
2504
  def test_menu_chrome_formatted_option_with_format
@@ -2584,7 +2553,7 @@ if $PROGRAM_NAME == __FILE__
2584
2553
 
2585
2554
  def test_yield_line_if_selected_with_line
2586
2555
  block_called = false
2587
- @hd.yield_line_if_selected('Test line', [:line]) do |type, content|
2556
+ HashDelegator.yield_line_if_selected('Test line', [:line]) do |type, content|
2588
2557
  block_called = true
2589
2558
  assert_equal :line, type
2590
2559
  assert_equal 'Test line', content.body[0]
@@ -2594,70 +2563,47 @@ if $PROGRAM_NAME == __FILE__
2594
2563
 
2595
2564
  def test_yield_line_if_selected_without_line
2596
2565
  block_called = false
2597
- @hd.yield_line_if_selected('Test line', [:other]) do |_|
2566
+ HashDelegator.yield_line_if_selected('Test line', [:other]) do |_|
2598
2567
  block_called = true
2599
2568
  end
2600
2569
  refute block_called
2601
2570
  end
2602
2571
 
2603
2572
  def test_yield_line_if_selected_without_block
2604
- result = @hd.yield_line_if_selected('Test line', [:line])
2573
+ result = HashDelegator.yield_line_if_selected('Test line', [:line])
2605
2574
  assert_nil result
2606
2575
  end
2607
2576
  end
2608
2577
 
2609
- class TestHashDelegator < Minitest::Test
2610
- def setup
2611
- @hd = HashDelegator.new
2612
- @hd.instance_variable_set(:@delegate_object, {
2613
- heading1_match: '^# (?<name>.+)$',
2614
- heading2_match: '^## (?<name>.+)$',
2615
- heading3_match: '^### (?<name>.+)$'
2616
- })
2617
- end
2618
-
2619
- def test_update_document_headings
2620
- assert_equal(['Heading 1'],
2621
- @hd.update_document_headings('# Heading 1', []))
2622
- assert_equal(['Heading 1', 'Heading 2'],
2623
- @hd.update_document_headings('## Heading 2',
2624
- ['Heading 1']))
2625
- assert_equal(['Heading 1', 'Heading 2', 'Heading 3'],
2626
- @hd.update_document_headings('### Heading 3',
2627
- ['Heading 1', 'Heading 2']))
2628
- assert_equal([], @hd.update_document_headings('Regular text', []))
2629
- end
2630
- end
2631
-
2632
2578
  class TestHashDelegatorUpdateMenuAttribYieldSelectedWithBody < Minitest::Test
2633
2579
  def setup
2634
2580
  @hd = HashDelegator.new
2635
2581
  @fcb = mock('Fcb')
2636
2582
  @fcb.stubs(:body).returns(true)
2637
- @hd.stubs(:initialize_fcb_names)
2638
- @hd.stubs(:default_block_title_from_body)
2639
- @hd.stubs(:yield_to_block_if_applicable)
2583
+ HashDelegator.stubs(:initialize_fcb_names)
2584
+ HashDelegator.stubs(:default_block_title_from_body)
2585
+ Filter.stubs(:yield_to_block_if_applicable)
2640
2586
  end
2641
2587
 
2642
2588
  def test_update_menu_attrib_yield_selected_with_body
2643
- @hd.expects(:initialize_fcb_names).with(@fcb)
2644
- @hd.expects(:default_block_title_from_body).with(@fcb)
2645
- @hd.expects(:yield_to_block_if_applicable).with(@fcb, [:some_message])
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], {})
2646
2592
 
2647
- @hd.update_menu_attrib_yield_selected(@fcb, [:some_message])
2593
+ HashDelegator.update_menu_attrib_yield_selected(@fcb, [:some_message])
2648
2594
  end
2649
2595
 
2650
2596
  def test_update_menu_attrib_yield_selected_without_body
2651
2597
  @fcb.stubs(:body).returns(nil)
2652
- @hd.expects(:initialize_fcb_names).with(@fcb)
2653
- @hd.update_menu_attrib_yield_selected(@fcb, [:some_message])
2598
+ HashDelegator.expects(:initialize_fcb_names).with(@fcb)
2599
+ HashDelegator.update_menu_attrib_yield_selected(@fcb, [:some_message])
2654
2600
  end
2655
2601
  end
2656
2602
 
2657
2603
  class TestHashDelegatorWaitForUserSelectedBlock < Minitest::Test
2658
2604
  def setup
2659
2605
  @hd = HashDelegator.new
2660
- @hd.stubs(:error_handler)
2606
+ HashDelegator.stubs(:error_handler)
2661
2607
  end
2662
2608
 
2663
2609
  def test_wait_for_user_selected_block_with_back_state
@@ -2699,7 +2645,7 @@ if $PROGRAM_NAME == __FILE__
2699
2645
 
2700
2646
  def test_yield_to_block_if_applicable_with_correct_conditions
2701
2647
  block_called = false
2702
- @hd.yield_to_block_if_applicable(@fcb, [:blocks]) do |type, fcb|
2648
+ Filter.yield_to_block_if_applicable(@fcb, [:blocks]) do |type, fcb|
2703
2649
  block_called = true
2704
2650
  assert_equal :blocks, type
2705
2651
  assert_equal @fcb, fcb
@@ -2708,14 +2654,14 @@ if $PROGRAM_NAME == __FILE__
2708
2654
  end
2709
2655
 
2710
2656
  def test_yield_to_block_if_applicable_without_block
2711
- result = @hd.yield_to_block_if_applicable(@fcb, [:blocks])
2657
+ result = Filter.yield_to_block_if_applicable(@fcb, [:blocks])
2712
2658
  assert_nil result
2713
2659
  end
2714
2660
 
2715
2661
  def test_yield_to_block_if_applicable_with_incorrect_conditions
2716
2662
  block_called = false
2717
2663
  MarkdownExec::Filter.stubs(:fcb_select?).returns(false)
2718
- @hd.yield_to_block_if_applicable(@fcb, [:non_blocks]) do |_|
2664
+ Filter.yield_to_block_if_applicable(@fcb, [:non_blocks]) do |_|
2719
2665
  block_called = true
2720
2666
  end
2721
2667
  refute block_called