markdown_exec 1.3.0 → 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.reek +3 -0
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +32 -9
- data/Gemfile +5 -0
- data/Gemfile.lock +15 -13
- data/README.md +56 -0
- data/Rakefile +182 -63
- data/bin/tab_completion.sh +21 -3
- data/bin/tab_completion.sh.erb +23 -0
- data/lib/cli.rb +19 -0
- data/lib/environment_opt_parse.rb +200 -0
- data/lib/markdown_exec/version.rb +1 -1
- data/lib/markdown_exec.rb +222 -139
- data/lib/menu.yml +135 -64
- data/lib/object_present.rb +40 -0
- data/lib/shared.rb +3 -14
- data/lib/tap.rb +76 -21
- metadata +5 -2
data/lib/markdown_exec.rb
CHANGED
@@ -6,18 +6,23 @@
|
|
6
6
|
require 'English'
|
7
7
|
require 'clipboard'
|
8
8
|
require 'open3'
|
9
|
-
require 'optparse'
|
9
|
+
# require 'optparse'
|
10
10
|
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
|
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
|
@@ -771,43 +821,43 @@ module MarkdownExec
|
|
771
821
|
menu_item.merge(
|
772
822
|
{
|
773
823
|
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
|
-
|
824
|
+
proccode: case menu_item[:procname]
|
825
|
+
when 'debug'
|
826
|
+
lambda { |value|
|
827
|
+
tap_config value: value
|
828
|
+
}
|
829
|
+
when 'exit'
|
830
|
+
lambda { |_|
|
831
|
+
exit
|
832
|
+
}
|
833
|
+
when 'help'
|
834
|
+
lambda { |_|
|
835
|
+
fout menu_help
|
836
|
+
exit
|
837
|
+
}
|
838
|
+
when 'path'
|
839
|
+
lambda { |value|
|
840
|
+
read_configuration_file! options, value
|
841
|
+
}
|
842
|
+
when 'show_config'
|
843
|
+
lambda { |_|
|
844
|
+
options_finalize options
|
845
|
+
fout options.sort_by_key.to_yaml
|
846
|
+
}
|
847
|
+
when 'val_as_bool'
|
848
|
+
->(value) { value.class.to_s == 'String' ? (value.chomp != '0') : value }
|
849
|
+
when 'val_as_int'
|
850
|
+
->(value) { value.to_i }
|
851
|
+
when 'val_as_str'
|
852
|
+
->(value) { value.to_s }
|
853
|
+
when 'version'
|
854
|
+
lambda { |_|
|
855
|
+
fout MarkdownExec::VERSION
|
856
|
+
exit
|
857
|
+
}
|
858
|
+
else
|
859
|
+
menu_item[:procname]
|
860
|
+
end
|
811
861
|
}
|
812
862
|
)
|
813
863
|
end
|
@@ -829,7 +879,7 @@ module MarkdownExec
|
|
829
879
|
menu += [summ[0][:name]]
|
830
880
|
end
|
831
881
|
end
|
832
|
-
menu.
|
882
|
+
menu.tap_yaml
|
833
883
|
end
|
834
884
|
|
835
885
|
def menu_iter(data = menu_for_optparse, &block)
|
@@ -840,6 +890,33 @@ module MarkdownExec
|
|
840
890
|
@option_parser.help
|
841
891
|
end
|
842
892
|
|
893
|
+
def menu_option_append(opts, options, item)
|
894
|
+
return unless item[:long_name].present? || item[:short_name].present?
|
895
|
+
|
896
|
+
opts.on(*[
|
897
|
+
# long name
|
898
|
+
if item[:long_name].present?
|
899
|
+
"--#{item[:long_name]}#{item[:arg_name].present? ? " #{item[:arg_name]}" : ''}"
|
900
|
+
end,
|
901
|
+
|
902
|
+
# short name
|
903
|
+
item[:short_name].present? ? "-#{item[:short_name]}" : nil,
|
904
|
+
|
905
|
+
# description and default
|
906
|
+
[item[:description],
|
907
|
+
item[:default].present? ? "[#{value_for_cli item[:default]}]" : nil].compact.join(' '),
|
908
|
+
|
909
|
+
# apply proccode, if present, to value
|
910
|
+
# save value to options hash if option is named
|
911
|
+
#
|
912
|
+
lambda { |value|
|
913
|
+
(item[:proccode] ? item[:proccode].call(value) : value).tap do |converted|
|
914
|
+
options[item[:opt_name]] = converted if item[:opt_name]
|
915
|
+
end
|
916
|
+
}
|
917
|
+
].compact)
|
918
|
+
end
|
919
|
+
|
843
920
|
## post-parse options configuration
|
844
921
|
#
|
845
922
|
def options_finalize(rest)
|
@@ -851,7 +928,7 @@ module MarkdownExec
|
|
851
928
|
elsif File.exist?(pos)
|
852
929
|
@options[:filename] = pos
|
853
930
|
else
|
854
|
-
raise
|
931
|
+
raise FileMissingError, pos, caller
|
855
932
|
end
|
856
933
|
end
|
857
934
|
|
@@ -925,6 +1002,21 @@ module MarkdownExec
|
|
925
1002
|
|
926
1003
|
# :reek:NestedIterators
|
927
1004
|
def run
|
1005
|
+
# eop = EnvironmentOptParse.new(
|
1006
|
+
# menu: File.join(File.expand_path(__dir__), 'menu.yml'),
|
1007
|
+
# options: {
|
1008
|
+
# menu_exit_at_top: true,
|
1009
|
+
# menu_with_exit: true
|
1010
|
+
# }
|
1011
|
+
# ).tap_yaml '** eop'
|
1012
|
+
# # eop = EnvironmentOptParse.new(menu: 'lib/menu.yml', options: ".#{MarkdownExec::APP_NAME.downcase}.yml", version: MarkdownExec::VERSION).tap_yaml '** eop'
|
1013
|
+
# eop.options.tap_inspect 'eop.options'
|
1014
|
+
# eop.remainder.tap_inspect 'eop.remainder'
|
1015
|
+
|
1016
|
+
# exec_block eop.options, eop.options[:block_name]
|
1017
|
+
|
1018
|
+
# return
|
1019
|
+
|
928
1020
|
## default configuration
|
929
1021
|
#
|
930
1022
|
@options = base_options
|
@@ -942,29 +1034,20 @@ module MarkdownExec
|
|
942
1034
|
].join("\n")
|
943
1035
|
|
944
1036
|
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)
|
1037
|
+
item.tap_yaml 'item'
|
1038
|
+
menu_option_append opts, options, item
|
959
1039
|
end
|
960
1040
|
end
|
961
1041
|
option_parser.load # filename defaults to basename of the program without suffix in a directory ~/.options
|
962
1042
|
option_parser.environment # env defaults to the basename of the program.
|
963
1043
|
rest = option_parser.parse! # (into: options)
|
964
1044
|
|
965
|
-
|
966
|
-
|
967
|
-
|
1045
|
+
begin
|
1046
|
+
options_finalize rest
|
1047
|
+
exec_block options, options[:block_name]
|
1048
|
+
rescue FileMissingError => e
|
1049
|
+
puts "File missing: #{e}"
|
1050
|
+
end
|
968
1051
|
end
|
969
1052
|
|
970
1053
|
def saved_name_split(name)
|
@@ -1013,7 +1096,7 @@ module MarkdownExec
|
|
1013
1096
|
def select_and_approve_block(call_options = {}, &options_block)
|
1014
1097
|
opts = optsmerge call_options, options_block
|
1015
1098
|
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).
|
1099
|
+
mdoc = MDoc.new(blocks_in_file) { |nopts| opts.merge!(nopts).tap_yaml name: :infiled_opts }
|
1017
1100
|
blocks_menu = mdoc.blocks_for_menu(opts.merge(struct: true)).tap_inspect name: :blocks_menu
|
1018
1101
|
|
1019
1102
|
repeat_menu = true && !opts[:block_name].present?
|
@@ -1097,7 +1180,7 @@ module MarkdownExec
|
|
1097
1180
|
|
1098
1181
|
def menu_export(data = menu_for_optparse)
|
1099
1182
|
data.map do |item|
|
1100
|
-
item.delete(:
|
1183
|
+
item.delete(:procname)
|
1101
1184
|
item
|
1102
1185
|
end.to_yaml
|
1103
1186
|
end
|
@@ -1116,7 +1199,7 @@ module MarkdownExec
|
|
1116
1199
|
else
|
1117
1200
|
@options.merge! opts
|
1118
1201
|
end
|
1119
|
-
@options.
|
1202
|
+
@options.tap_yaml
|
1120
1203
|
end
|
1121
1204
|
|
1122
1205
|
def write_command_file(call_options, required_blocks)
|