markdown_exec 1.3.0 → 1.3.2
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.
- checksums.yaml +4 -4
- data/.reek +3 -0
- data/.rubocop.yml +19 -1
- data/CHANGELOG.md +39 -9
- data/Gemfile +5 -0
- data/Gemfile.lock +33 -13
- data/README.md +60 -0
- data/Rakefile +189 -63
- data/bin/tab_completion.sh +21 -3
- data/bin/tab_completion.sh.erb +23 -0
- data/lib/cli.rb +19 -0
- data/lib/env.rb +7 -3
- data/lib/env_opts.rb +244 -0
- data/lib/environment_opt_parse.rb +204 -0
- data/lib/markdown_exec/version.rb +1 -1
- data/lib/markdown_exec.rb +211 -145
- data/lib/menu.yml +135 -64
- data/lib/object_present.rb +39 -0
- data/lib/shared.rb +3 -14
- data/lib/tap.rb +95 -20
- data/lib/yaml_env_opts.rb +60 -0
- metadata +7 -2
data/lib/markdown_exec.rb
CHANGED
@@ -11,13 +11,18 @@ require 'shellwords'
|
|
11
11
|
require 'tty-prompt'
|
12
12
|
require 'yaml'
|
13
13
|
|
14
|
+
require_relative 'cli'
|
14
15
|
require_relative 'colorize'
|
15
16
|
require_relative 'env'
|
17
|
+
# require_relative 'environment_opt_parse'
|
18
|
+
require_relative 'object_present'
|
16
19
|
require_relative 'shared'
|
17
20
|
require_relative 'tap'
|
18
21
|
require_relative 'markdown_exec/version'
|
19
22
|
|
23
|
+
include CLI
|
20
24
|
include Tap
|
25
|
+
|
21
26
|
tap_config envvar: MarkdownExec::TAP_DEBUG
|
22
27
|
|
23
28
|
$stderr.sync = true
|
@@ -25,6 +30,8 @@ $stdout.sync = true
|
|
25
30
|
|
26
31
|
BLOCK_SIZE = 1024
|
27
32
|
|
33
|
+
class FileMissingError < StandardError; end
|
34
|
+
|
28
35
|
# hash with keys sorted by name
|
29
36
|
#
|
30
37
|
class Hash
|
@@ -33,26 +40,34 @@ class Hash
|
|
33
40
|
end
|
34
41
|
end
|
35
42
|
|
36
|
-
#
|
43
|
+
# stdout manager
|
37
44
|
#
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
true
|
44
|
-
else
|
45
|
-
self && (!respond_to?(:blank?) || !blank?)
|
46
|
-
end
|
45
|
+
module FOUT
|
46
|
+
# standard output; not for debug
|
47
|
+
#
|
48
|
+
def fout(str)
|
49
|
+
puts str
|
47
50
|
end
|
48
|
-
end
|
49
51
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
def
|
55
|
-
|
52
|
+
def fout_list(str)
|
53
|
+
puts str
|
54
|
+
end
|
55
|
+
|
56
|
+
def fout_section(name, data)
|
57
|
+
puts "# #{name}"
|
58
|
+
puts data.to_yaml
|
59
|
+
end
|
60
|
+
|
61
|
+
def approved_fout?(level)
|
62
|
+
level <= @options[:display_level]
|
63
|
+
end
|
64
|
+
|
65
|
+
# display output at level or lower than filter (DISPLAY_LEVEL_DEFAULT)
|
66
|
+
#
|
67
|
+
def lout(str, level: DISPLAY_LEVEL_BASE)
|
68
|
+
return unless approved_fout? level
|
69
|
+
|
70
|
+
fout level == DISPLAY_LEVEL_BASE ? str : @options[:display_level_xbase_prefix] + str
|
56
71
|
end
|
57
72
|
end
|
58
73
|
|
@@ -64,6 +79,29 @@ module MarkdownExec
|
|
64
79
|
# :reek:IrresponsibleModule
|
65
80
|
class Error < StandardError; end
|
66
81
|
|
82
|
+
# cache lines in text file
|
83
|
+
#
|
84
|
+
class CFile
|
85
|
+
def initialize
|
86
|
+
@cache = {}
|
87
|
+
end
|
88
|
+
|
89
|
+
def readlines(filename)
|
90
|
+
if @cache[filename]
|
91
|
+
@cache[filename].each do |line|
|
92
|
+
yield line if block_given?
|
93
|
+
end
|
94
|
+
else
|
95
|
+
lines = []
|
96
|
+
File.readlines(filename).each do |line|
|
97
|
+
lines.push line
|
98
|
+
yield line if block_given?
|
99
|
+
end
|
100
|
+
@cache[filename] = lines
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end # class CFile
|
104
|
+
|
67
105
|
## an imported markdown document
|
68
106
|
#
|
69
107
|
class MDoc
|
@@ -74,7 +112,7 @@ module MarkdownExec
|
|
74
112
|
def collect_recursively_required_code(name)
|
75
113
|
get_required_blocks(name)
|
76
114
|
.map do |block|
|
77
|
-
block.
|
115
|
+
block.tap_yaml name: :block
|
78
116
|
body = block[:body].join("\n")
|
79
117
|
|
80
118
|
if block[:cann]
|
@@ -106,12 +144,12 @@ module MarkdownExec
|
|
106
144
|
block[:body]
|
107
145
|
end
|
108
146
|
end.flatten(1)
|
109
|
-
.
|
147
|
+
.tap_yaml
|
110
148
|
end
|
111
149
|
|
112
150
|
def get_block_by_name(name, default = {})
|
113
151
|
name.tap_inspect name: :name
|
114
|
-
@table.select { |block| block[:name] == name }.fetch(0, default).
|
152
|
+
@table.select { |block| block[:name] == name }.fetch(0, default).tap_yaml
|
115
153
|
end
|
116
154
|
|
117
155
|
def get_required_blocks(name)
|
@@ -125,19 +163,19 @@ module MarkdownExec
|
|
125
163
|
|
126
164
|
# insert function blocks
|
127
165
|
sel.map do |block|
|
128
|
-
block.
|
166
|
+
block.tap_yaml name: :block
|
129
167
|
if (call = block[:call])
|
130
168
|
[get_block_by_name("[#{call.match(/^\((\S+) |\)/)[1]}]").merge({ cann: call })]
|
131
169
|
else
|
132
170
|
[]
|
133
171
|
end + [block]
|
134
|
-
end.flatten(1) # .
|
172
|
+
end.flatten(1) # .tap_yaml
|
135
173
|
end
|
136
174
|
|
137
175
|
# :reek:UtilityFunction
|
138
176
|
def hide_menu_block_per_options(opts, block)
|
139
177
|
(opts[:hide_blocks_by_name] &&
|
140
|
-
block[:name].match(Regexp.new(opts[:
|
178
|
+
block[:name].match(Regexp.new(opts[:block_name_hidden_match]))).tap_inspect
|
141
179
|
end
|
142
180
|
|
143
181
|
def blocks_for_menu(opts)
|
@@ -161,7 +199,7 @@ module MarkdownExec
|
|
161
199
|
.compact
|
162
200
|
.flatten(1)
|
163
201
|
end
|
164
|
-
all.
|
202
|
+
all.tap_yaml
|
165
203
|
end
|
166
204
|
end # class MDoc
|
167
205
|
|
@@ -297,9 +335,12 @@ module MarkdownExec
|
|
297
335
|
class MarkParse
|
298
336
|
attr_reader :options
|
299
337
|
|
338
|
+
include FOUT
|
339
|
+
|
300
340
|
def initialize(options = {})
|
301
341
|
@options = options
|
302
|
-
@prompt = TTY::Prompt.new(interrupt: :exit)
|
342
|
+
@prompt = TTY::Prompt.new(interrupt: :exit, symbols: { cross: ' ' })
|
343
|
+
# @prompt = TTY::Prompt.new(interrupt: :exit, symbols: { cross: options[:menu_divider_symbol] })
|
303
344
|
@execute_aborted_at = nil
|
304
345
|
@execute_completed_at = nil
|
305
346
|
@execute_error = nil
|
@@ -309,6 +350,7 @@ module MarkdownExec
|
|
309
350
|
@execute_script_filespec = nil
|
310
351
|
@execute_started_at = nil
|
311
352
|
@option_parser = nil
|
353
|
+
@cfile = CFile.new
|
312
354
|
end
|
313
355
|
|
314
356
|
##
|
@@ -316,7 +358,7 @@ module MarkdownExec
|
|
316
358
|
|
317
359
|
def base_options
|
318
360
|
menu_iter do |item|
|
319
|
-
# noisy item.
|
361
|
+
# noisy item.tap_yaml name: :item
|
320
362
|
next unless item[:opt_name].present?
|
321
363
|
|
322
364
|
item_default = item[:default]
|
@@ -326,13 +368,13 @@ module MarkdownExec
|
|
326
368
|
else
|
327
369
|
env_str(item[:env_var], default: OptionValue.new(item_default).for_hash)
|
328
370
|
end
|
329
|
-
[item[:opt_name], item[:
|
371
|
+
[item[:opt_name], item[:proccode] ? item[:proccode].call(value) : value]
|
330
372
|
end.compact.to_h.merge(
|
331
373
|
{
|
332
374
|
menu_exit_at_top: true,
|
333
375
|
menu_with_exit: true
|
334
376
|
}
|
335
|
-
).
|
377
|
+
).tap_yaml
|
336
378
|
end
|
337
379
|
|
338
380
|
def default_options
|
@@ -341,10 +383,6 @@ module MarkdownExec
|
|
341
383
|
exclude_expect_blocks: true,
|
342
384
|
hide_blocks_by_name: true,
|
343
385
|
output_saved_script_filename: false,
|
344
|
-
prompt_approve_block: 'Process?',
|
345
|
-
prompt_select_block: 'Choose a block:',
|
346
|
-
prompt_select_md: 'Choose a file:',
|
347
|
-
prompt_select_output: 'Choose a file:',
|
348
386
|
saved_script_filename: nil, # calculated
|
349
387
|
struct: true # allow get_block_summary()
|
350
388
|
}
|
@@ -352,7 +390,7 @@ module MarkdownExec
|
|
352
390
|
|
353
391
|
def approve_block(opts, mdoc)
|
354
392
|
required_blocks = mdoc.collect_recursively_required_code(opts[:block_name])
|
355
|
-
|
393
|
+
display_required_code(opts, required_blocks) if opts[:output_script] || opts[:user_must_approve]
|
356
394
|
|
357
395
|
allow = true
|
358
396
|
if opts[:user_must_approve]
|
@@ -362,10 +400,10 @@ module MarkdownExec
|
|
362
400
|
# menu.enum '.'
|
363
401
|
# menu.filter true
|
364
402
|
|
365
|
-
menu.choice
|
366
|
-
menu.choice
|
367
|
-
menu.choice
|
368
|
-
menu.choice
|
403
|
+
menu.choice opts[:prompt_yes], 1
|
404
|
+
menu.choice opts[:prompt_no], 2
|
405
|
+
menu.choice opts[:prompt_script_to_clipboard], 3
|
406
|
+
menu.choice opts[:prompt_save_script], 4
|
369
407
|
end).tap_inspect name: :sel
|
370
408
|
allow = (sel == 1)
|
371
409
|
if sel == 3
|
@@ -397,15 +435,22 @@ module MarkdownExec
|
|
397
435
|
selected[:name]
|
398
436
|
end
|
399
437
|
|
438
|
+
# def cc(str)
|
439
|
+
# puts " - - - #{Process.clock_gettime(Process::CLOCK_MONOTONIC)} - #{str}"
|
440
|
+
# end
|
441
|
+
|
400
442
|
# :reek:DuplicateMethodCall
|
401
443
|
# :reek:UncommunicativeVariableName { exclude: [ e ] }
|
402
444
|
# :reek:LongYieldList
|
403
445
|
def command_execute(opts, command)
|
446
|
+
# dd = lambda { |s| puts 'command_execute() ' + s }
|
447
|
+
#d 'execute command and yield outputs'
|
404
448
|
@execute_files = Hash.new([])
|
405
449
|
@execute_options = opts
|
406
450
|
@execute_started_at = Time.now.utc
|
407
451
|
|
408
452
|
Open3.popen3(@options[:shell], '-c', command) do |stdin, stdout, stderr, exec_thr|
|
453
|
+
#d 'command started'
|
409
454
|
Thread.new do
|
410
455
|
until (line = stdout.gets).nil?
|
411
456
|
@execute_files[EF_STDOUT] = @execute_files[EF_STDOUT] + [line]
|
@@ -413,7 +458,7 @@ module MarkdownExec
|
|
413
458
|
yield nil, line, nil, exec_thr if block_given?
|
414
459
|
end
|
415
460
|
rescue IOError
|
416
|
-
# thread killed, do nothing
|
461
|
+
#d 'stdout IOError, thread killed, do nothing'
|
417
462
|
end
|
418
463
|
|
419
464
|
Thread.new do
|
@@ -423,7 +468,7 @@ module MarkdownExec
|
|
423
468
|
yield nil, nil, line, exec_thr if block_given?
|
424
469
|
end
|
425
470
|
rescue IOError
|
426
|
-
# thread killed, do nothing
|
471
|
+
#d 'stderr IOError, thread killed, do nothing'
|
427
472
|
end
|
428
473
|
|
429
474
|
in_thr = Thread.new do
|
@@ -432,22 +477,33 @@ module MarkdownExec
|
|
432
477
|
@execute_files[EF_STDIN] = @execute_files[EF_STDIN] + [line]
|
433
478
|
yield line, nil, nil, exec_thr if block_given?
|
434
479
|
end
|
480
|
+
#d 'exec_thr now dead'
|
481
|
+
rescue StandardError
|
482
|
+
#d 'stdin error, thread killed, do nothing'
|
435
483
|
end
|
436
484
|
|
485
|
+
#d 'join exec_thr'
|
437
486
|
exec_thr.join
|
487
|
+
|
488
|
+
#d 'wait before closing stdin'
|
489
|
+
sleep 0.1
|
490
|
+
|
491
|
+
#d 'kill stdin thread'
|
438
492
|
in_thr.kill
|
439
493
|
# @return_code = exec_thr.value
|
494
|
+
#d 'command end'
|
440
495
|
end
|
496
|
+
#d 'command completed'
|
441
497
|
@execute_completed_at = Time.now.utc
|
442
498
|
rescue Errno::ENOENT => e
|
443
|
-
# error triggered by missing command in script
|
499
|
+
#d 'command error ENOENT triggered by missing command in script'
|
444
500
|
@execute_aborted_at = Time.now.utc
|
445
501
|
@execute_error_message = e.message
|
446
502
|
@execute_error = e
|
447
503
|
@execute_files[EF_STDERR] += [@execute_error_message]
|
448
504
|
fout "Error ENOENT: #{e.inspect}"
|
449
505
|
rescue SignalException => e
|
450
|
-
# SIGTERM triggered by user or system
|
506
|
+
#d 'command SIGTERM triggered by user or system'
|
451
507
|
@execute_aborted_at = Time.now.utc
|
452
508
|
@execute_error_message = 'SIGTERM'
|
453
509
|
@execute_error = e
|
@@ -458,15 +514,15 @@ module MarkdownExec
|
|
458
514
|
def count_blocks_in_filename
|
459
515
|
fenced_start_and_end_match = Regexp.new @options[:fenced_start_and_end_match]
|
460
516
|
cnt = 0
|
461
|
-
|
517
|
+
@cfile.readlines(@options[:filename]).each do |line|
|
462
518
|
cnt += 1 if line.match(fenced_start_and_end_match)
|
463
519
|
end
|
464
520
|
cnt / 2
|
465
521
|
end
|
466
522
|
|
467
523
|
# :reek:DuplicateMethodCall
|
468
|
-
def
|
469
|
-
frame =
|
524
|
+
def display_required_code(opts, required_blocks)
|
525
|
+
frame = opts[:output_divider].send(opts[:output_divider_color].to_sym)
|
470
526
|
fout frame
|
471
527
|
required_blocks.each { |cb| fout cb }
|
472
528
|
fout frame
|
@@ -523,21 +579,6 @@ module MarkdownExec
|
|
523
579
|
fout "saved_filespec: #{@execute_script_filespec}" if @options[:output_saved_script_filename]
|
524
580
|
end
|
525
581
|
|
526
|
-
# standard output; not for debug
|
527
|
-
#
|
528
|
-
def fout(str)
|
529
|
-
puts str
|
530
|
-
end
|
531
|
-
|
532
|
-
def fout_list(str)
|
533
|
-
puts str
|
534
|
-
end
|
535
|
-
|
536
|
-
def fout_section(name, data)
|
537
|
-
puts "# #{name}"
|
538
|
-
puts data.to_yaml
|
539
|
-
end
|
540
|
-
|
541
582
|
# :reek:LongParameterList
|
542
583
|
def get_block_summary(call_options = {}, headings:, block_title:, block_body:)
|
543
584
|
opts = optsmerge call_options
|
@@ -561,19 +602,7 @@ module MarkdownExec
|
|
561
602
|
call: call,
|
562
603
|
reqs: reqs,
|
563
604
|
stdin: stdin,
|
564
|
-
stdout: stdout })].
|
565
|
-
end
|
566
|
-
|
567
|
-
def approved_fout?(level)
|
568
|
-
level <= @options[:display_level]
|
569
|
-
end
|
570
|
-
|
571
|
-
# display output at level or lower than filter (DISPLAY_LEVEL_DEFAULT)
|
572
|
-
#
|
573
|
-
def lout(str, level: DISPLAY_LEVEL_BASE)
|
574
|
-
return unless approved_fout? level
|
575
|
-
|
576
|
-
fout level == DISPLAY_LEVEL_BASE ? str : @options[:display_level_xbase_prefix] + str
|
605
|
+
stdout: stdout })].tap_yaml
|
577
606
|
end
|
578
607
|
|
579
608
|
# :reek:DuplicateMethodCall
|
@@ -600,7 +629,7 @@ module MarkdownExec
|
|
600
629
|
|
601
630
|
selected_messages = yield :filter
|
602
631
|
|
603
|
-
|
632
|
+
@cfile.readlines(opts[:filename]).each do |line|
|
604
633
|
continue unless line
|
605
634
|
|
606
635
|
if opts[:menu_blocks_with_headings]
|
@@ -656,19 +685,32 @@ module MarkdownExec
|
|
656
685
|
opts = optsmerge call_options, options_block
|
657
686
|
|
658
687
|
blocks = []
|
688
|
+
if opts[:menu_initial_divider].present?
|
689
|
+
blocks += [{
|
690
|
+
name: format(opts[:menu_divider_format],
|
691
|
+
opts[:menu_initial_divider]).send(opts[:menu_divider_color].to_sym), disabled: ''
|
692
|
+
}]
|
693
|
+
end
|
659
694
|
iter_blocks_in_file(opts) do |btype, headings, block_title, body|
|
660
695
|
case btype
|
661
696
|
when :filter
|
662
697
|
%i[blocks line]
|
663
698
|
when :line
|
664
699
|
if opts[:menu_divider_match] && (mbody = body.match opts[:menu_divider_match])
|
665
|
-
blocks += [{ name: (opts[:menu_divider_format]
|
700
|
+
blocks += [{ name: format(opts[:menu_divider_format], mbody[:name]).send(opts[:menu_divider_color].to_sym),
|
701
|
+
disabled: '' }]
|
666
702
|
end
|
667
703
|
when :blocks
|
668
704
|
blocks += get_block_summary opts, headings: headings, block_title: block_title, block_body: body
|
669
705
|
end
|
670
706
|
end
|
671
|
-
|
707
|
+
if opts[:menu_divider_format].present? && opts[:menu_final_divider].present?
|
708
|
+
blocks += [{
|
709
|
+
name: format(opts[:menu_divider_format],
|
710
|
+
opts[:menu_final_divider]).send(opts[:menu_divider_color].to_sym), disabled: ''
|
711
|
+
}]
|
712
|
+
end
|
713
|
+
blocks.tap_yaml
|
672
714
|
end
|
673
715
|
|
674
716
|
def list_default_env
|
@@ -706,22 +748,30 @@ module MarkdownExec
|
|
706
748
|
def list_files_specified(specified_filename: nil, specified_folder: nil,
|
707
749
|
default_filename: nil, default_folder: nil, filetree: nil)
|
708
750
|
fn = File.join(if specified_filename&.present?
|
709
|
-
|
710
|
-
|
711
|
-
|
751
|
+
# puts ' LFS 01'
|
752
|
+
if specified_filename.start_with? '/'
|
753
|
+
# puts ' LFS 02'
|
712
754
|
[specified_filename]
|
755
|
+
elsif specified_folder&.present?
|
756
|
+
# puts ' LFS 03'
|
757
|
+
[specified_folder, specified_filename]
|
713
758
|
else
|
759
|
+
# puts ' LFS 04'
|
714
760
|
[default_folder, specified_filename]
|
715
761
|
end
|
716
762
|
elsif specified_folder&.present?
|
763
|
+
# puts ' LFS 05'
|
717
764
|
if filetree
|
765
|
+
# puts ' LFS 06'
|
718
766
|
[specified_folder, @options[:md_filename_match]]
|
719
767
|
else
|
768
|
+
# puts ' LFS 07'
|
720
769
|
[specified_folder, @options[:md_filename_glob]]
|
721
770
|
end
|
722
771
|
else
|
772
|
+
# puts ' LFS 08'
|
723
773
|
[default_folder, default_filename]
|
724
|
-
end)
|
774
|
+
end).tap_inspect name: :fn
|
725
775
|
if filetree
|
726
776
|
filetree.select { |filename| filename == fn || filename.match(/^#{fn}$/) || filename.match(%r{^#{fn}/.+$}) }
|
727
777
|
else
|
@@ -738,11 +788,9 @@ module MarkdownExec
|
|
738
788
|
blocks_in_file = list_blocks_in_file(opts.merge(struct: true))
|
739
789
|
mdoc = MDoc.new(blocks_in_file)
|
740
790
|
|
741
|
-
list_blocks_in_file(opts).
|
742
|
-
|
743
|
-
|
744
|
-
block
|
745
|
-
end.compact.tap_inspect
|
791
|
+
list_blocks_in_file(opts).reject do |block|
|
792
|
+
mdoc.hide_menu_block_per_options(opts, block)
|
793
|
+
end.tap_inspect
|
746
794
|
end
|
747
795
|
|
748
796
|
def list_recent_output(saved_stdout_folder, saved_stdout_glob, list_count)
|
@@ -771,43 +819,43 @@ module MarkdownExec
|
|
771
819
|
menu_item.merge(
|
772
820
|
{
|
773
821
|
opt_name: menu_item[:opt_name]&.to_sym,
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
822
|
+
proccode: case menu_item[:procname]
|
823
|
+
when 'debug'
|
824
|
+
lambda { |value|
|
825
|
+
tap_config value: value
|
826
|
+
}
|
827
|
+
when 'exit'
|
828
|
+
lambda { |_|
|
829
|
+
exit
|
830
|
+
}
|
831
|
+
when 'help'
|
832
|
+
lambda { |_|
|
833
|
+
fout menu_help
|
834
|
+
exit
|
835
|
+
}
|
836
|
+
when 'path'
|
837
|
+
lambda { |value|
|
838
|
+
read_configuration_file! options, value
|
839
|
+
}
|
840
|
+
when 'show_config'
|
841
|
+
lambda { |_|
|
842
|
+
options_finalize options
|
843
|
+
fout options.sort_by_key.to_yaml
|
844
|
+
}
|
845
|
+
when 'val_as_bool'
|
846
|
+
->(value) { value.class.to_s == 'String' ? (value.chomp != '0') : value }
|
847
|
+
when 'val_as_int'
|
848
|
+
->(value) { value.to_i }
|
849
|
+
when 'val_as_str'
|
850
|
+
->(value) { value.to_s }
|
851
|
+
when 'version'
|
852
|
+
lambda { |_|
|
853
|
+
fout MarkdownExec::VERSION
|
854
|
+
exit
|
855
|
+
}
|
856
|
+
else
|
857
|
+
menu_item[:procname]
|
858
|
+
end
|
811
859
|
}
|
812
860
|
)
|
813
861
|
end
|
@@ -829,7 +877,7 @@ module MarkdownExec
|
|
829
877
|
menu += [summ[0][:name]]
|
830
878
|
end
|
831
879
|
end
|
832
|
-
menu.
|
880
|
+
menu.tap_yaml
|
833
881
|
end
|
834
882
|
|
835
883
|
def menu_iter(data = menu_for_optparse, &block)
|
@@ -840,6 +888,33 @@ module MarkdownExec
|
|
840
888
|
@option_parser.help
|
841
889
|
end
|
842
890
|
|
891
|
+
def menu_option_append(opts, options, item)
|
892
|
+
return unless item[:long_name].present? || item[:short_name].present?
|
893
|
+
|
894
|
+
opts.on(*[
|
895
|
+
# long name
|
896
|
+
if item[:long_name].present?
|
897
|
+
"--#{item[:long_name]}#{item[:arg_name].present? ? " #{item[:arg_name]}" : ''}"
|
898
|
+
end,
|
899
|
+
|
900
|
+
# short name
|
901
|
+
item[:short_name].present? ? "-#{item[:short_name]}" : nil,
|
902
|
+
|
903
|
+
# description and default
|
904
|
+
[item[:description],
|
905
|
+
item[:default].present? ? "[#{value_for_cli item[:default]}]" : nil].compact.join(' '),
|
906
|
+
|
907
|
+
# apply proccode, if present, to value
|
908
|
+
# save value to options hash if option is named
|
909
|
+
#
|
910
|
+
lambda { |value|
|
911
|
+
(item[:proccode] ? item[:proccode].call(value) : value).tap do |converted|
|
912
|
+
options[item[:opt_name]] = converted if item[:opt_name]
|
913
|
+
end
|
914
|
+
}
|
915
|
+
].compact)
|
916
|
+
end
|
917
|
+
|
843
918
|
## post-parse options configuration
|
844
919
|
#
|
845
920
|
def options_finalize(rest)
|
@@ -851,7 +926,7 @@ module MarkdownExec
|
|
851
926
|
elsif File.exist?(pos)
|
852
927
|
@options[:filename] = pos
|
853
928
|
else
|
854
|
-
raise
|
929
|
+
raise FileMissingError, pos, caller
|
855
930
|
end
|
856
931
|
end
|
857
932
|
|
@@ -942,29 +1017,20 @@ module MarkdownExec
|
|
942
1017
|
].join("\n")
|
943
1018
|
|
944
1019
|
menu_iter do |item|
|
945
|
-
|
946
|
-
|
947
|
-
opts.on(*[if item[:long_name].present?
|
948
|
-
"--#{item[:long_name]}#{item[:arg_name].present? ? " #{item[:arg_name]}" : ''}"
|
949
|
-
end,
|
950
|
-
item[:short_name].present? ? "-#{item[:short_name]}" : nil,
|
951
|
-
[item[:description],
|
952
|
-
item[:default].present? ? "[#{value_for_cli item[:default]}]" : nil].compact.join(' '),
|
953
|
-
lambda { |value|
|
954
|
-
# ret = item[:proc1].call(value)
|
955
|
-
ret = item[:proc1] ? item[:proc1].call(value) : value
|
956
|
-
options[item[:opt_name]] = ret if item[:opt_name]
|
957
|
-
ret
|
958
|
-
}].compact)
|
1020
|
+
item.tap_yaml 'item'
|
1021
|
+
menu_option_append opts, options, item
|
959
1022
|
end
|
960
1023
|
end
|
961
1024
|
option_parser.load # filename defaults to basename of the program without suffix in a directory ~/.options
|
962
1025
|
option_parser.environment # env defaults to the basename of the program.
|
963
1026
|
rest = option_parser.parse! # (into: options)
|
964
1027
|
|
965
|
-
|
966
|
-
|
967
|
-
|
1028
|
+
begin
|
1029
|
+
options_finalize rest
|
1030
|
+
exec_block options, options[:block_name]
|
1031
|
+
rescue FileMissingError => e
|
1032
|
+
puts "File missing: #{e}"
|
1033
|
+
end
|
968
1034
|
end
|
969
1035
|
|
970
1036
|
def saved_name_split(name)
|
@@ -998,7 +1064,7 @@ module MarkdownExec
|
|
998
1064
|
@options[:logged_stdout_filespec] = File.join @options[:saved_stdout_folder], @options[:logged_stdout_filename]
|
999
1065
|
@logged_stdout_filespec = @options[:logged_stdout_filespec]
|
1000
1066
|
(dirname = File.dirname(@options[:logged_stdout_filespec])).tap_inspect name: :dirname
|
1001
|
-
Dir.
|
1067
|
+
Dir.mkdir_p dirname
|
1002
1068
|
|
1003
1069
|
ol = ["-STDOUT-\n"]
|
1004
1070
|
ol += @execute_files&.fetch(EF_STDOUT, [])
|
@@ -1013,7 +1079,7 @@ module MarkdownExec
|
|
1013
1079
|
def select_and_approve_block(call_options = {}, &options_block)
|
1014
1080
|
opts = optsmerge call_options, options_block
|
1015
1081
|
blocks_in_file = list_blocks_in_file(opts.merge(struct: true)).tap_inspect name: :blocks_in_file
|
1016
|
-
mdoc = MDoc.new(blocks_in_file) { |nopts| opts.merge!(nopts).
|
1082
|
+
mdoc = MDoc.new(blocks_in_file) { |nopts| opts.merge!(nopts).tap_yaml name: :infiled_opts }
|
1017
1083
|
blocks_menu = mdoc.blocks_for_menu(opts.merge(struct: true)).tap_inspect name: :blocks_menu
|
1018
1084
|
|
1019
1085
|
repeat_menu = true && !opts[:block_name].present?
|
@@ -1097,7 +1163,7 @@ module MarkdownExec
|
|
1097
1163
|
|
1098
1164
|
def menu_export(data = menu_for_optparse)
|
1099
1165
|
data.map do |item|
|
1100
|
-
item.delete(:
|
1166
|
+
item.delete(:procname)
|
1101
1167
|
item
|
1102
1168
|
end.to_yaml
|
1103
1169
|
end
|
@@ -1116,7 +1182,7 @@ module MarkdownExec
|
|
1116
1182
|
else
|
1117
1183
|
@options.merge! opts
|
1118
1184
|
end
|
1119
|
-
@options.
|
1185
|
+
@options.tap_yaml
|
1120
1186
|
end
|
1121
1187
|
|
1122
1188
|
def write_command_file(call_options, required_blocks)
|
@@ -1135,7 +1201,7 @@ module MarkdownExec
|
|
1135
1201
|
File.join opts[:saved_script_folder], opts[:saved_script_filename]
|
1136
1202
|
|
1137
1203
|
dirname = File.dirname(@options[:saved_filespec])
|
1138
|
-
Dir.
|
1204
|
+
Dir.mkdir_p dirname
|
1139
1205
|
(shebang = if @options[:shebang]&.present?
|
1140
1206
|
"#{@options[:shebang]} #{@options[:shell]}\n"
|
1141
1207
|
else
|