markdown_exec 1.6 → 1.8

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.
data/lib/mdoc.rb CHANGED
@@ -21,7 +21,7 @@ module MarkdownExec
21
21
  #
22
22
  # @param table [Array<Hash>] An array of hashes representing markdown sections.
23
23
  #
24
- def initialize(table)
24
+ def initialize(table = [])
25
25
  @table = table
26
26
  end
27
27
 
@@ -47,8 +47,8 @@ module MarkdownExec
47
47
  # write named variables to block at top of script
48
48
  #
49
49
  fcb[:body].join(' ').split.compact.map do |key|
50
- format(opts[:block_type_port_set_format],
51
- { key: key, value: ENV.fetch(key, nil) })
50
+ ### format(opts[:block_type_port_set_format], { key: key, value: ENV.fetch(key, nil) })
51
+ "key: #{key}, value: #{ENV.fetch(key, nil)}"
52
52
  end
53
53
  end
54
54
 
@@ -72,22 +72,30 @@ module MarkdownExec
72
72
  def collect_recursively_required_blocks(name)
73
73
  name_block = get_block_by_anyname(name)
74
74
  if name_block.nil? || name_block.keys.empty?
75
- raise "Named code block `#{name}` not found."
75
+ raise "Named code block `#{name}` not found. (@#{__LINE__})"
76
76
  end
77
77
 
78
- all = [name_block.oname] + recursively_required(name_block[:reqs])
78
+ # all_dependency_names = [name_block.oname] + recursively_required(name_block[:reqs])
79
+ dependencies = collect_dependencies(name_block[:oname])
80
+ all_dependency_names = collect_unique_names(dependencies).push(name_block[:oname]).uniq
81
+ unmet_dependencies = all_dependency_names.dup
79
82
 
80
- # in order of appearance in document
83
+ # in order of appearance in document (@table)
81
84
  # insert function blocks
82
- @table.select { |fcb| all.include? fcb.oname }
83
- .map do |fcb|
85
+ blocks = @table.select { |fcb| all_dependency_names.include? fcb[:oname] }
86
+ .map do |fcb|
87
+ unmet_dependencies.delete(fcb[:oname]) # may not exist if block name is duplicated
84
88
  if (call = fcb[:call])
85
89
  [get_block_by_oname("[#{call.match(/^%\((\S+) |\)/)[1]}]")
86
90
  .merge({ cann: call })]
87
91
  else
88
92
  []
89
93
  end + [fcb]
90
- end.flatten(1)
94
+ end.flatten(1) #.tap { rbp }
95
+ { all_dependency_names: all_dependency_names,
96
+ blocks: blocks,
97
+ dependencies: dependencies,
98
+ unmet_dependencies: unmet_dependencies }
91
99
  end
92
100
 
93
101
  # Collects recursively required code blocks and returns them as an array of strings.
@@ -95,10 +103,9 @@ module MarkdownExec
95
103
  # @param name [String] The name of the code block to start the collection from.
96
104
  # @return [Array<String>] An array of strings containing the collected code blocks.
97
105
  #
98
- def collect_recursively_required_code(name, opts: {})
99
- code = collect_wrapped_blocks(
100
- blocks = collect_recursively_required_blocks(name)
101
- ).map do |fcb|
106
+ def collect_recursively_required_code(name, label_body: true, label_format_above: nil, label_format_below: nil)
107
+ block_search = collect_recursively_required_blocks(name)
108
+ block_search.merge({ code: collect_wrapped_blocks(block_search[:blocks]).map do |fcb|
102
109
  if fcb[:cann]
103
110
  collect_block_code_cann(fcb)
104
111
  elsif fcb[:stdout]
@@ -108,11 +115,18 @@ module MarkdownExec
108
115
  nil
109
116
  elsif fcb[:shell] == BlockType::PORT
110
117
  collect_block_code_shell(fcb)
111
- else
118
+ elsif label_body
119
+ [label_format_above && format(label_format_above, { name: fcb[:oname] })] +
120
+ fcb[:body] +
121
+ [label_format_below && format(label_format_below, { name: fcb[:oname] })]
122
+ else # raw body
112
123
  fcb[:body]
113
124
  end
114
- end.compact.flatten(1)
115
- { blocks: blocks, code: code }
125
+ end.compact.flatten(1).compact })
126
+ end
127
+
128
+ def collect_unique_names(hash)
129
+ hash.values.flatten.uniq
116
130
  end
117
131
 
118
132
  # Retrieves code blocks that are wrapped
@@ -209,9 +223,7 @@ module MarkdownExec
209
223
  end
210
224
  end
211
225
 
212
- # def load_auto_blocks(opts)
213
- # end
214
-
226
+ # if tr ue
215
227
  # Recursively fetches required code blocks for a given list of requirements.
216
228
  #
217
229
  # @param reqs [Array<String>] An array of requirements to start the recursion from.
@@ -222,7 +234,7 @@ module MarkdownExec
222
234
 
223
235
  rem = reqs
224
236
  memo = []
225
- while rem.count.positive?
237
+ while rem && rem.count.positive?
226
238
  rem = rem.map do |req|
227
239
  next if memo.include? req
228
240
 
@@ -235,6 +247,57 @@ module MarkdownExec
235
247
  memo
236
248
  end
237
249
 
250
+ # else
251
+ # Recursively fetches required code blocks for a given list of requirements.
252
+ #
253
+ # @param source [String] The name of the code block to start the recursion from.
254
+ # @return [Hash] A list of code blocks required by each source code block.
255
+ #
256
+ def recursively_required_hash(source, memo = Hash.new([]))
257
+ return memo unless source
258
+ return memo if memo.keys.include? source
259
+
260
+ block = get_block_by_anyname(source)
261
+ if block.nil? || block.keys.empty?
262
+ raise "Named code block `#{source}` not found. (@#{__LINE__})"
263
+ end
264
+
265
+ memo[source] = block[:reqs]
266
+ return memo unless memo[source]&.count&.positive?
267
+
268
+ memo[source].each do |req|
269
+ next if memo.keys.include? req
270
+
271
+ recursively_required_hash(req, memo)
272
+ end
273
+ memo
274
+ end
275
+
276
+ # end
277
+
278
+ # Recursively collects dependencies of a given source.
279
+ # @param source [String] The name of the initial source block.
280
+ # @param memo [Hash] A memoization hash to store resolved dependencies.
281
+ # @return [Hash] A hash mapping sources to their respective dependencies.
282
+ def collect_dependencies(source, memo = {})
283
+ return memo unless source
284
+
285
+ if (block = get_block_by_anyname(source)).nil? || block.keys.empty?
286
+ if true
287
+ return memo
288
+ else
289
+ raise "Named code block `#{source}` not found. (@#{__LINE__})"
290
+ end
291
+ end
292
+
293
+ return memo unless block[:reqs]
294
+
295
+ memo[source] = block[:reqs]
296
+
297
+ block[:reqs].each { |req| collect_dependencies(req, memo) unless memo.key?(req) }
298
+ memo
299
+ end
300
+
238
301
  def select_elements_with_neighbor_conditions(array,
239
302
  last_selected_placeholder = nil, next_selected_placeholder = nil)
240
303
  selected_elements = []
@@ -286,16 +349,64 @@ if $PROGRAM_NAME == __FILE__
286
349
  Bundler.require(:default)
287
350
 
288
351
  require 'minitest/autorun'
352
+ require 'mocha/minitest'
289
353
 
290
354
  module MarkdownExec
355
+ class TestMDocCollectDependencies < Minitest::Test
356
+ def setup
357
+ @mdoc = MDoc.new
358
+ end
359
+
360
+ def test_collect_dependencies_with_no_source
361
+ assert_empty @mdoc.collect_dependencies(nil)
362
+ end
363
+
364
+ if false # must raise error
365
+ def test_collect_dependencies_with_nonexistent_source
366
+ assert_raises(RuntimeError) { @mdoc.collect_dependencies('nonexistent') }
367
+ end
368
+ end
369
+
370
+ def test_collect_dependencies_with_valid_source
371
+ @mdoc.stubs(:get_block_by_anyname).with('source1').returns({ reqs: ['source2'] })
372
+ @mdoc.stubs(:get_block_by_anyname).with('source2').returns({ reqs: [] })
373
+
374
+ expected = { 'source1' => ['source2'], 'source2' => [] }
375
+ assert_equal expected, @mdoc.collect_dependencies('source1')
376
+ end
377
+ end
378
+
379
+ class TestCollectUniqueNames < Minitest::Test
380
+ def setup
381
+ @mdoc = MDoc.new
382
+ end
383
+
384
+ def test_empty_hash
385
+ assert_empty @mdoc.collect_unique_names({})
386
+ end
387
+
388
+ def test_single_key
389
+ input = { group1: %w[Alice Bob Charlie] }
390
+ assert_equal %w[Alice Bob Charlie], @mdoc.collect_unique_names(input)
391
+ end
392
+
393
+ def test_multiple_keys
394
+ input = { group1: %w[Alice Bob], group2: %w[Charlie Alice] }
395
+ assert_equal %w[Alice Bob Charlie], @mdoc.collect_unique_names(input)
396
+ end
397
+
398
+ def test_no_unique_names
399
+ input = { group1: ['Alice'], group2: ['Alice'] }
400
+ assert_equal ['Alice'], @mdoc.collect_unique_names(input)
401
+ end
402
+ end
403
+
291
404
  class TestMDoc < Minitest::Test
292
405
  def setup
293
406
  @table = [
294
- { oname: 'block1', body: ['code for block1'],
295
- reqs: ['block2'] },
407
+ { oname: 'block1', body: ['code for block1'], reqs: ['block2'] },
296
408
  { oname: 'block2', body: ['code for block2'], reqs: nil },
297
- { oname: 'block3', body: ['code for block3'],
298
- reqs: ['block1'] }
409
+ { oname: 'block3', body: ['code for block3'], reqs: ['block1'] }
299
410
  ]
300
411
  @doc = MDoc.new(@table)
301
412
  end
@@ -315,15 +426,15 @@ if $PROGRAM_NAME == __FILE__
315
426
  end
316
427
 
317
428
  ### broken test
318
- # def test_collect_recursively_required_blocks
319
- # result = @doc.collect_recursively_required_blocks('block3')
320
- # expected_result = [@table[0], @table[1], @table[2]]
321
- # assert_equal expected_result, result
429
+ def test_collect_recursively_required_blocks
430
+ result = @doc.collect_recursively_required_blocks('block3')[:blocks]
431
+ expected_result = [@table[0], @table[1], @table[2]]
432
+ assert_equal expected_result, result
322
433
 
323
- # assert_raises(RuntimeError) do
324
- # @doc.collect_recursively_required_blocks('missing_block')
325
- # end
326
- # end
434
+ assert_raises(RuntimeError) do
435
+ @doc.collect_recursively_required_blocks('missing_block')
436
+ end
437
+ end
327
438
 
328
439
  def test_hide_menu_block_per_options
329
440
  opts = { hide_blocks_by_name: true,
@@ -341,11 +452,12 @@ if $PROGRAM_NAME == __FILE__
341
452
  # end
342
453
 
343
454
  def test_recursively_required
344
- result = @doc.recursively_required(['block3'])
345
- assert_equal %w[block3 block1 block2], result
455
+ result = @doc.recursively_required_hash('block3')
456
+ assert_equal ({ 'block3' => ['block1'], 'block1' => ['block2'], 'block2' => nil }),
457
+ result
346
458
 
347
- result_no_reqs = @doc.recursively_required(nil)
348
- assert_equal [], result_no_reqs
459
+ result_no_reqs = @doc.recursively_required_hash(nil)
460
+ assert_equal ({}), result_no_reqs
349
461
  end
350
462
  end
351
463