markdown_exec 1.2.0 → 1.3.1
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 +6 -1
- data/.rubocop.yml +21 -0
- data/CHANGELOG.md +87 -3
- data/Gemfile +5 -0
- data/Gemfile.lock +15 -13
- data/README.md +81 -4
- data/Rakefile +571 -18
- data/bin/tab_completion.sh +29 -39
- data/bin/tab_completion.sh.erb +23 -0
- data/lib/cli.rb +19 -0
- data/lib/environment_opt_parse.rb +200 -0
- data/lib/globfiles.rb +40 -0
- data/lib/markdown_exec/version.rb +3 -1
- data/lib/markdown_exec.rb +427 -618
- data/lib/menu.yml +364 -0
- data/lib/object_present.rb +40 -0
- data/lib/shared.rb +20 -10
- data/lib/tap.rb +78 -17
- metadata +7 -2
data/bin/tab_completion.sh
CHANGED
@@ -13,7 +13,7 @@ __filedirs_all()
|
|
13
13
|
}
|
14
14
|
|
15
15
|
_mde_echo_version() {
|
16
|
-
echo "1.
|
16
|
+
echo "1.3.1"
|
17
17
|
}
|
18
18
|
|
19
19
|
_mde() {
|
@@ -34,17 +34,23 @@ _mde() {
|
|
34
34
|
|
35
35
|
--debug) COMPREPLY="0"; return 0 ;;
|
36
36
|
|
37
|
-
|
37
|
+
-d) COMPREPLY="0"; return 0 ;;
|
38
38
|
|
39
39
|
--filename) COMPREPLY="."; return 0 ;;
|
40
40
|
|
41
|
-
|
41
|
+
-f) COMPREPLY="."; return 0 ;;
|
42
|
+
|
43
|
+
--path) COMPREPLY="."; return 0 ;;
|
44
|
+
|
45
|
+
-p) COMPREPLY="."; return 0 ;;
|
42
46
|
|
43
|
-
--
|
47
|
+
--user-must-approve) COMPREPLY="1"; return 0 ;;
|
44
48
|
|
45
|
-
|
49
|
+
-q) COMPREPLY="1"; return 0 ;;
|
46
50
|
|
47
|
-
--
|
51
|
+
--display-level) COMPREPLY="1"; return 0 ;;
|
52
|
+
|
53
|
+
--list-count) COMPREPLY="32"; return 0 ;;
|
48
54
|
|
49
55
|
--output-execution-summary) COMPREPLY="0"; return 0 ;;
|
50
56
|
|
@@ -52,26 +58,14 @@ _mde() {
|
|
52
58
|
|
53
59
|
--output-stdout) COMPREPLY="1"; return 0 ;;
|
54
60
|
|
55
|
-
--path) COMPREPLY="."; return 0 ;;
|
56
|
-
|
57
61
|
--save-executed-script) COMPREPLY="0"; return 0 ;;
|
58
62
|
|
59
63
|
--save-execution-output) COMPREPLY="0"; return 0 ;;
|
60
64
|
|
61
|
-
--saved-script-chmod) COMPREPLY="493"; return 0 ;;
|
62
|
-
|
63
|
-
--saved-script-filename-prefix) COMPREPLY="mde"; return 0 ;;
|
64
|
-
|
65
65
|
--saved-script-folder) COMPREPLY="logs"; return 0 ;;
|
66
66
|
|
67
|
-
--saved-script-glob) COMPREPLY="mde_\*.sh"; return 0 ;;
|
68
|
-
|
69
67
|
--saved-stdout-folder) COMPREPLY="logs"; return 0 ;;
|
70
68
|
|
71
|
-
--saved-stdout-glob) COMPREPLY="mde_\*.out.txt"; return 0 ;;
|
72
|
-
|
73
|
-
--user-must-approve) COMPREPLY="1"; return 0 ;;
|
74
|
-
|
75
69
|
esac
|
76
70
|
fi
|
77
71
|
fi
|
@@ -80,7 +74,7 @@ _mde() {
|
|
80
74
|
# present matching option names
|
81
75
|
#
|
82
76
|
if [[ ${cur} == -* ]] ; then
|
83
|
-
opts=("--
|
77
|
+
opts=("--block-name" "--config" "--debug" "--filename" "--help" "--path" "--user-must-approve" "--version" "--exit" "--list-blocks" "--list-default-env" "--list-default-yaml" "--list-docs" "--list-recent-output" "--list-recent-scripts" "--select-recent-output" "--select-recent-script" "--tab-completions" "--run-last-script" "--pwd" "--display-level" "--list-count" "--output-execution-summary" "--output-script" "--output-stdout" "--save-executed-script" "--save-execution-output" "--saved-script-folder" "--saved-stdout-folder")
|
84
78
|
COMPREPLY=( $(compgen -W "$(printf "'%s' " "${opts[@]}")" -- "${cur}") )
|
85
79
|
|
86
80
|
return 0
|
@@ -93,23 +87,31 @@ _mde() {
|
|
93
87
|
if [[ -z ${cur} ]] ; then
|
94
88
|
case $prev in
|
95
89
|
|
90
|
+
--block-name) COMPREPLY=".NAME."; return 0 ;;
|
91
|
+
|
92
|
+
-b) COMPREPLY=".NAME."; return 0 ;;
|
93
|
+
|
96
94
|
--config) COMPREPLY=".PATH."; return 0 ;;
|
97
95
|
|
98
96
|
--debug) COMPREPLY=".BOOL."; return 0 ;;
|
99
97
|
|
100
|
-
|
101
|
-
|
102
|
-
--block-name) COMPREPLY=".NAME."; return 0 ;;
|
98
|
+
-d) COMPREPLY=".BOOL."; return 0 ;;
|
103
99
|
|
104
100
|
--filename) COMPREPLY=".RELATIVE_PATH."; return 0 ;;
|
105
101
|
|
106
|
-
|
102
|
+
-f) COMPREPLY=".RELATIVE_PATH."; return 0 ;;
|
103
|
+
|
104
|
+
--path) COMPREPLY=".RELATIVE_PATH."; return 0 ;;
|
105
|
+
|
106
|
+
-p) COMPREPLY=".RELATIVE_PATH."; return 0 ;;
|
107
|
+
|
108
|
+
--user-must-approve) COMPREPLY=".BOOL."; return 0 ;;
|
107
109
|
|
108
|
-
|
110
|
+
-q) COMPREPLY=".BOOL."; return 0 ;;
|
109
111
|
|
110
|
-
--
|
112
|
+
--display-level) COMPREPLY=".INT.0-3."; return 0 ;;
|
111
113
|
|
112
|
-
--
|
114
|
+
--list-count) COMPREPLY=".INT.1-."; return 0 ;;
|
113
115
|
|
114
116
|
--output-execution-summary) COMPREPLY=".BOOL."; return 0 ;;
|
115
117
|
|
@@ -117,26 +119,14 @@ _mde() {
|
|
117
119
|
|
118
120
|
--output-stdout) COMPREPLY=".BOOL."; return 0 ;;
|
119
121
|
|
120
|
-
--path) COMPREPLY=".RELATIVE_PATH."; return 0 ;;
|
121
|
-
|
122
122
|
--save-executed-script) COMPREPLY=".BOOL."; return 0 ;;
|
123
123
|
|
124
124
|
--save-execution-output) COMPREPLY=".BOOL."; return 0 ;;
|
125
125
|
|
126
|
-
--saved-script-chmod) COMPREPLY=".INT."; return 0 ;;
|
127
|
-
|
128
|
-
--saved-script-filename-prefix) COMPREPLY=".PREFIX."; return 0 ;;
|
129
|
-
|
130
126
|
--saved-script-folder) COMPREPLY=".RELATIVE_PATH."; return 0 ;;
|
131
127
|
|
132
|
-
--saved-script-glob) COMPREPLY=".GLOB."; return 0 ;;
|
133
|
-
|
134
128
|
--saved-stdout-folder) COMPREPLY=".RELATIVE_PATH."; return 0 ;;
|
135
129
|
|
136
|
-
--saved-stdout-glob) COMPREPLY=".GLOB."; return 0 ;;
|
137
|
-
|
138
|
-
--user-must-approve) COMPREPLY=".BOOL."; return 0 ;;
|
139
|
-
|
140
130
|
esac
|
141
131
|
fi
|
142
132
|
|
@@ -148,4 +138,4 @@ _mde() {
|
|
148
138
|
|
149
139
|
complete -o filenames -o nospace -F _mde mde
|
150
140
|
# _mde_echo_version
|
151
|
-
# echo "Updated: 2022-
|
141
|
+
# echo "Updated: 2022-10-29 23:24:15 UTC"
|
data/bin/tab_completion.sh.erb
CHANGED
@@ -30,6 +30,7 @@ _mde() {
|
|
30
30
|
if [[ ${prev} == -* ]] ; then
|
31
31
|
case $prev in
|
32
32
|
<% svhs.each do |svh|
|
33
|
+
|
33
34
|
svn = svh[:long_name]
|
34
35
|
if svn && svh[:arg_name]
|
35
36
|
svn = '--' + svh[:long_name]
|
@@ -43,6 +44,21 @@ _mde() {
|
|
43
44
|
<%= svn + ') COMPREPLY="' + svh[:compreply] + '"; return 0 ;;' %>
|
44
45
|
<% end
|
45
46
|
end
|
47
|
+
|
48
|
+
svn = svh[:short_name]
|
49
|
+
if svn && svh[:arg_name]
|
50
|
+
svn = '-' + svh[:short_name]
|
51
|
+
if svh[:compreply] == false
|
52
|
+
# nothing
|
53
|
+
elsif svh[:compreply].nil? %>
|
54
|
+
<%= svn + ') __filedirs_all; return 0 ;;' %>
|
55
|
+
<% elsif svh[:compreply].empty?
|
56
|
+
# nothing
|
57
|
+
else %>
|
58
|
+
<%= svn + ') COMPREPLY="' + svh[:compreply] + '"; return 0 ;;' %>
|
59
|
+
<% end
|
60
|
+
end
|
61
|
+
|
46
62
|
end %>
|
47
63
|
esac
|
48
64
|
fi
|
@@ -65,11 +81,18 @@ _mde() {
|
|
65
81
|
if [[ -z ${cur} ]] ; then
|
66
82
|
case $prev in
|
67
83
|
<% svhs.each do |svh|
|
84
|
+
|
68
85
|
svn = svh[:long_name]
|
69
86
|
if svn && svh[:arg_name]
|
70
87
|
svn = '--' + svh[:long_name] %>
|
71
88
|
<%= svn + ') COMPREPLY=".' + svh[:arg_name] + '."; return 0 ;;' %>
|
72
89
|
<% end
|
90
|
+
|
91
|
+
svn = svh[:short_name]
|
92
|
+
if svn && svh[:arg_name]
|
93
|
+
svn = '-' + svh[:short_name] %>
|
94
|
+
<%= svn + ') COMPREPLY=".' + svh[:arg_name] + '."; return 0 ;;' %>
|
95
|
+
<% end
|
73
96
|
end %>
|
74
97
|
esac
|
75
98
|
fi
|
data/lib/cli.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# encoding=utf-8
|
4
|
+
|
5
|
+
# utility functions to provide CLI
|
6
|
+
#
|
7
|
+
module CLI
|
8
|
+
# skip :reek:UtilityFunction
|
9
|
+
def value_for_cli(value)
|
10
|
+
case value.class.to_s
|
11
|
+
when 'String'
|
12
|
+
Shellwords.escape value
|
13
|
+
when 'FalseClass', 'TrueClass'
|
14
|
+
value ? '1' : '0'
|
15
|
+
else
|
16
|
+
Shellwords.escape value.to_s
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# encoding=utf-8
|
4
|
+
|
5
|
+
require 'optparse'
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
require_relative 'object_present'
|
9
|
+
|
10
|
+
class Hash
|
11
|
+
unless defined?(sym_keys)
|
12
|
+
def sym_keys
|
13
|
+
transform_keys(&:to_sym)
|
14
|
+
# map do |key, value|
|
15
|
+
# [key.to_sym, value]
|
16
|
+
# end.to_h
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class EnvironmentOptParse
|
22
|
+
attr_reader :options, :remainder
|
23
|
+
|
24
|
+
# utility functions to create menu
|
25
|
+
#
|
26
|
+
module Menu
|
27
|
+
def menu_all(menu_data, lambdas, config)
|
28
|
+
config.tap_yaml 'config'
|
29
|
+
input_option_values, remainder, = menu_parse(add_proc(menu_data, lambdas))
|
30
|
+
# options = menu_default_option_values(menu_data).merge input_option_values
|
31
|
+
# options = (menu_default_option_values(menu_data)).merge(input_option_values).tap_yaml 'options1'
|
32
|
+
options = menu_default_option_values(menu_data).merge(config).merge(input_option_values) #.tap_yaml 'options2'
|
33
|
+
# options = menu_data.map do |menu_item|
|
34
|
+
# menu_item.tap_inspect 'menu_item'
|
35
|
+
# mion = menu_item[:opt_name]&.to_sym.tap_inspect 'mion'
|
36
|
+
# omion = config[mion].tap_inspect 'omion'
|
37
|
+
# unless omion.nil?
|
38
|
+
# menu_item[:default] = omion
|
39
|
+
# end
|
40
|
+
# menu_item
|
41
|
+
# end,
|
42
|
+
|
43
|
+
[options, remainder]
|
44
|
+
end
|
45
|
+
|
46
|
+
def add_proc(menu_data, lambdas)
|
47
|
+
menu_data.each do |menu_item|
|
48
|
+
menu_item.tap_yaml 'menu_item'
|
49
|
+
procname = menu_item[:procname]
|
50
|
+
next if procname.nil?
|
51
|
+
|
52
|
+
menu_item[:proccode] = lambdas.fetch(procname.to_sym, menu_item[:procname])
|
53
|
+
end.tap_yaml
|
54
|
+
end
|
55
|
+
|
56
|
+
def menu_default_option_values(menu_data)
|
57
|
+
menu_data.map do |item|
|
58
|
+
item_default = item[:default]
|
59
|
+
next if item_default.nil?
|
60
|
+
next unless item[:opt_name].present?
|
61
|
+
|
62
|
+
[item[:opt_name].to_sym, item_default]
|
63
|
+
end.compact.to_h
|
64
|
+
end
|
65
|
+
|
66
|
+
def menu_help(menu_data)
|
67
|
+
options = {}
|
68
|
+
option_parser = OptionParser.new do |opts|
|
69
|
+
opts.banner = [
|
70
|
+
"#{APP_NAME} - #{APP_DESC} (#{VERSION})",
|
71
|
+
"Usage: #{File.basename($PROGRAM_NAME)} [options]"
|
72
|
+
].join("\n")
|
73
|
+
|
74
|
+
menu_data.each do |item|
|
75
|
+
menu_option_append opts, options, item
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
option_parser.help
|
80
|
+
end
|
81
|
+
|
82
|
+
def menu_option_append(opts, options, item)
|
83
|
+
return unless item[:long_name].present? || item[:short_name].present?
|
84
|
+
|
85
|
+
mmoo = [
|
86
|
+
# long name
|
87
|
+
if item[:long_name].present?
|
88
|
+
"--#{item[:long_name]}#{item[:arg_name].present? ? " #{item[:arg_name]}" : ''}"
|
89
|
+
end,
|
90
|
+
|
91
|
+
# short name
|
92
|
+
item[:short_name].present? ? "-#{item[:short_name]}" : nil,
|
93
|
+
|
94
|
+
# description and default
|
95
|
+
[item[:description],
|
96
|
+
item[:default].present? ? "[#{value_for_menu item[:default]}]" : nil].compact.join(' '),
|
97
|
+
|
98
|
+
# apply proccode, if present, to value
|
99
|
+
# save value to options hash if option is named
|
100
|
+
#
|
101
|
+
lambda { |value|
|
102
|
+
(item[:proccode] ? item[:proccode].call(value) : value).tap do |converted|
|
103
|
+
opt_name = item[:opt_name]
|
104
|
+
next if opt_name.nil?
|
105
|
+
|
106
|
+
options[opt_name.to_sym] = converted if item[:opt_name]
|
107
|
+
end
|
108
|
+
}
|
109
|
+
].compact
|
110
|
+
opts.on(*mmoo)
|
111
|
+
end
|
112
|
+
|
113
|
+
def menu_parse(menu_options)
|
114
|
+
options = {}
|
115
|
+
option_parser = OptionParser.new do |opts|
|
116
|
+
menu_options.each do |item|
|
117
|
+
item[:opt_name] = item[:opt_name]&.to_sym
|
118
|
+
menu_option_append opts, options, item
|
119
|
+
end
|
120
|
+
end
|
121
|
+
option_parser.load # filename defaults to basename of the program without suffix in a directory ~/.options
|
122
|
+
option_parser.environment # env defaults to the basename of the program.
|
123
|
+
remainder = option_parser.parse!
|
124
|
+
|
125
|
+
[options, remainder, option_parser.help]
|
126
|
+
end
|
127
|
+
|
128
|
+
# skip :reek:UtilityFunction
|
129
|
+
def value_for_menu(value)
|
130
|
+
case value.class.to_s
|
131
|
+
when 'String'
|
132
|
+
value
|
133
|
+
when 'FalseClass', 'TrueClass'
|
134
|
+
value ? '1' : '0'
|
135
|
+
else
|
136
|
+
value.to_s
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
include Menu
|
142
|
+
|
143
|
+
def initialize(menu: {}, lambdas: nil, options: nil, version: nil)
|
144
|
+
@menu = if menu.class.to_s == 'String'
|
145
|
+
filetext = File.read(menu).tap_yaml 'filetext'
|
146
|
+
fileyaml = YAML.load(filetext)
|
147
|
+
fileyaml.map(&:sym_keys)
|
148
|
+
else
|
149
|
+
menu
|
150
|
+
end.tap_yaml '@menu'
|
151
|
+
@lambdas = lambdas
|
152
|
+
@version = version || '0.1'
|
153
|
+
# @options = {}
|
154
|
+
@options = if options.class.to_s == 'String'
|
155
|
+
YAML.safe_load(File.read(options)).sym_keys.tap_yaml '@options'
|
156
|
+
else
|
157
|
+
{}
|
158
|
+
end #.tap_yaml '@options'
|
159
|
+
|
160
|
+
parse!
|
161
|
+
end
|
162
|
+
|
163
|
+
def parse!
|
164
|
+
@options, @remainder = menu_all(
|
165
|
+
@menu,
|
166
|
+
# @menu.map do |menu_item|
|
167
|
+
# menu_item.tap_inspect 'menu_item'
|
168
|
+
# mion = menu_item[:opt_name]&.to_sym.tap_inspect 'mion'
|
169
|
+
# omion = @options[mion].tap_inspect 'omion'
|
170
|
+
# unless omion.nil?
|
171
|
+
# @options[menu_item[:default]] = omion
|
172
|
+
# end
|
173
|
+
# menu_item
|
174
|
+
# end,
|
175
|
+
{
|
176
|
+
debug: ->(value) { tap_config value: value },
|
177
|
+
|
178
|
+
# stdout_configuration: lambda { |_| self.options.tap_puts 'eop' },
|
179
|
+
# stdout_configuration: (lambda { |options|
|
180
|
+
# lambda { |v| options.tap_puts 'eop_l' }
|
181
|
+
# }).call(@options),
|
182
|
+
|
183
|
+
stdout_defaults: ->(_) { menu_default_option_values(@menu).to_yaml.tap_puts },
|
184
|
+
stdout_help: lambda { |_|
|
185
|
+
menu_help(@menu).tap_puts
|
186
|
+
exit
|
187
|
+
},
|
188
|
+
val_as_bool: ->(value) { value.class.to_s == 'String' ? (value.chomp != '0') : value },
|
189
|
+
val_as_int: ->(value) { value.to_i },
|
190
|
+
val_as_str: ->(value) { value.to_s },
|
191
|
+
version: lambda { |_|
|
192
|
+
@version.tap_puts
|
193
|
+
exit
|
194
|
+
}
|
195
|
+
}.merge(@lambdas || {}),
|
196
|
+
@options
|
197
|
+
)
|
198
|
+
@options #.tap_yaml '@options'
|
199
|
+
end
|
200
|
+
end
|
data/lib/globfiles.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# encoding=utf-8
|
4
|
+
|
5
|
+
# require 'json'
|
6
|
+
# require 'yaml'
|
7
|
+
|
8
|
+
# require_relative 'env'
|
9
|
+
# include Env
|
10
|
+
|
11
|
+
## directory listing of saved files matching glob
|
12
|
+
#
|
13
|
+
class Globfiles
|
14
|
+
def initialize(folder, glob)
|
15
|
+
@folder = folder
|
16
|
+
@glob = glob
|
17
|
+
end
|
18
|
+
|
19
|
+
def list_all
|
20
|
+
Dir.glob(File.join(@folder, @glob)).tap_inspect
|
21
|
+
end
|
22
|
+
|
23
|
+
## single most recent item
|
24
|
+
#
|
25
|
+
def most_recent(arr = nil)
|
26
|
+
arr = list_all if arr.nil?
|
27
|
+
return if arr.count < 1
|
28
|
+
|
29
|
+
arr.max.tap_inspect
|
30
|
+
end
|
31
|
+
|
32
|
+
## multiple recent items
|
33
|
+
#
|
34
|
+
def most_recent_list(list_count, arr = nil)
|
35
|
+
arr = list_all if arr.nil?
|
36
|
+
return if (ac = arr.count) < 1
|
37
|
+
|
38
|
+
arr.sort[-[ac, list_count].min..].reverse.tap_inspect
|
39
|
+
end
|
40
|
+
end # class Globfiles
|