markdown_exec 2.0.2 → 2.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/Gemfile +0 -2
- data/Gemfile.lock +1 -1
- data/bin/tab_completion.sh +2 -2
- data/examples/linked.md +5 -0
- data/lib/ansi_formatter.rb +8 -4
- data/lib/directory_searcher.rb +1 -1
- data/lib/hash_delegator.rb +194 -92
- data/lib/input_sequencer.rb +6 -1
- data/lib/markdown_exec/version.rb +1 -1
- data/lib/markdown_exec.rb +0 -1
- data/lib/menu.src.yml +32 -38
- data/lib/menu.yml +27 -27
- data/lib/saved_assets.rb +27 -25
- data/lib/std_out_err_logger.rb +121 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b67dcb867789b2a348645d74be064f2f596be8821f1174ceb736151ac7565732
|
4
|
+
data.tar.gz: 390919d82d1dcadb508edf926235269a96f6f30aee75d3b0368bc8c8ecfc94e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e0294e1c0eff38cd85d4917144bc41c407fea45b4fa89e680345c346873743c99565edaa1d224184a6b1a7106d1c6fe2d6cf77236cf63f98881bed2096812a1b
|
7
|
+
data.tar.gz: 23a6b99a7e205d60c6667c23a95acfd476dd36ab54192a183786a56773edf1e44cb803bef20afd2f86c13e237d2494c07a22cc4e9857cff1ae5dd41f73ebadeb
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [2.0.3] - 2024-04-15
|
4
|
+
|
5
|
+
### Added
|
6
|
+
|
7
|
+
- Option to set menu line count to fill console height.
|
8
|
+
- Rescue when named block in link block is missing.
|
9
|
+
|
10
|
+
### Changed
|
11
|
+
|
12
|
+
- Fix handling of variables with spaces in link blocks.
|
13
|
+
- Fix substitution for '/' in block names used in file names.
|
14
|
+
|
3
15
|
## [2.0.2] - 2024-02-09
|
4
16
|
|
5
17
|
### Changed
|
data/Gemfile
CHANGED
@@ -9,7 +9,6 @@ gemspec
|
|
9
9
|
gem 'clipboard'
|
10
10
|
gem 'debug'
|
11
11
|
gem 'erb'
|
12
|
-
# gem 'httparty' # 2024-01-01 for ChatGPI API
|
13
12
|
gem 'irb', '>= 1.8.0'
|
14
13
|
gem 'mocha', require: false
|
15
14
|
gem 'minitest', require: false
|
@@ -24,6 +23,5 @@ gem 'rubocop-minitest', require: false
|
|
24
23
|
gem 'rubocop-rake', require: false
|
25
24
|
gem 'rubocop-rspec', require: false
|
26
25
|
gem 'shellwords'
|
27
|
-
# gem 'tty-file'
|
28
26
|
gem 'uri', '0.12.2'
|
29
27
|
gem 'yaml', '~> 0.2.1'
|
data/Gemfile.lock
CHANGED
data/bin/tab_completion.sh
CHANGED
@@ -13,7 +13,7 @@ __filedirs_all()
|
|
13
13
|
}
|
14
14
|
|
15
15
|
_mde_echo_version() {
|
16
|
-
echo "2.0.
|
16
|
+
echo "2.0.3"
|
17
17
|
}
|
18
18
|
|
19
19
|
_mde() {
|
@@ -186,4 +186,4 @@ _mde() {
|
|
186
186
|
|
187
187
|
complete -o filenames -o nospace -F _mde mde
|
188
188
|
# _mde_echo_version
|
189
|
-
# echo "Updated: 2024-
|
189
|
+
# echo "Updated: 2024-04-17 23:39:50 UTC"
|
data/examples/linked.md
CHANGED
data/lib/ansi_formatter.rb
CHANGED
@@ -33,11 +33,15 @@ class AnsiFormatter
|
|
33
33
|
def scan_and_process_multiple_substrings(str, substrings, plain_sym, color_sym)
|
34
34
|
return string_send_color(str, plain_sym) if substrings.empty? || substrings.any?(&:empty?)
|
35
35
|
|
36
|
+
substring_patterns = substrings.map do |value|
|
37
|
+
[value, Regexp.new(value, Regexp::IGNORECASE)]
|
38
|
+
end
|
39
|
+
|
36
40
|
results = []
|
37
41
|
remaining_str = str.dup
|
38
42
|
|
39
43
|
while remaining_str.length.positive?
|
40
|
-
match_indices =
|
44
|
+
match_indices = substring_patterns.map { |_, pattern| remaining_str.index(pattern) }.compact
|
41
45
|
earliest_match = match_indices.min
|
42
46
|
|
43
47
|
if earliest_match
|
@@ -48,12 +52,12 @@ class AnsiFormatter
|
|
48
52
|
end
|
49
53
|
|
50
54
|
# Find which substring has this earliest match
|
51
|
-
matching_substring =
|
52
|
-
remaining_str.index(
|
55
|
+
matching_substring = substring_patterns.find do |_, pattern|
|
56
|
+
remaining_str.index(pattern) == earliest_match
|
53
57
|
end
|
54
58
|
|
55
59
|
if matching_substring
|
56
|
-
matching_segment = remaining_str.slice!(0...matching_substring.length)
|
60
|
+
matching_segment = remaining_str.slice!(0...matching_substring[0].length)
|
57
61
|
results << string_send_color(matching_segment, color_sym)
|
58
62
|
end
|
59
63
|
else
|
data/lib/directory_searcher.rb
CHANGED
@@ -102,7 +102,7 @@ class DirectorySearcher
|
|
102
102
|
# @param include_subdirectories [Boolean] Whether to search in subdirectories.
|
103
103
|
# @param filename_glob [String, nil] Glob pattern for file names.
|
104
104
|
def initialize(pattern, paths, include_subdirectories: true, filename_glob: '*.[Mm][Dd]') #'*.md'
|
105
|
-
@pattern = pattern
|
105
|
+
@pattern = Regexp.new(pattern, Regexp::IGNORECASE)
|
106
106
|
@paths = paths
|
107
107
|
@include_subdirectories = include_subdirectories
|
108
108
|
@filename_glob = filename_glob
|
data/lib/hash_delegator.rb
CHANGED
@@ -11,7 +11,6 @@ require 'optparse'
|
|
11
11
|
require 'set'
|
12
12
|
require 'shellwords'
|
13
13
|
require 'tmpdir'
|
14
|
-
# require 'tty-file'
|
15
14
|
require 'tty-prompt'
|
16
15
|
require 'yaml'
|
17
16
|
|
@@ -21,6 +20,7 @@ require_relative 'block_label'
|
|
21
20
|
require_relative 'block_types'
|
22
21
|
require_relative 'cached_nested_file_reader'
|
23
22
|
require_relative 'constants'
|
23
|
+
require_relative 'std_out_err_logger'
|
24
24
|
require_relative 'directory_searcher'
|
25
25
|
require_relative 'exceptions'
|
26
26
|
require_relative 'fcb'
|
@@ -193,18 +193,15 @@ module HashDelegatorSelf
|
|
193
193
|
end
|
194
194
|
|
195
195
|
def next_link_state(block_name_from_cli:, was_using_cli:, block_state:, block_name: nil)
|
196
|
-
# &bsp 'next_link_state', block_name_from_cli, was_using_cli, block_state
|
197
196
|
# Set block_name based on block_name_from_cli
|
198
197
|
block_name = @cli_block_name if block_name_from_cli
|
199
|
-
# &bsp 'block_name:', block_name
|
200
198
|
|
201
199
|
# Determine the state of breaker based on was_using_cli and the block type
|
200
|
+
# true only when block_name is nil, block_name_from_cli is false, was_using_cli is true, and the block_state.block[:shell] equals BlockType::BASH. In all other scenarios, breaker is false.
|
202
201
|
breaker = !block_name && !block_name_from_cli && was_using_cli && block_state.block[:shell] == BlockType::BASH
|
203
|
-
# &bsp 'breaker:', breaker
|
204
202
|
|
205
203
|
# Reset block_name_from_cli if the conditions are not met
|
206
204
|
block_name_from_cli ||= false
|
207
|
-
# &bsp 'block_name_from_cli:', block_name_from_cli
|
208
205
|
|
209
206
|
[block_name, block_name_from_cli, breaker]
|
210
207
|
end
|
@@ -352,6 +349,20 @@ module CompactionHelpers
|
|
352
349
|
end
|
353
350
|
end
|
354
351
|
|
352
|
+
module PathUtils
|
353
|
+
# Determines if a given path is absolute or substitutes a placeholder in an expression with the path.
|
354
|
+
# @param path [String] The input path to check or fill in.
|
355
|
+
# @param expression [String] The expression where a wildcard '*' is replaced by the path if it's not absolute.
|
356
|
+
# @return [String] The absolute path or the expression with the wildcard replaced by the path.
|
357
|
+
def self.resolve_path_or_substitute(path, expression)
|
358
|
+
if path.include?('/')
|
359
|
+
path
|
360
|
+
else
|
361
|
+
expression.gsub('*', path)
|
362
|
+
end
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
355
366
|
module MarkdownExec
|
356
367
|
class DebugHelper
|
357
368
|
# Class-level variable to store history of printed messages
|
@@ -368,7 +379,7 @@ module MarkdownExec
|
|
368
379
|
end
|
369
380
|
end
|
370
381
|
|
371
|
-
class
|
382
|
+
class HashDelegatorParent
|
372
383
|
attr_accessor :most_recent_loaded_filename, :pass_args, :run_state
|
373
384
|
|
374
385
|
extend HashDelegatorSelf
|
@@ -559,11 +570,11 @@ module MarkdownExec
|
|
559
570
|
|
560
571
|
# private
|
561
572
|
|
562
|
-
def calc_logged_stdout_filename
|
573
|
+
def calc_logged_stdout_filename(block_name:)
|
563
574
|
return unless @delegate_object[:saved_stdout_folder]
|
564
575
|
|
565
576
|
@delegate_object[:logged_stdout_filename] =
|
566
|
-
SavedAsset.stdout_name(blockname:
|
577
|
+
SavedAsset.stdout_name(blockname: block_name,
|
567
578
|
filename: File.basename(@delegate_object[:filename],
|
568
579
|
'.*'),
|
569
580
|
prefix: @delegate_object[:logged_stdout_filename_prefix],
|
@@ -898,7 +909,7 @@ module MarkdownExec
|
|
898
909
|
# @param selected [FCB] The selected functional code block object.
|
899
910
|
def execute_required_lines(required_lines: [], selected: FCB.new)
|
900
911
|
write_command_file(required_lines: required_lines, selected: selected) if @delegate_object[:save_executed_script]
|
901
|
-
calc_logged_stdout_filename
|
912
|
+
calc_logged_stdout_filename(block_name: @dml_block_state.block[:oname]) if @dml_block_state
|
902
913
|
format_and_execute_command(code_lines: required_lines)
|
903
914
|
post_execution_process
|
904
915
|
end
|
@@ -950,7 +961,6 @@ module MarkdownExec
|
|
950
961
|
next_load_file: LoadFile::Reuse
|
951
962
|
)
|
952
963
|
|
953
|
-
|
954
964
|
elsif selected[:shell] == BlockType::VARS
|
955
965
|
debounce_reset
|
956
966
|
block_names = []
|
@@ -972,6 +982,7 @@ module MarkdownExec
|
|
972
982
|
selected: selected,
|
973
983
|
link_state: link_state,
|
974
984
|
block_source: block_source)
|
985
|
+
|
975
986
|
else
|
976
987
|
LoadFileLinkState.new(LoadFile::Reuse, link_state)
|
977
988
|
end
|
@@ -1132,42 +1143,47 @@ module MarkdownExec
|
|
1132
1143
|
def link_block_data_eval(link_state, code_lines, selected, link_block_data, block_source:)
|
1133
1144
|
all_code = HashDelegator.code_merge(link_state&.inherited_lines, code_lines)
|
1134
1145
|
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1146
|
+
Tempfile.open do |file|
|
1147
|
+
file.write(all_code.join("\n"))
|
1148
|
+
file.rewind
|
1138
1149
|
|
1139
|
-
|
1140
|
-
@
|
1141
|
-
|
1142
|
-
) do |stdin, stdout, stderr, _exec_thr|
|
1143
|
-
handle_stream(stream: stdout, file_type: ExecutionStreams::StdOut) do |line|
|
1144
|
-
output_lines.push(line)
|
1145
|
-
end
|
1146
|
-
handle_stream(stream: stderr, file_type: ExecutionStreams::StdErr) do |line|
|
1147
|
-
output_lines.push(line)
|
1148
|
-
end
|
1150
|
+
if link_block_data.fetch(LinkKeys::Exec, false)
|
1151
|
+
@run_state.files = Hash.new([])
|
1152
|
+
output_lines = []
|
1149
1153
|
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1154
|
+
Open3.popen3(
|
1155
|
+
"#{@delegate_object[:shell]} #{file.path}"
|
1156
|
+
) do |stdin, stdout, stderr, _exec_thr|
|
1157
|
+
handle_stream(stream: stdout, file_type: ExecutionStreams::StdOut) do |line|
|
1158
|
+
output_lines.push(line)
|
1159
|
+
end
|
1160
|
+
handle_stream(stream: stderr, file_type: ExecutionStreams::StdErr) do |line|
|
1161
|
+
output_lines.push(line)
|
1162
|
+
end
|
1153
1163
|
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
end
|
1164
|
+
in_thr = handle_stream(stream: $stdin, file_type: ExecutionStreams::StdIn) do |line|
|
1165
|
+
stdin.puts(line)
|
1166
|
+
end
|
1158
1167
|
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
begin_pattern: @delegate_object.fetch(:output_assignment_begin, nil),
|
1164
|
-
end_pattern: @delegate_object.fetch(:output_assignment_end, nil),
|
1165
|
-
scan1: @delegate_object.fetch(:output_assignment_match, nil),
|
1166
|
-
format1: @delegate_object.fetch(:output_assignment_format, nil)
|
1167
|
-
)
|
1168
|
+
wait_for_stream_processing
|
1169
|
+
sleep 0.1
|
1170
|
+
in_thr.kill if in_thr&.alive?
|
1171
|
+
end
|
1168
1172
|
|
1169
|
-
|
1170
|
-
|
1173
|
+
## select output_lines that look like assignment or match other specs
|
1174
|
+
#
|
1175
|
+
output_lines = process_string_array(
|
1176
|
+
output_lines,
|
1177
|
+
begin_pattern: @delegate_object.fetch(:output_assignment_begin, nil),
|
1178
|
+
end_pattern: @delegate_object.fetch(:output_assignment_end, nil),
|
1179
|
+
scan1: @delegate_object.fetch(:output_assignment_match, nil),
|
1180
|
+
format1: @delegate_object.fetch(:output_assignment_format, nil)
|
1181
|
+
)
|
1182
|
+
|
1183
|
+
else
|
1184
|
+
# output_lines = `#{all_code.join("\n")}`.split("\n")
|
1185
|
+
output_lines = `#{@delegate_object[:shell]} #{file.path}`.split("\n")
|
1186
|
+
end
|
1171
1187
|
end
|
1172
1188
|
|
1173
1189
|
HashDelegator.error_handler('all_code eval output_lines is nil', { abort: true }) unless output_lines
|
@@ -1285,7 +1301,7 @@ module MarkdownExec
|
|
1285
1301
|
puts format(@delegate_object[:prompt_show_expr_format],
|
1286
1302
|
{ expr: filespec })
|
1287
1303
|
puts @delegate_object[:prompt_enter_filespec]
|
1288
|
-
resolve_path_or_substitute(gets.chomp, filespec)
|
1304
|
+
PathUtils.resolve_path_or_substitute(gets.chomp, filespec)
|
1289
1305
|
end
|
1290
1306
|
|
1291
1307
|
# Handle expression with wildcard characters
|
@@ -1320,11 +1336,34 @@ module MarkdownExec
|
|
1320
1336
|
}
|
1321
1337
|
end
|
1322
1338
|
|
1339
|
+
# # Loads auto link block.
|
1340
|
+
# def load_auto_link_block(all_blocks, link_state, mdoc, block_source:)
|
1341
|
+
# block_name = @delegate_object[:document_load_link_block_name]
|
1342
|
+
# return unless block_name.present? && @most_recent_loaded_filename != @delegate_object[:filename]
|
1343
|
+
|
1344
|
+
# block = HashDelegator.block_find(all_blocks, :oname, block_name)
|
1345
|
+
# return unless block
|
1346
|
+
|
1347
|
+
# if block.fetch(:shell, '') != BlockType::LINK
|
1348
|
+
# HashDelegator.error_handler('must be Link block type', { abort: true })
|
1349
|
+
|
1350
|
+
# else
|
1351
|
+
# # debounce_reset
|
1352
|
+
# push_link_history_and_trigger_load(
|
1353
|
+
# link_block_body: block.fetch(:body, ''),
|
1354
|
+
# mdoc: mdoc,
|
1355
|
+
# selected: block,
|
1356
|
+
# link_state: link_state,
|
1357
|
+
# block_source: block_source
|
1358
|
+
# )
|
1359
|
+
# end
|
1360
|
+
# end
|
1361
|
+
|
1323
1362
|
# Loads auto blocks based on delegate object settings and updates if new filename is detected.
|
1324
1363
|
# Executes a specified block once per filename.
|
1325
1364
|
# @param all_blocks [Array] Array of all block elements.
|
1326
1365
|
# @return [Boolean, nil] True if values were modified, nil otherwise.
|
1327
|
-
def
|
1366
|
+
def load_auto_opts_block(all_blocks)
|
1328
1367
|
block_name = @delegate_object[:document_load_opts_block_name]
|
1329
1368
|
return unless block_name.present? && @most_recent_loaded_filename != @delegate_object[:filename]
|
1330
1369
|
|
@@ -1354,7 +1393,8 @@ module MarkdownExec
|
|
1354
1393
|
|
1355
1394
|
# recreate menu with new options
|
1356
1395
|
#
|
1357
|
-
all_blocks, mdoc = mdoc_and_blocks_from_nested_files if
|
1396
|
+
all_blocks, mdoc = mdoc_and_blocks_from_nested_files if load_auto_opts_block(all_blocks)
|
1397
|
+
# load_auto_link_block(all_blocks, link_state, mdoc, block_source: {})
|
1358
1398
|
|
1359
1399
|
menu_blocks = mdoc.fcbs_per_options(@delegate_object)
|
1360
1400
|
add_menu_chrome_blocks!(menu_blocks: menu_blocks, link_state: link_state)
|
@@ -1756,18 +1796,6 @@ module MarkdownExec
|
|
1756
1796
|
end
|
1757
1797
|
end
|
1758
1798
|
|
1759
|
-
# Determines if a given path is absolute or substitutes a placeholder in an expression with the path.
|
1760
|
-
# @param path [String] The input path to check or fill in.
|
1761
|
-
# @param expression [String] The expression where a wildcard '*' is replaced by the path if it's not absolute.
|
1762
|
-
# @return [String] The absolute path or the expression with the wildcard replaced by the path.
|
1763
|
-
def resolve_path_or_substitute(path, expression)
|
1764
|
-
if path.include?('/')
|
1765
|
-
path
|
1766
|
-
else
|
1767
|
-
expression.gsub('*', path)
|
1768
|
-
end
|
1769
|
-
end
|
1770
|
-
|
1771
1799
|
def runtime_exception(exception_sym, name, items)
|
1772
1800
|
if @delegate_object[exception_sym] != 0
|
1773
1801
|
data = { name: name, detail: items.join(', ') }
|
@@ -1841,12 +1869,20 @@ module MarkdownExec
|
|
1841
1869
|
@delegate_object[:block_name] = nil
|
1842
1870
|
|
1843
1871
|
when :user_choice
|
1844
|
-
|
1845
|
-
|
1846
|
-
|
1847
|
-
|
1872
|
+
if @dml_link_state.block_name.present?
|
1873
|
+
# @prior_block_was_link = true
|
1874
|
+
@dml_block_state.block = @dml_blocks_in_file.find do |item|
|
1875
|
+
item[:oname] == @dml_link_state.block_name
|
1876
|
+
end
|
1877
|
+
@dml_link_state.block_name = nil
|
1878
|
+
else
|
1879
|
+
# puts "? - Select a block to execute (or type #{$texit} to exit):"
|
1880
|
+
break if ii_user_choice == :break # into @dml_block_state
|
1881
|
+
break if @dml_block_state.block.nil? # no block matched
|
1882
|
+
end
|
1848
1883
|
# puts "! - Executing block: #{data}"
|
1849
|
-
@dml_block_state.block[:oname]
|
1884
|
+
# @dml_block_state.block[:oname]
|
1885
|
+
@dml_block_state.block&.fetch(:oname, nil)
|
1850
1886
|
|
1851
1887
|
when :execute_block
|
1852
1888
|
block_name = data
|
@@ -1888,13 +1924,12 @@ module MarkdownExec
|
|
1888
1924
|
|
1889
1925
|
## order of block name processing: link block, cli, from user
|
1890
1926
|
#
|
1891
|
-
@cli_block_name = block_name
|
1892
1927
|
@dml_link_state.block_name, @run_state.block_name_from_cli, cli_break = \
|
1893
1928
|
HashDelegator.next_link_state(
|
1894
|
-
|
1895
|
-
|
1929
|
+
block_name: @dml_link_state.block_name,
|
1930
|
+
block_name_from_cli: !@dml_link_state.block_name.present?,
|
1896
1931
|
block_state: @dml_block_state,
|
1897
|
-
|
1932
|
+
was_using_cli: @dml_now_using_cli
|
1898
1933
|
)
|
1899
1934
|
|
1900
1935
|
if !@dml_block_state.block[:block_name_from_ui] && cli_break
|
@@ -2282,7 +2317,12 @@ module MarkdownExec
|
|
2282
2317
|
@delegate_object
|
2283
2318
|
end
|
2284
2319
|
|
2285
|
-
|
2320
|
+
sph = @delegate_object[:select_page_height]
|
2321
|
+
unless sph.positive?
|
2322
|
+
require 'io/console'
|
2323
|
+
sph = [IO.console.winsize[0] - 3, 4].max
|
2324
|
+
end
|
2325
|
+
selection_opts.merge!(per_page: sph)
|
2286
2326
|
|
2287
2327
|
selected_option = select_option_with_metadata(prompt_title, block_menu,
|
2288
2328
|
selection_opts)
|
@@ -2331,13 +2371,63 @@ module MarkdownExec
|
|
2331
2371
|
if save_expr.present?
|
2332
2372
|
save_filespec = save_filespec_from_expression(save_expr)
|
2333
2373
|
File.write(save_filespec, HashDelegator.join_code_lines(link_state&.inherited_lines))
|
2334
|
-
# TTY::File.create_file save_filespec, HahDelegator.join_code_lines(link_state&.inherited_lines), force: true
|
2335
2374
|
@delegate_object[:filename]
|
2336
2375
|
else
|
2337
2376
|
link_block_data[LinkKeys::File] || @delegate_object[:filename]
|
2338
2377
|
end
|
2339
2378
|
end
|
2340
2379
|
end
|
2380
|
+
|
2381
|
+
class HashDelegator < HashDelegatorParent
|
2382
|
+
# Cleans a value, handling both Hash and Struct types.
|
2383
|
+
# For Structs, the cleaned version is converted to a hash.
|
2384
|
+
def self.clean_value(value)
|
2385
|
+
case value
|
2386
|
+
when Hash
|
2387
|
+
clean_hash_recursively(value)
|
2388
|
+
when Struct
|
2389
|
+
struct_hash = value.to_h # Convert the Struct to a hash
|
2390
|
+
cleaned_hash = clean_hash_recursively(struct_hash) # Clean the hash
|
2391
|
+
# Return the cleaned hash instead of updating the Struct
|
2392
|
+
return cleaned_hash
|
2393
|
+
else
|
2394
|
+
value
|
2395
|
+
end
|
2396
|
+
end
|
2397
|
+
|
2398
|
+
# Recursively cleans the given object (hash or struct) from unwanted values.
|
2399
|
+
def self.clean_hash_recursively(obj)
|
2400
|
+
obj.each do |key, value|
|
2401
|
+
cleaned_value = clean_value(value) # Clean and possibly convert value
|
2402
|
+
obj[key] = cleaned_value if value.is_a?(Hash) || value.is_a?(Struct)
|
2403
|
+
end
|
2404
|
+
|
2405
|
+
if obj.is_a?(Hash)
|
2406
|
+
obj.select! { |key, value| ![nil, '', [], {}, nil].include?(value) }
|
2407
|
+
end
|
2408
|
+
|
2409
|
+
obj
|
2410
|
+
end
|
2411
|
+
|
2412
|
+
def self.next_link_state(*args, **kwargs, &block)
|
2413
|
+
super
|
2414
|
+
# result = super
|
2415
|
+
|
2416
|
+
# @logger ||= StdOutErrLogger.new
|
2417
|
+
# @logger.unknown(
|
2418
|
+
# HashDelegator.clean_hash_recursively(
|
2419
|
+
# { "HashDelegator.next_link_state":
|
2420
|
+
# { 'args': args,
|
2421
|
+
# 'at': Time.now.strftime('%FT%TZ'),
|
2422
|
+
# 'for': /[^\/]+:\d+/.match(caller.first)[0],
|
2423
|
+
# 'kwargs': kwargs,
|
2424
|
+
# 'return': result } }
|
2425
|
+
# )
|
2426
|
+
# )
|
2427
|
+
|
2428
|
+
# result
|
2429
|
+
end
|
2430
|
+
end
|
2341
2431
|
end
|
2342
2432
|
|
2343
2433
|
return if $PROGRAM_NAME != __FILE__
|
@@ -2348,12 +2438,20 @@ Bundler.require(:default)
|
|
2348
2438
|
require 'minitest/autorun'
|
2349
2439
|
require 'mocha/minitest'
|
2350
2440
|
|
2351
|
-
|
2352
|
-
require_relative 'instance_method_wrapper'
|
2353
|
-
# MarkdownExec::HashDelegator.prepend(InstanceMethodWrapper)
|
2354
|
-
# MarkdownExec::HashDelegator.singleton_class.prepend(ClassMethodWrapper)
|
2441
|
+
require_relative 'std_out_err_logger'
|
2355
2442
|
|
2356
2443
|
module MarkdownExec
|
2444
|
+
class TestHashDelegator0 < Minitest::Test
|
2445
|
+
def setup
|
2446
|
+
@hd = HashDelegator.new
|
2447
|
+
end
|
2448
|
+
|
2449
|
+
# Test case for empty body
|
2450
|
+
def test_next_link_state
|
2451
|
+
@hd.next_link_state(block_name_from_cli: nil, was_using_cli: nil, block_state: nil, block_name: nil)
|
2452
|
+
end
|
2453
|
+
end
|
2454
|
+
|
2357
2455
|
class TestHashDelegator < Minitest::Test
|
2358
2456
|
def setup
|
2359
2457
|
@hd = HashDelegator.new
|
@@ -3194,29 +3292,33 @@ module MarkdownExec
|
|
3194
3292
|
end
|
3195
3293
|
end
|
3196
3294
|
|
3197
|
-
|
3198
|
-
|
3199
|
-
|
3200
|
-
|
3295
|
+
class PathUtilsTest < Minitest::Test
|
3296
|
+
def test_absolute_path_returns_unchanged
|
3297
|
+
absolute_path = "/usr/local/bin"
|
3298
|
+
expression = "path/to/*/directory"
|
3299
|
+
assert_equal absolute_path, PathUtils.resolve_path_or_substitute(absolute_path, expression)
|
3300
|
+
end
|
3201
3301
|
|
3202
|
-
|
3203
|
-
|
3204
|
-
|
3205
|
-
|
3206
|
-
|
3207
|
-
|
3302
|
+
def test_relative_path_gets_substituted
|
3303
|
+
relative_path = "my_folder"
|
3304
|
+
expression = "path/to/*/directory"
|
3305
|
+
expected_output = "path/to/my_folder/directory"
|
3306
|
+
assert_equal expected_output, PathUtils.resolve_path_or_substitute(relative_path, expression)
|
3307
|
+
end
|
3208
3308
|
|
3209
|
-
|
3210
|
-
|
3211
|
-
|
3212
|
-
|
3213
|
-
|
3214
|
-
|
3309
|
+
def test_path_with_no_slash_substitutes_correctly
|
3310
|
+
relative_path = "data"
|
3311
|
+
expression = "path/to/*/directory"
|
3312
|
+
expected_output = "path/to/data/directory"
|
3313
|
+
assert_equal expected_output, PathUtils.resolve_path_or_substitute(relative_path, expression)
|
3314
|
+
end
|
3215
3315
|
|
3216
|
-
|
3217
|
-
|
3218
|
-
|
3219
|
-
|
3220
|
-
|
3316
|
+
def test_empty_path_substitution
|
3317
|
+
empty_path = ""
|
3318
|
+
expression = "path/to/*/directory"
|
3319
|
+
expected_output = "path/to//directory"
|
3320
|
+
assert_equal expected_output, PathUtils.resolve_path_or_substitute(empty_path, expression)
|
3321
|
+
end
|
3221
3322
|
end
|
3323
|
+
|
3222
3324
|
end # module MarkdownExec
|
data/lib/input_sequencer.rb
CHANGED
@@ -34,6 +34,7 @@ class InputSequencer
|
|
34
34
|
prior_block_was_link: next_state.prior_block_was_link.nil? ? current.prior_block_was_link : next_state.prior_block_was_link
|
35
35
|
)
|
36
36
|
rescue
|
37
|
+
pp backtrace
|
37
38
|
binding.irb
|
38
39
|
end
|
39
40
|
|
@@ -75,11 +76,14 @@ class InputSequencer
|
|
75
76
|
|
76
77
|
if now_menu.display_menu
|
77
78
|
exit_when_bq_empty = false
|
78
|
-
|
79
79
|
run_yield :display_menu, &block
|
80
80
|
|
81
81
|
choice = run_yield :user_choice, &block
|
82
82
|
|
83
|
+
if choice.nil?
|
84
|
+
raise "Block not recognized."
|
85
|
+
break
|
86
|
+
end
|
83
87
|
break if run_yield(:exit?, choice&.downcase, &block) # Exit loop and method to terminate the app
|
84
88
|
|
85
89
|
next_state = run_yield :execute_block, choice, &block
|
@@ -115,6 +119,7 @@ class InputSequencer
|
|
115
119
|
now_menu = InputSequencer.merge_link_state(now_menu, next_menu)
|
116
120
|
end
|
117
121
|
rescue
|
122
|
+
pp backtrace
|
118
123
|
binding.irb
|
119
124
|
end
|
120
125
|
end
|
data/lib/markdown_exec.rb
CHANGED
data/lib/menu.src.yml
CHANGED
@@ -99,6 +99,12 @@
|
|
99
99
|
:opt_name: display_level_xbase_prefix
|
100
100
|
:procname: val_as_str
|
101
101
|
|
102
|
+
# - :default: "(document_link)"
|
103
|
+
# :description: Name of Link block to load with the document
|
104
|
+
# :env_var: MDE_DOCUMENT_LOAD_LINK_BLOCK_NAME
|
105
|
+
# :opt_name: document_load_link_block_name
|
106
|
+
# :procname: val_as_str
|
107
|
+
|
102
108
|
- :default: "(document_options)"
|
103
109
|
:description: Name of Opts block to load with the document
|
104
110
|
:env_var: MDE_DOCUMENT_LOAD_OPTS_BLOCK_NAME
|
@@ -108,7 +114,6 @@
|
|
108
114
|
- :arg_name: BOOL
|
109
115
|
:default: false
|
110
116
|
:description: Dump @delegate_object
|
111
|
-
:env_var: MDE_DUMP_DELEGATE_OBJECT
|
112
117
|
:long_name: dump-dump-delegate-object
|
113
118
|
:opt_name: dump_delegate_object
|
114
119
|
:procname: val_as_bool
|
@@ -116,7 +121,6 @@
|
|
116
121
|
- :arg_name: BOOL
|
117
122
|
:default: false
|
118
123
|
:description: Dump BlocksInFile (stage 1)
|
119
|
-
:env_var: MDE_DUMP_BLOCKS_IN_FILE
|
120
124
|
:long_name: dump-blocks-in-file
|
121
125
|
:opt_name: dump_blocks_in_file
|
122
126
|
:procname: val_as_bool
|
@@ -124,7 +128,6 @@
|
|
124
128
|
- :arg_name: BOOL
|
125
129
|
:default: false
|
126
130
|
:description: Dump inherited block_names
|
127
|
-
:env_var: MDE_DUMP_INHERITED_BLOCK_NAMES
|
128
131
|
:long_name: dump-dump-inherited-block_names
|
129
132
|
:opt_name: dump_inherited_block_names
|
130
133
|
:procname: val_as_bool
|
@@ -132,7 +135,6 @@
|
|
132
135
|
- :arg_name: BOOL
|
133
136
|
:default: false
|
134
137
|
:description: Dump inherited dependencies
|
135
|
-
:env_var: MDE_DUMP_INHERITED_DEPENDENCIES
|
136
138
|
:long_name: dump-dump-inherited-dependencies
|
137
139
|
:opt_name: dump_inherited_dependencies
|
138
140
|
:procname: val_as_bool
|
@@ -140,7 +142,6 @@
|
|
140
142
|
- :arg_name: BOOL
|
141
143
|
:default: false
|
142
144
|
:description: Dump inherited lines
|
143
|
-
:env_var: MDE_DUMP_INHERITED_LINES
|
144
145
|
:long_name: dump-dump-inherited-lines
|
145
146
|
:opt_name: dump_inherited_lines
|
146
147
|
:procname: val_as_bool
|
@@ -148,7 +149,6 @@
|
|
148
149
|
- :arg_name: BOOL
|
149
150
|
:default: false
|
150
151
|
:description: Dump MenuBlocks (stage 2)
|
151
|
-
:env_var: MDE_DUMP_MENU_BLOCKS
|
152
152
|
:long_name: dump-menu-blocks
|
153
153
|
:opt_name: dump_menu_blocks
|
154
154
|
:procname: val_as_bool
|
@@ -156,7 +156,6 @@
|
|
156
156
|
- :arg_name: BOOL
|
157
157
|
:default: false
|
158
158
|
:description: Dump selected block
|
159
|
-
:env_var: MDE_DUMP_SELECTED_BLOCK
|
160
159
|
:long_name: dump-selected-block
|
161
160
|
:opt_name: dump_selected_block
|
162
161
|
:procname: val_as_bool
|
@@ -206,35 +205,30 @@
|
|
206
205
|
:opt_name: exclude_expect_blocks
|
207
206
|
:procname: val_as_bool
|
208
207
|
|
208
|
+
# - :default: >
|
209
|
+
# osascript scripts/applescript/mde.applescript "%{batch_index}" "%{home}" " %{started_at} - %{document_filename} - %{block_name} " "%{script_filespec}" "%{output_filespec}"
|
209
210
|
- :default: >
|
210
211
|
osascript -e '
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
write text "o=\"%{output_filespec}\""
|
232
|
-
write text "cd \"%{home}\""
|
233
|
-
write text "echo -ne \"\\033]; %{started_at} - %{document_filename} - %{block_name} \\007\""
|
234
|
-
write text "\"$s\" | tee -a \"$o\""
|
235
|
-
end tell
|
236
|
-
end tell
|
237
|
-
end tell'
|
212
|
+
on run argv
|
213
|
+
set batch_index to "%{batch_index}"
|
214
|
+
set home to "%{home}"
|
215
|
+
set output_filespec to "%{output_filespec}"
|
216
|
+
set script_filespec to "%{script_filespec}"
|
217
|
+
set title to " %{started_at} - %{document_filename} - %{block_name} "
|
218
|
+
|
219
|
+
tell application "iTerm"
|
220
|
+
create window with default profile
|
221
|
+
tell the first window
|
222
|
+
tell the current session
|
223
|
+
write text "s=" & quoted form of script_filespec & ""
|
224
|
+
write text "o=" & quoted form of output_filespec & ""
|
225
|
+
write text "cd " & quoted form of home & ""
|
226
|
+
write text "echo -ne \"\\033]; " & title & " \\007\""
|
227
|
+
write text "\"$s\" 2>&1 | tee -a \"$o\""
|
228
|
+
end tell
|
229
|
+
end tell
|
230
|
+
end tell
|
231
|
+
end run'
|
238
232
|
:description: execute_command_format
|
239
233
|
:env_var: MDE_EXECUTE_COMMAND_FORMAT
|
240
234
|
:opt_name: execute_command_format
|
@@ -247,7 +241,7 @@
|
|
247
241
|
:procname: val_as_str
|
248
242
|
|
249
243
|
- :arg_name: BOOL
|
250
|
-
:default:
|
244
|
+
:default: false
|
251
245
|
:description: Execute script in own window
|
252
246
|
:env_var: MDE_EXECUTE_IN_OWN_WINDOW
|
253
247
|
:opt_name: execute_in_own_window
|
@@ -301,7 +295,7 @@
|
|
301
295
|
|
302
296
|
- :arg_name: FIND
|
303
297
|
:default: ''
|
304
|
-
:description: Find in documents
|
298
|
+
:description: Find argument in documents
|
305
299
|
:long_name: find
|
306
300
|
:procname: find
|
307
301
|
:short_name: "?"
|
@@ -1056,8 +1050,8 @@
|
|
1056
1050
|
:opt_name: select_by_shell_regex
|
1057
1051
|
:procname: val_as_str
|
1058
1052
|
|
1059
|
-
- :default:
|
1060
|
-
:description: 'Maximum # of rows in select list'
|
1053
|
+
- :default: 0
|
1054
|
+
:description: 'Maximum # of rows in select list. Detects current limit if not specified.'
|
1061
1055
|
:env_var: MDE_SELECT_PAGE_HEIGHT
|
1062
1056
|
:opt_name: select_page_height
|
1063
1057
|
:procname: val_as_int
|
data/lib/menu.yml
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# MDE - Markdown Executor (2.0.
|
1
|
+
# MDE - Markdown Executor (2.0.3)
|
2
2
|
---
|
3
3
|
- :description: Show current configuration values
|
4
4
|
:procname: show_config
|
@@ -91,49 +91,42 @@
|
|
91
91
|
- :arg_name: BOOL
|
92
92
|
:default: false
|
93
93
|
:description: Dump @delegate_object
|
94
|
-
:env_var: MDE_DUMP_DELEGATE_OBJECT
|
95
94
|
:long_name: dump-dump-delegate-object
|
96
95
|
:opt_name: dump_delegate_object
|
97
96
|
:procname: val_as_bool
|
98
97
|
- :arg_name: BOOL
|
99
98
|
:default: false
|
100
99
|
:description: Dump BlocksInFile (stage 1)
|
101
|
-
:env_var: MDE_DUMP_BLOCKS_IN_FILE
|
102
100
|
:long_name: dump-blocks-in-file
|
103
101
|
:opt_name: dump_blocks_in_file
|
104
102
|
:procname: val_as_bool
|
105
103
|
- :arg_name: BOOL
|
106
104
|
:default: false
|
107
105
|
:description: Dump inherited block_names
|
108
|
-
:env_var: MDE_DUMP_INHERITED_BLOCK_NAMES
|
109
106
|
:long_name: dump-dump-inherited-block_names
|
110
107
|
:opt_name: dump_inherited_block_names
|
111
108
|
:procname: val_as_bool
|
112
109
|
- :arg_name: BOOL
|
113
110
|
:default: false
|
114
111
|
:description: Dump inherited dependencies
|
115
|
-
:env_var: MDE_DUMP_INHERITED_DEPENDENCIES
|
116
112
|
:long_name: dump-dump-inherited-dependencies
|
117
113
|
:opt_name: dump_inherited_dependencies
|
118
114
|
:procname: val_as_bool
|
119
115
|
- :arg_name: BOOL
|
120
116
|
:default: false
|
121
117
|
:description: Dump inherited lines
|
122
|
-
:env_var: MDE_DUMP_INHERITED_LINES
|
123
118
|
:long_name: dump-dump-inherited-lines
|
124
119
|
:opt_name: dump_inherited_lines
|
125
120
|
:procname: val_as_bool
|
126
121
|
- :arg_name: BOOL
|
127
122
|
:default: false
|
128
123
|
:description: Dump MenuBlocks (stage 2)
|
129
|
-
:env_var: MDE_DUMP_MENU_BLOCKS
|
130
124
|
:long_name: dump-menu-blocks
|
131
125
|
:opt_name: dump_menu_blocks
|
132
126
|
:procname: val_as_bool
|
133
127
|
- :arg_name: BOOL
|
134
128
|
:default: false
|
135
129
|
:description: Dump selected block
|
136
|
-
:env_var: MDE_DUMP_SELECTED_BLOCK
|
137
130
|
:long_name: dump-selected-block
|
138
131
|
:opt_name: dump_selected_block
|
139
132
|
:procname: val_as_bool
|
@@ -177,21 +170,28 @@
|
|
177
170
|
:env_var: MDE_EXCLUDE_EXPECT_BLOCKS
|
178
171
|
:opt_name: exclude_expect_blocks
|
179
172
|
:procname: val_as_bool
|
180
|
-
- :default:
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
173
|
+
- :default: |
|
174
|
+
osascript -e '
|
175
|
+
on run argv
|
176
|
+
set batch_index to "%{batch_index}"
|
177
|
+
set home to "%{home}"
|
178
|
+
set output_filespec to "%{output_filespec}"
|
179
|
+
set script_filespec to "%{script_filespec}"
|
180
|
+
set title to " %{started_at} - %{document_filename} - %{block_name} "
|
181
|
+
|
182
|
+
tell application "iTerm"
|
183
|
+
create window with default profile
|
184
|
+
tell the first window
|
185
|
+
tell the current session
|
186
|
+
write text "s=" & quoted form of script_filespec & ""
|
187
|
+
write text "o=" & quoted form of output_filespec & ""
|
188
|
+
write text "cd " & quoted form of home & ""
|
189
|
+
write text "echo -ne \"\\033]; " & title & " \\007\""
|
190
|
+
write text "\"$s\" 2>&1 | tee -a \"$o\""
|
191
|
+
end tell
|
192
|
+
end tell
|
193
|
+
end tell
|
194
|
+
end run'
|
195
195
|
:description: execute_command_format
|
196
196
|
:env_var: MDE_EXECUTE_COMMAND_FORMAT
|
197
197
|
:opt_name: execute_command_format
|
@@ -202,7 +202,7 @@
|
|
202
202
|
:opt_name: execute_command_title_time_format
|
203
203
|
:procname: val_as_str
|
204
204
|
- :arg_name: BOOL
|
205
|
-
:default:
|
205
|
+
:default: false
|
206
206
|
:description: Execute script in own window
|
207
207
|
:env_var: MDE_EXECUTE_IN_OWN_WINDOW
|
208
208
|
:opt_name: execute_in_own_window
|
@@ -249,7 +249,7 @@
|
|
249
249
|
:short_name: f
|
250
250
|
- :arg_name: FIND
|
251
251
|
:default: ''
|
252
|
-
:description: Find in documents
|
252
|
+
:description: Find argument in documents
|
253
253
|
:long_name: find
|
254
254
|
:procname: find
|
255
255
|
:short_name: "?"
|
@@ -901,8 +901,8 @@
|
|
901
901
|
:env_var: MDE_SELECT_BY_SHELL_REGEX
|
902
902
|
:opt_name: select_by_shell_regex
|
903
903
|
:procname: val_as_str
|
904
|
-
- :default:
|
905
|
-
:description: 'Maximum # of rows in select list'
|
904
|
+
- :default: 0
|
905
|
+
:description: 'Maximum # of rows in select list. Detects current limit if not specified.'
|
906
906
|
:env_var: MDE_SELECT_PAGE_HEIGHT
|
907
907
|
:opt_name: select_page_height
|
908
908
|
:procname: val_as_int
|
data/lib/saved_assets.rb
CHANGED
@@ -19,43 +19,45 @@ module MarkdownExec
|
|
19
19
|
# Generates a formatted script name based on the provided parameters.
|
20
20
|
def self.script_name(filename:, prefix:, time:, blockname:, ftime: DEFAULT_FTIME, join_str: '_', pattern: FNR11, replace: FNR12, exts: '.sh')
|
21
21
|
fne = filename.gsub(pattern, replace)
|
22
|
-
|
22
|
+
bne = blockname.gsub(pattern, replace)
|
23
|
+
"#{[prefix, time.strftime(ftime), fne, ',', bne].join(join_str)}#{exts}"
|
23
24
|
end
|
24
25
|
|
25
26
|
# Generates a formatted stdout name based on the provided parameters.
|
26
27
|
def self.stdout_name(filename:, prefix:, time:, blockname:, ftime: DEFAULT_FTIME, join_str: '_', pattern: FNR11, replace: FNR12, exts: '.out.txt')
|
27
28
|
fne = filename.gsub(pattern, replace)
|
28
|
-
|
29
|
+
bne = blockname.gsub(pattern, replace)
|
30
|
+
"#{[prefix, time.strftime(ftime), fne, ',', bne].join(join_str)}#{exts}"
|
29
31
|
end
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
33
|
-
if $PROGRAM_NAME
|
34
|
-
require 'minitest/autorun'
|
35
|
+
return if $PROGRAM_NAME != __FILE__
|
35
36
|
|
36
|
-
|
37
|
-
def test_script_name
|
38
|
-
filename = 'sample.txt'
|
39
|
-
prefix = 'test'
|
40
|
-
time = Time.new(2023, 1, 1, 12, 0, 0) # Sample date-time for consistency in testing
|
41
|
-
blockname = 'block1'
|
37
|
+
require 'minitest/autorun'
|
42
38
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
39
|
+
class SavedAssetTest < Minitest::Test
|
40
|
+
def test_script_name_with_special_characters_in_blockname
|
41
|
+
filename = 'sample.txt'
|
42
|
+
prefix = 'test'
|
43
|
+
time = Time.new(2023, 1, 1, 12, 0, 0)
|
44
|
+
blockname = 'block/1:2'
|
45
|
+
|
46
|
+
expected_name = 'test_2023-01-01-12-00-00_sample.txt_,_block_1_2.sh'
|
47
|
+
assert_equal expected_name, MarkdownExec::SavedAsset.script_name(
|
48
|
+
filename: filename, prefix: prefix, time: time, blockname: blockname
|
49
|
+
)
|
50
|
+
end
|
48
51
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
52
|
+
def test_stdout_name_with_special_characters_in_blockname
|
53
|
+
filename = 'sample.txt'
|
54
|
+
prefix = 'test'
|
55
|
+
time = Time.new(2023, 1, 1, 12, 0, 0)
|
56
|
+
blockname = 'block/1:2'
|
54
57
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
58
|
+
expected_name = 'test_2023-01-01-12-00-00_sample.txt_,_block_1_2.out.txt'
|
59
|
+
assert_equal expected_name, MarkdownExec::SavedAsset.stdout_name(
|
60
|
+
filename: filename, prefix: prefix, time: time, blockname: blockname
|
61
|
+
)
|
60
62
|
end
|
61
63
|
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
#!/usr/bin/env -S bundle exec ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# encoding=utf-8
|
5
|
+
require 'logger'
|
6
|
+
|
7
|
+
# Logger::LogDevice is used by Logger, the parent class of StdOutErrLogger
|
8
|
+
class Logger::LogDevice
|
9
|
+
# remove header
|
10
|
+
def add_log_header(file); end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Custom logger to direct info to stdout and warn and above to stderr
|
14
|
+
#
|
15
|
+
class StdOutErrLogger < Logger
|
16
|
+
attr_reader :file
|
17
|
+
|
18
|
+
# def initialize(file = nil)
|
19
|
+
def initialize(file = "#{__dir__}/../tmp/hash_delegator_next_link_state.yaml")
|
20
|
+
@file = file
|
21
|
+
super(file || STDOUT)
|
22
|
+
self.formatter = proc do |severity, datetime, progname, msg|
|
23
|
+
"#{msg}\n"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def add(severity, message = nil, progname = nil, &block)
|
28
|
+
message = (message || block&.call || progname) if message.nil?
|
29
|
+
message = "- #{message.to_json}\n"
|
30
|
+
### message = message.join("\n") if message.is_a? Array
|
31
|
+
out = format_message(format_severity(severity), Time.now, progname, message)
|
32
|
+
if severity == Logger::UNKNOWN # does not follow spec, outputs to stderr for IO
|
33
|
+
# $stderr.puts(out)
|
34
|
+
super
|
35
|
+
elsif severity >= Logger::WARN
|
36
|
+
if @file
|
37
|
+
super
|
38
|
+
else
|
39
|
+
$stderr.puts(out)
|
40
|
+
end
|
41
|
+
else
|
42
|
+
if @file
|
43
|
+
super
|
44
|
+
else
|
45
|
+
$stdout.puts(out)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
return if $PROGRAM_NAME != __FILE__
|
52
|
+
|
53
|
+
require 'minitest/autorun'
|
54
|
+
|
55
|
+
class StdOutErrLoggerTest < Minitest::Test
|
56
|
+
# Redirect STDOUT and STDERR to capture them for assertions
|
57
|
+
def setup
|
58
|
+
@original_stdout = $stdout
|
59
|
+
@original_stderr = $stderr
|
60
|
+
$stdout = StringIO.new
|
61
|
+
$stderr = StringIO.new
|
62
|
+
end
|
63
|
+
|
64
|
+
def teardown
|
65
|
+
$stdout = @original_stdout
|
66
|
+
$stderr = @original_stderr
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_initialize_without_file
|
70
|
+
logger = StdOutErrLogger.new
|
71
|
+
assert_nil logger.file
|
72
|
+
assert_equal Logger::DEBUG, logger.level
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_initialize_with_file
|
76
|
+
Tempfile.open do |file|
|
77
|
+
logger = StdOutErrLogger.new(file.path)
|
78
|
+
assert_equal file.path, logger.file
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_logging_info
|
83
|
+
logger = StdOutErrLogger.new
|
84
|
+
logger.info("Info message")
|
85
|
+
assert_equal "Info message\n", $stdout.string
|
86
|
+
assert_empty $stderr.string
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_logging_warning
|
90
|
+
logger = StdOutErrLogger.new
|
91
|
+
logger.warn("Warning message")
|
92
|
+
assert_empty $stdout.string
|
93
|
+
assert_equal "Warning message\n", $stderr.string
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_logging_error
|
97
|
+
logger = StdOutErrLogger.new
|
98
|
+
logger.error("Error message")
|
99
|
+
assert_empty $stdout.string
|
100
|
+
assert_equal "Error message\n", $stderr.string
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_logging_with_array
|
104
|
+
logger = StdOutErrLogger.new
|
105
|
+
logger.info(["Message line 1", "Message line 2"])
|
106
|
+
assert_equal "Message line 1\nMessage line 2\n", $stdout.string
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_logging_with_block
|
110
|
+
logger = StdOutErrLogger.new
|
111
|
+
logger.info { "Block message" }
|
112
|
+
assert_equal "Block message\n", $stdout.string
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_logging_unknown_severity
|
116
|
+
logger = StdOutErrLogger.new
|
117
|
+
logger.add(Logger::UNKNOWN, "Unknown severity message")
|
118
|
+
assert_empty $stdout.string
|
119
|
+
assert_equal "Unknown severity message\n", $stderr.string
|
120
|
+
end
|
121
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: markdown_exec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fareed Stevenson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-04-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: clipboard
|
@@ -169,6 +169,7 @@ files:
|
|
169
169
|
- lib/saved_assets.rb
|
170
170
|
- lib/saved_files_matcher.rb
|
171
171
|
- lib/shared.rb
|
172
|
+
- lib/std_out_err_logger.rb
|
172
173
|
- lib/string_util.rb
|
173
174
|
- lib/tap.rb
|
174
175
|
homepage: https://rubygems.org/gems/markdown_exec
|