markdown_exec 1.8.6 → 1.8.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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