markdown_exec 2.3.0 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +11 -2
- data/CHANGELOG.md +19 -0
- data/Gemfile.lock +1 -1
- data/Rakefile +32 -8
- data/bats/bats.bats +33 -0
- data/bats/block-types.bats +56 -0
- data/bats/cli.bats +74 -0
- data/bats/fail.bats +11 -0
- data/bats/history.bats +34 -0
- data/bats/markup.bats +66 -0
- data/bats/mde.bats +29 -0
- data/bats/options.bats +92 -0
- data/bats/test_helper.bash +152 -0
- data/bin/tab_completion.sh +44 -20
- data/docs/dev/block-type-opts.md +10 -0
- data/docs/dev/block-type-port.md +24 -0
- data/docs/dev/block-type-vars.md +7 -0
- data/docs/dev/pass-through-arguments.md +8 -0
- data/docs/dev/specs-import.md +9 -0
- data/docs/dev/specs.md +83 -0
- data/docs/dev/text-decoration.md +7 -0
- data/examples/bash-blocks.md +4 -4
- data/examples/block-names.md +2 -2
- data/examples/import0.md +23 -0
- data/examples/import1.md +13 -0
- data/examples/link-blocks-vars.md +3 -3
- data/examples/opts-blocks-require.md +6 -6
- data/examples/table-markup.md +31 -0
- data/examples/text-markup.md +58 -0
- data/examples/vars-blocks.md +2 -2
- data/examples/wrap.md +87 -9
- data/lib/ansi_formatter.rb +12 -6
- data/lib/ansi_string.rb +153 -0
- data/lib/argument_processor.rb +160 -0
- data/lib/cached_nested_file_reader.rb +4 -2
- data/lib/ce_get_cost_and_usage.rb +4 -3
- data/lib/cli.rb +1 -1
- data/lib/colorize.rb +39 -11
- data/lib/constants.rb +17 -0
- data/lib/directory_searcher.rb +4 -2
- data/lib/doh.rb +190 -0
- data/lib/env.rb +1 -1
- data/lib/exceptions.rb +9 -6
- data/lib/fcb.rb +0 -199
- data/lib/filter.rb +18 -5
- data/lib/find_files.rb +8 -3
- data/lib/format_table.rb +406 -0
- data/lib/hash_delegator.rb +888 -603
- data/lib/hierarchy_string.rb +113 -25
- data/lib/input_sequencer.rb +16 -10
- data/lib/instance_method_wrapper.rb +2 -1
- data/lib/layered_hash.rb +143 -0
- data/lib/link_history.rb +22 -8
- data/lib/markdown_exec/version.rb +1 -1
- data/lib/markdown_exec.rb +413 -165
- data/lib/mdoc.rb +27 -34
- data/lib/menu.src.yml +825 -710
- data/lib/menu.yml +799 -703
- data/lib/namer.rb +6 -12
- data/lib/object_present.rb +1 -1
- data/lib/option_value.rb +7 -3
- data/lib/poly.rb +33 -14
- data/lib/resize_terminal.rb +60 -52
- data/lib/saved_assets.rb +45 -34
- data/lib/saved_files_matcher.rb +6 -3
- data/lib/streams_out.rb +7 -1
- data/lib/table_extractor.rb +166 -0
- data/lib/tap.rb +5 -6
- data/lib/text_analyzer.rb +144 -8
- metadata +26 -3
- data/lib/std_out_err_logger.rb +0 -119
data/lib/namer.rb
CHANGED
@@ -3,7 +3,6 @@
|
|
3
3
|
|
4
4
|
# encoding=utf-8
|
5
5
|
require 'digest'
|
6
|
-
# require_relative 'poly'
|
7
6
|
|
8
7
|
$pd = false unless defined?($pd)
|
9
8
|
|
@@ -11,7 +10,9 @@ class Hash
|
|
11
10
|
# block name in commands and documents
|
12
11
|
def pub_name(**kwargs)
|
13
12
|
full = fetch(:nickname, nil) || fetch(:oname, nil)
|
14
|
-
full&.to_s&.pub_name(**kwargs).tap { |ret|
|
13
|
+
full&.to_s&.pub_name(**kwargs).tap { |ret|
|
14
|
+
pp [__LINE__, 'Hash.pub_name() ->', ret] if $pd
|
15
|
+
}
|
15
16
|
end
|
16
17
|
end
|
17
18
|
|
@@ -36,15 +37,8 @@ class String
|
|
36
37
|
self
|
37
38
|
end
|
38
39
|
|
39
|
-
trimmed.gsub(pattern, replacement).tap { |ret|
|
40
|
+
trimmed.gsub(pattern, replacement).tap { |ret|
|
41
|
+
pp [__LINE__, 'String.pub_name() ->', ret] if $pd
|
42
|
+
}
|
40
43
|
end
|
41
44
|
end
|
42
|
-
|
43
|
-
# require 'ostruct'
|
44
|
-
|
45
|
-
# class BlkS < OpenStruct
|
46
|
-
# # Method to fetch the value associated with the attribute :nickname or :oname
|
47
|
-
# def pub_name
|
48
|
-
# self.nickname || self.oname
|
49
|
-
# end
|
50
|
-
# end
|
data/lib/object_present.rb
CHANGED
data/lib/option_value.rb
CHANGED
@@ -16,7 +16,7 @@ module MarkdownExec
|
|
16
16
|
return default if value.nil?
|
17
17
|
|
18
18
|
case value
|
19
|
-
when String, Integer
|
19
|
+
when String, Integer, Array, Hash
|
20
20
|
value
|
21
21
|
when TrueClass, FalseClass
|
22
22
|
value ? true : false
|
@@ -64,8 +64,12 @@ if $PROGRAM_NAME == __FILE__
|
|
64
64
|
assert_equal false, MarkdownExec::OptionValue.for_hash(false)
|
65
65
|
end
|
66
66
|
|
67
|
-
def
|
68
|
-
assert_equal
|
67
|
+
def test_for_hash_with_empty_array
|
68
|
+
assert_equal [], MarkdownExec::OptionValue.for_hash([], 'default')
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_for_hash_with_empty_hash
|
72
|
+
assert_equal({}, MarkdownExec::OptionValue.for_hash({}, 'default'))
|
69
73
|
end
|
70
74
|
|
71
75
|
def test_for_yaml_with_string
|
data/lib/poly.rb
CHANGED
@@ -8,7 +8,9 @@ $pd = false
|
|
8
8
|
class Poly
|
9
9
|
# attr_reader :table
|
10
10
|
def initialize(table = {})
|
11
|
-
@table = table.tap{|ret|
|
11
|
+
@table = table.tap { |ret|
|
12
|
+
pp [__LINE__, 'Poly.initialize()', 'table', table.to_yaml] if $pd
|
13
|
+
}
|
12
14
|
end
|
13
15
|
|
14
16
|
def fetch(key, *args)
|
@@ -20,16 +22,21 @@ class Poly
|
|
20
22
|
elsif block_given?
|
21
23
|
yield key_sym
|
22
24
|
elsif args.count.positive?
|
23
|
-
# binding.irb
|
25
|
+
# binding.irb
|
24
26
|
args.first
|
25
27
|
else
|
26
|
-
binding.irb
|
28
|
+
binding.irb
|
27
29
|
raise KeyError, "key not found: #{key}"
|
28
|
-
end.tap{|ret|
|
30
|
+
end.tap { |ret|
|
31
|
+
pp([__LINE__, "Poly.fetch #{key} #{args}", '->',
|
32
|
+
ret]) if $pd
|
33
|
+
}
|
29
34
|
end
|
30
35
|
|
31
36
|
def key?(name)
|
32
|
-
@table.key?(name.to_sym).tap{|ret|
|
37
|
+
@table.key?(name.to_sym).tap { |ret|
|
38
|
+
pp([__LINE__, "Poly.key? #{name}", '->', ret]) if $pd
|
39
|
+
}
|
33
40
|
end
|
34
41
|
|
35
42
|
def method_missing(name, *args)
|
@@ -55,12 +62,17 @@ binding.irb
|
|
55
62
|
else
|
56
63
|
pt = 'table read'
|
57
64
|
@table[name.to_sym]
|
58
|
-
end.tap{|ret|
|
65
|
+
end.tap { |ret|
|
66
|
+
pp([__LINE__,
|
67
|
+
"Poly.method_missing #{name} #{args.map(&:to_s).join(' ')}", pt, '->', ret]) if $pd
|
68
|
+
}
|
59
69
|
end
|
60
70
|
|
61
71
|
def respond_to_missing?(name, include_private = false)
|
62
72
|
# name.to_s.end_with?('=') || @table.key?(name.to_sym) || @table.respond_to?(name) || super
|
63
|
-
(name.to_s.end_with?('=') || @table.key?(name.to_sym) || @table.respond_to?(name) || super).tap{|ret|
|
73
|
+
(name.to_s.end_with?('=') || @table.key?(name.to_sym) || @table.respond_to?(name) || super).tap { |ret|
|
74
|
+
pp([__LINE__, "Poly.respond_to_missing? #{name}", '->', ret]) if $pd
|
75
|
+
}
|
64
76
|
end
|
65
77
|
|
66
78
|
def [](key)
|
@@ -68,7 +80,7 @@ binding.irb
|
|
68
80
|
send("get_#{key}")
|
69
81
|
else
|
70
82
|
@table[key.to_sym]
|
71
|
-
end.tap{|ret| pp([__LINE__,"Poly.[] #{key}",'->',ret]) if $pd }
|
83
|
+
end.tap { |ret| pp([__LINE__, "Poly.[] #{key}", '->', ret]) if $pd }
|
72
84
|
end
|
73
85
|
|
74
86
|
def []=(key, value)
|
@@ -76,7 +88,10 @@ binding.irb
|
|
76
88
|
send("set_#{key}", value)
|
77
89
|
else
|
78
90
|
@table[key.to_sym] = value
|
79
|
-
end.tap{|ret|
|
91
|
+
end.tap { |ret|
|
92
|
+
pp([__LINE__, "Poly.[]= #{key} #{value}", '->',
|
93
|
+
ret]) if $pd
|
94
|
+
}
|
80
95
|
end
|
81
96
|
|
82
97
|
# for export to Prompt library
|
@@ -84,18 +99,22 @@ binding.irb
|
|
84
99
|
# Proc.new { |x| @table.merge x }
|
85
100
|
# end
|
86
101
|
def merge(*args)
|
87
|
-
# pp caller
|
88
|
-
# binding.irb
|
89
|
-
@table.merge(*args).tap{|ret|
|
102
|
+
# pp caller
|
103
|
+
# binding.irb
|
104
|
+
@table.merge(*args).tap { |ret|
|
105
|
+
pp([__LINE__, "Poly.merge", '->', ret]) if $pd
|
106
|
+
}
|
90
107
|
end
|
91
108
|
|
92
109
|
# for export to Prompt library
|
93
110
|
def to_h
|
94
|
-
@table.tap{|ret| pp([__LINE__,"Poly.to_h",'->',ret]) if $pd }
|
111
|
+
@table.tap { |ret| pp([__LINE__, "Poly.to_h", '->', ret]) if $pd }
|
95
112
|
end
|
96
113
|
|
97
114
|
def to_yaml
|
98
|
-
@table.to_yaml.tap{|ret|
|
115
|
+
@table.to_yaml.tap { |ret|
|
116
|
+
pp([__LINE__, "Poly.to_yaml", '->', ret]) if $pd
|
117
|
+
}
|
99
118
|
end
|
100
119
|
end
|
101
120
|
|
data/lib/resize_terminal.rb
CHANGED
@@ -10,60 +10,66 @@ require 'timeout'
|
|
10
10
|
# If so, it sends escape sequences to query the terminal size and reads the response.
|
11
11
|
# It then compares the current terminal size with the calculated size and adjusts if necessary.
|
12
12
|
# If the terminal emulator is unsupported, it prints an error message.
|
13
|
-
|
13
|
+
# 2024-8-23 add require_stdout to allow for testing
|
14
|
+
def resize_terminal(show_dims: false, show_rectangle: false,
|
15
|
+
require_stdout: true)
|
14
16
|
# Check if running in an interactive terminal and no arguments are provided
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
$stdout.flush
|
20
|
-
|
21
|
-
# Read the response from the terminal
|
22
|
-
response = String.new
|
23
|
-
Timeout.timeout(5) do
|
24
|
-
loop do
|
25
|
-
char = $stdin.getch
|
26
|
-
response << char
|
27
|
-
break if response.include?('R')
|
28
|
-
end
|
29
|
-
end
|
17
|
+
unless $stdin.tty?
|
18
|
+
warn 'Usage: resize_terminal'
|
19
|
+
return
|
20
|
+
end
|
30
21
|
|
31
|
-
|
32
|
-
warn "Error: No response received from terminal. Response: #{response.inspect}"
|
33
|
-
return 1
|
34
|
-
end
|
22
|
+
return if require_stdout && !$stdout.tty?
|
35
23
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
24
|
+
# Save the current state and send the escape sequence to get the cursor position
|
25
|
+
print "\e7\e[r\e[999;999H\e[6n\e8"
|
26
|
+
$stdout.flush
|
27
|
+
|
28
|
+
# Read the response from the terminal
|
29
|
+
response = String.new
|
30
|
+
Timeout.timeout(5) do
|
31
|
+
loop do
|
32
|
+
char = $stdin.getch
|
33
|
+
response << char
|
34
|
+
break if response.include?('R')
|
35
|
+
end
|
36
|
+
end
|
42
37
|
|
43
|
-
|
38
|
+
if response.empty?
|
39
|
+
warn "Error: No response received from terminal. Response: #{response.inspect}"
|
40
|
+
return 1
|
41
|
+
end
|
44
42
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
warn "Error: Calculated terminal size is invalid. Columns: #{calculated_columns}, Rows: #{calculated_rows}"
|
52
|
-
return 1
|
53
|
-
end
|
43
|
+
# Match the response to extract the terminal dimensions
|
44
|
+
match_data = response.match(/\[(\d+);(\d+)R/)
|
45
|
+
unless match_data
|
46
|
+
warn "Error: Failed to match terminal response pattern. Response: #{response.inspect}"
|
47
|
+
return 1
|
48
|
+
end
|
54
49
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
50
|
+
calculated_rows, calculated_columns = match_data.captures.map(&:to_i)
|
51
|
+
|
52
|
+
if ENV['COLUMNS'].to_i == calculated_columns && ENV['LINES'].to_i == calculated_rows
|
53
|
+
puts "#{ENV.fetch('TERM', nil)} #{calculated_columns}x#{calculated_rows}"
|
54
|
+
elsif calculated_columns.positive? && calculated_rows.positive?
|
55
|
+
warn "#{ENV.fetch('COLUMNS',
|
56
|
+
nil)}x#{ENV.fetch('LINES',
|
57
|
+
nil)} -> #{calculated_columns}x#{calculated_rows}" if show_dims
|
58
|
+
system("stty cols #{calculated_columns} rows #{calculated_rows}")
|
64
59
|
else
|
65
|
-
warn
|
60
|
+
warn "Error: Calculated terminal size is invalid. Columns: #{calculated_columns}, Rows: #{calculated_rows}"
|
61
|
+
return 1
|
66
62
|
end
|
63
|
+
|
64
|
+
# Display a text rectangle if the option is enabled
|
65
|
+
display_terminal_rectangle(calculated_columns,
|
66
|
+
calculated_rows) if show_rectangle
|
67
|
+
rescue Timeout::Error
|
68
|
+
warn 'Error: Timeout while reading terminal response. Unsupported terminal emulator.'
|
69
|
+
1
|
70
|
+
rescue StandardError => err
|
71
|
+
warn "Error: #{err.message}. Unsupported terminal emulator."
|
72
|
+
1
|
67
73
|
end
|
68
74
|
|
69
75
|
# This function draws a rectangle of the given width and height
|
@@ -119,7 +125,7 @@ class ResizeTerminalTest < Minitest::Test
|
|
119
125
|
$stdin.stub(:getch, -> { response.slice!(0) || '' }) do
|
120
126
|
assert_output("\e7\e[r\e[999;999H\e[6n\e8xterm-256color #{columns}x24\n") do
|
121
127
|
# assert_output('', '') do
|
122
|
-
resize_terminal
|
128
|
+
resize_terminal(require_stdout: false)
|
123
129
|
end
|
124
130
|
end
|
125
131
|
end
|
@@ -131,8 +137,9 @@ class ResizeTerminalTest < Minitest::Test
|
|
131
137
|
ARGV.replace([])
|
132
138
|
$stdin.stub(:getch, -> { '' }) do
|
133
139
|
# assert_output(nil, /Error: No response received from terminal/) do
|
134
|
-
assert_output(nil,
|
135
|
-
|
140
|
+
assert_output(nil,
|
141
|
+
"Error: Timeout while reading terminal response. Unsupported terminal emulator.\n") do
|
142
|
+
assert_equal 1, resize_terminal(require_stdout: false)
|
136
143
|
end
|
137
144
|
end
|
138
145
|
end
|
@@ -144,8 +151,9 @@ class ResizeTerminalTest < Minitest::Test
|
|
144
151
|
ARGV.replace([])
|
145
152
|
response = "\e[999;999H\e[6n\e[InvalidResponse".dup
|
146
153
|
$stdin.stub(:getch, -> { response.slice!(0) || '' }) do
|
147
|
-
assert_output(nil,
|
148
|
-
|
154
|
+
assert_output(nil,
|
155
|
+
/Error: Failed to match terminal response pattern/) do
|
156
|
+
assert_equal 1, resize_terminal(require_stdout: false)
|
149
157
|
end
|
150
158
|
end
|
151
159
|
end
|
@@ -157,7 +165,7 @@ class ResizeTerminalTest < Minitest::Test
|
|
157
165
|
ARGV.replace([])
|
158
166
|
Timeout.stub(:timeout, ->(_) { raise Timeout::Error }) do
|
159
167
|
assert_output(nil, /Error: Timeout while reading terminal response/) do
|
160
|
-
assert_equal 1, resize_terminal
|
168
|
+
assert_equal 1, resize_terminal(require_stdout: false)
|
161
169
|
end
|
162
170
|
end
|
163
171
|
end
|
data/lib/saved_assets.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
|
4
4
|
# encoding=utf-8
|
5
5
|
require_relative 'namer'
|
6
|
+
require_relative 'object_present'
|
6
7
|
|
7
8
|
module MarkdownExec
|
8
9
|
# SavedAsset
|
@@ -25,16 +26,15 @@ module MarkdownExec
|
|
25
26
|
# @param ftime [String] the time format (default: DEFAULT_FTIME)
|
26
27
|
# @param exts [String] the extension to append (default: '.sh')
|
27
28
|
def initialize(
|
28
|
-
saved_asset_format:,
|
29
|
-
ftime: DEFAULT_FTIME,
|
30
|
-
mark: nil,
|
29
|
+
saved_asset_format:, blockname: nil, exts: nil,
|
30
|
+
filename: nil, ftime: DEFAULT_FTIME, join_str: nil,
|
31
|
+
mark: nil, prefix: nil, time: nil
|
31
32
|
)
|
32
|
-
@filename = filename ? filename.pub_name : '*'
|
33
|
-
@prefix = prefix || '*'
|
34
|
-
@time = time ? time.strftime(ftime) : '*'
|
35
|
-
@blockname = blockname ? blockname.pub_name : '*'
|
36
|
-
|
37
|
-
@exts = exts || '.*' # [String] the extension to append (default: '.sh')
|
33
|
+
@filename = filename.present? ? filename.pub_name : '*'
|
34
|
+
@prefix = prefix || '*'
|
35
|
+
@time = time ? time.strftime(ftime) : '*'
|
36
|
+
@blockname = blockname ? blockname.pub_name : '*'
|
37
|
+
@exts = exts || '.*'
|
38
38
|
@mark = mark || MARK_STR
|
39
39
|
@join_str = join_str || JOIN_STR
|
40
40
|
@saved_asset_format = saved_asset_format
|
@@ -64,6 +64,9 @@ return if $PROGRAM_NAME != __FILE__
|
|
64
64
|
|
65
65
|
require 'minitest/autorun'
|
66
66
|
|
67
|
+
SAVED_ASSET_FORMAT = '%{prefix}%{join}%{time}%{join}%{filename}%{join}' \
|
68
|
+
'%{mark}%{join}%{blockname}%{join}%{exts}'
|
69
|
+
|
67
70
|
class SavedAssetTest < Minitest::Test
|
68
71
|
def test_script_name_with_special_characters_in_blockname
|
69
72
|
filename = 'sample.txt'
|
@@ -71,10 +74,11 @@ class SavedAssetTest < Minitest::Test
|
|
71
74
|
time = Time.new(2023, 1, 1, 12, 0, 0)
|
72
75
|
blockname = 'block/1:2'
|
73
76
|
|
74
|
-
expected_name = 'test_2023-01-01-12-00-00_sample_txt_
|
75
|
-
assert_equal expected_name, MarkdownExec::SavedAsset.
|
76
|
-
filename: filename, prefix: prefix,
|
77
|
-
|
77
|
+
expected_name = 'test_2023-01-01-12-00-00_sample_txt_~_block_1_2_.*'
|
78
|
+
assert_equal expected_name, MarkdownExec::SavedAsset.new(
|
79
|
+
blockname: blockname, filename: filename, prefix: prefix,
|
80
|
+
saved_asset_format: SAVED_ASSET_FORMAT, time: time
|
81
|
+
).generate_name
|
78
82
|
end
|
79
83
|
|
80
84
|
def test_stdout_name_with_special_characters_in_blockname
|
@@ -83,10 +87,11 @@ class SavedAssetTest < Minitest::Test
|
|
83
87
|
time = Time.new(2023, 1, 1, 12, 0, 0)
|
84
88
|
blockname = 'block/1:2'
|
85
89
|
|
86
|
-
expected_name = 'test_2023-01-01-12-00-00_sample_txt_
|
87
|
-
assert_equal expected_name, MarkdownExec::SavedAsset.
|
90
|
+
expected_name = 'test_2023-01-01-12-00-00_sample_txt_~_block_1_2_.*'
|
91
|
+
assert_equal expected_name, MarkdownExec::SavedAsset.new(
|
92
|
+
saved_asset_format: SAVED_ASSET_FORMAT,
|
88
93
|
filename: filename, prefix: prefix, time: time, blockname: blockname
|
89
|
-
)
|
94
|
+
).generate_name
|
90
95
|
end
|
91
96
|
|
92
97
|
def test_wildcard_name_with_all_parameters
|
@@ -94,11 +99,12 @@ class SavedAssetTest < Minitest::Test
|
|
94
99
|
prefix = 'test'
|
95
100
|
time = Time.new(2023, 1, 1, 12, 0, 0)
|
96
101
|
blockname = 'block/1:2'
|
97
|
-
expected_wildcard = 'test_2023-01-01-12-00-00_sample_txt_
|
102
|
+
expected_wildcard = 'test_2023-01-01-12-00-00_sample_txt_~_block_1_2_.*'
|
98
103
|
|
99
|
-
assert_equal expected_wildcard, MarkdownExec::SavedAsset.
|
104
|
+
assert_equal expected_wildcard, MarkdownExec::SavedAsset.new(
|
105
|
+
saved_asset_format: SAVED_ASSET_FORMAT,
|
100
106
|
filename: filename, prefix: prefix, time: time, blockname: blockname
|
101
|
-
)
|
107
|
+
).generate_name
|
102
108
|
end
|
103
109
|
|
104
110
|
def test_wildcard_name_with_missing_time
|
@@ -106,11 +112,12 @@ class SavedAssetTest < Minitest::Test
|
|
106
112
|
prefix = 'test'
|
107
113
|
time = nil
|
108
114
|
blockname = 'block/1:2'
|
109
|
-
expected_wildcard = 'test_*_sample_txt_
|
115
|
+
expected_wildcard = 'test_*_sample_txt_~_block_1_2_.*'
|
110
116
|
|
111
|
-
assert_equal expected_wildcard, MarkdownExec::SavedAsset.
|
117
|
+
assert_equal expected_wildcard, MarkdownExec::SavedAsset.new(
|
118
|
+
saved_asset_format: SAVED_ASSET_FORMAT,
|
112
119
|
filename: filename, prefix: prefix, time: time, blockname: blockname
|
113
|
-
)
|
120
|
+
).generate_name
|
114
121
|
end
|
115
122
|
|
116
123
|
def test_wildcard_name_with_missing_filename
|
@@ -118,11 +125,12 @@ class SavedAssetTest < Minitest::Test
|
|
118
125
|
prefix = 'test'
|
119
126
|
time = Time.new(2023, 1, 1, 12, 0, 0)
|
120
127
|
blockname = 'block/1:2'
|
121
|
-
expected_wildcard = 'test_2023-01-01-12-00-00_*_
|
128
|
+
expected_wildcard = 'test_2023-01-01-12-00-00_*_~_block_1_2_.*'
|
122
129
|
|
123
|
-
assert_equal expected_wildcard, MarkdownExec::SavedAsset.
|
130
|
+
assert_equal expected_wildcard, MarkdownExec::SavedAsset.new(
|
131
|
+
saved_asset_format: SAVED_ASSET_FORMAT,
|
124
132
|
filename: filename, prefix: prefix, time: time, blockname: blockname
|
125
|
-
)
|
133
|
+
).generate_name
|
126
134
|
end
|
127
135
|
|
128
136
|
def test_wildcard_name_with_missing_prefix
|
@@ -130,11 +138,12 @@ class SavedAssetTest < Minitest::Test
|
|
130
138
|
prefix = nil
|
131
139
|
time = Time.new(2023, 1, 1, 12, 0, 0)
|
132
140
|
blockname = 'block/1:2'
|
133
|
-
expected_wildcard = '*_2023-01-01-12-00-00_sample_txt_
|
141
|
+
expected_wildcard = '*_2023-01-01-12-00-00_sample_txt_~_block_1_2_.*'
|
134
142
|
|
135
|
-
assert_equal expected_wildcard, MarkdownExec::SavedAsset.
|
143
|
+
assert_equal expected_wildcard, MarkdownExec::SavedAsset.new(
|
144
|
+
saved_asset_format: SAVED_ASSET_FORMAT,
|
136
145
|
filename: filename, prefix: prefix, time: time, blockname: blockname
|
137
|
-
)
|
146
|
+
).generate_name
|
138
147
|
end
|
139
148
|
|
140
149
|
def test_wildcard_name_with_missing_blockname
|
@@ -142,11 +151,12 @@ class SavedAssetTest < Minitest::Test
|
|
142
151
|
prefix = 'test'
|
143
152
|
time = Time.new(2023, 1, 1, 12, 0, 0)
|
144
153
|
blockname = nil
|
145
|
-
expected_wildcard = 'test_2023-01-01-12-00-00_sample_txt_
|
154
|
+
expected_wildcard = 'test_2023-01-01-12-00-00_sample_txt_~_*_.*'
|
146
155
|
|
147
|
-
assert_equal expected_wildcard, MarkdownExec::SavedAsset.
|
156
|
+
assert_equal expected_wildcard, MarkdownExec::SavedAsset.new(
|
157
|
+
saved_asset_format: SAVED_ASSET_FORMAT,
|
148
158
|
filename: filename, prefix: prefix, time: time, blockname: blockname
|
149
|
-
)
|
159
|
+
).generate_name
|
150
160
|
end
|
151
161
|
|
152
162
|
def test_wildcard_name_with_all_missing
|
@@ -154,10 +164,11 @@ class SavedAssetTest < Minitest::Test
|
|
154
164
|
prefix = nil
|
155
165
|
time = nil
|
156
166
|
blockname = nil
|
157
|
-
expected_wildcard = '*_*_*_
|
167
|
+
expected_wildcard = '*_*_*_~_*_.*'
|
158
168
|
|
159
|
-
assert_equal expected_wildcard, MarkdownExec::SavedAsset.
|
169
|
+
assert_equal expected_wildcard, MarkdownExec::SavedAsset.new(
|
170
|
+
saved_asset_format: SAVED_ASSET_FORMAT,
|
160
171
|
filename: filename, prefix: prefix, time: time, blockname: blockname
|
161
|
-
)
|
172
|
+
).generate_name
|
162
173
|
end
|
163
174
|
end
|
data/lib/saved_files_matcher.rb
CHANGED
@@ -45,15 +45,18 @@ if $PROGRAM_NAME == __FILE__
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def test_list_all
|
48
|
-
assert_kind_of Array,
|
48
|
+
assert_kind_of Array,
|
49
|
+
MarkdownExec::SavedFilesMatcher.list_all(@folder, @glob)
|
49
50
|
end
|
50
51
|
|
51
52
|
def test_most_recent
|
52
|
-
assert_match(/\.md$/,
|
53
|
+
assert_match(/\.md$/,
|
54
|
+
MarkdownExec::SavedFilesMatcher.most_recent(@folder, @glob))
|
53
55
|
end
|
54
56
|
|
55
57
|
def test_most_recent_list
|
56
|
-
result = MarkdownExec::SavedFilesMatcher.most_recent_list(@folder, @glob,
|
58
|
+
result = MarkdownExec::SavedFilesMatcher.most_recent_list(@folder, @glob,
|
59
|
+
5)
|
57
60
|
assert_kind_of Array, result
|
58
61
|
assert_operator result.size, :<=, 16
|
59
62
|
end
|
data/lib/streams_out.rb
CHANGED
@@ -11,7 +11,13 @@ class StreamsOut
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def append_stream_line(stream, line)
|
14
|
-
@streams <<
|
14
|
+
@streams << OpenStruct.new(stream: stream, line: line, timestamp: Time.now)
|
15
|
+
end
|
16
|
+
|
17
|
+
def stream_lines(stream)
|
18
|
+
@streams.select do |v|
|
19
|
+
v[:stream] == stream
|
20
|
+
end.map(&:line)
|
15
21
|
end
|
16
22
|
|
17
23
|
def write_execution_output_to_file(filespec)
|