markdown_exec 2.3.0 → 2.4.0
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/.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
@@ -0,0 +1,166 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class TableExtractor
|
4
|
+
# Extract tables from an array of text lines formatted in Markdown style
|
5
|
+
# @param [Array<String>] lines The array of text lines
|
6
|
+
# @return [Array<Hash>] An array of tables with row count, column count, and start index
|
7
|
+
def self.extract_tables(lines)
|
8
|
+
tables = []
|
9
|
+
inside_table = false
|
10
|
+
table_start = nil
|
11
|
+
row_count = 0
|
12
|
+
column_count = 0
|
13
|
+
|
14
|
+
separator_regexp = /^[ \t]*\|? *(?::?-+:?) *( *\| *(?::?-+:?) *)+\|? *$/
|
15
|
+
|
16
|
+
lines.each_with_index do |line, index|
|
17
|
+
# Match line separators with at least 2 columns
|
18
|
+
if line.strip.match?(separator_regexp)
|
19
|
+
if inside_table
|
20
|
+
# Add the current table before starting a new one
|
21
|
+
tables << {
|
22
|
+
rows: row_count,
|
23
|
+
columns: column_count,
|
24
|
+
start_index: table_start
|
25
|
+
}
|
26
|
+
end
|
27
|
+
# Start a new table
|
28
|
+
table_start = index - 1 if table_start.nil?
|
29
|
+
column_count = line.split('|').count - 1
|
30
|
+
row_count = 2 # Reset to 2 to account for the header and separator rows
|
31
|
+
inside_table = true
|
32
|
+
elsif inside_table && (line.strip.start_with?('|') || line.include?('|'))
|
33
|
+
row_count += 1
|
34
|
+
elsif inside_table
|
35
|
+
# Add the current table and reset the state
|
36
|
+
tables << {
|
37
|
+
rows: row_count,
|
38
|
+
columns: column_count,
|
39
|
+
start_index: table_start
|
40
|
+
}
|
41
|
+
inside_table = false
|
42
|
+
table_start = nil
|
43
|
+
row_count = 0
|
44
|
+
column_count = 0
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Handle case where table ends at the last line
|
49
|
+
if inside_table
|
50
|
+
tables << {
|
51
|
+
rows: row_count,
|
52
|
+
columns: column_count,
|
53
|
+
start_index: table_start
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
tables
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
return if $PROGRAM_NAME != __FILE__
|
62
|
+
|
63
|
+
require 'minitest/autorun'
|
64
|
+
|
65
|
+
class TestTableExtractor < Minitest::Test
|
66
|
+
def test_single_table
|
67
|
+
lines = [
|
68
|
+
'| Species| Genus| Family',
|
69
|
+
'|-|-|-',
|
70
|
+
'| Pongo tapanuliensis| Pongo| Hominidae',
|
71
|
+
'| | Histiophryne| Antennariidae'
|
72
|
+
]
|
73
|
+
expected = [{ rows: 4, columns: 3, start_index: 0 }]
|
74
|
+
assert_equal expected, TableExtractor.extract_tables(lines)
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_indented_table
|
78
|
+
lines = [
|
79
|
+
"\t | Species| Genus| Family",
|
80
|
+
"\t |-|-|-",
|
81
|
+
"\t | Pongo tapanuliensis| Pongo| Hominidae",
|
82
|
+
"\t | | Histiophryne| Antennariidae"
|
83
|
+
]
|
84
|
+
expected = [{ rows: 4, columns: 3, start_index: 0 }]
|
85
|
+
assert_equal expected, TableExtractor.extract_tables(lines)
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_multiple_tables
|
89
|
+
lines = [
|
90
|
+
'| Species| Genus| Family',
|
91
|
+
'|-|-|-',
|
92
|
+
'| Pongo tapanuliensis| Pongo| Hominidae',
|
93
|
+
'| | Histiophryne| Antennariidae',
|
94
|
+
'',
|
95
|
+
'| Name| Species',
|
96
|
+
'|-|-',
|
97
|
+
'| Tapanuli Orangutan| Pongo tapanuliensis'
|
98
|
+
]
|
99
|
+
expected = [
|
100
|
+
{ rows: 4, columns: 3, start_index: 0 },
|
101
|
+
{ rows: 3, columns: 2, start_index: 5 }
|
102
|
+
]
|
103
|
+
assert_equal expected, TableExtractor.extract_tables(lines)
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_no_tables
|
107
|
+
lines = [
|
108
|
+
'This is a regular line.',
|
109
|
+
'Another regular line.'
|
110
|
+
]
|
111
|
+
expected = []
|
112
|
+
assert_equal expected, TableExtractor.extract_tables(lines)
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_inconsistent_columns
|
116
|
+
lines = [
|
117
|
+
'| Species| Genus| Family',
|
118
|
+
'|-|-',
|
119
|
+
'| Pongo tapanuliensis| Pongo| Hominidae',
|
120
|
+
'| | Histiophryne| Antennariidae',
|
121
|
+
'',
|
122
|
+
'| Name| Species',
|
123
|
+
'|-|-|-',
|
124
|
+
'| Tapanuli Orangutan| Pongo tapanuliensis'
|
125
|
+
]
|
126
|
+
# number of columns determined from row of dividers
|
127
|
+
expected = [{ rows: 4, columns: 2, start_index: 0 },
|
128
|
+
{ rows: 3, columns: 3, start_index: 5 }]
|
129
|
+
assert_equal expected, TableExtractor.extract_tables(lines)
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_table_at_end_of_lines
|
133
|
+
lines = [
|
134
|
+
'Some introductory text.',
|
135
|
+
'| Species| Genus| Family',
|
136
|
+
'|-|-|-',
|
137
|
+
'| Pongo tapanuliensis| Pongo| Hominidae',
|
138
|
+
'| | Histiophryne| Antennariidae'
|
139
|
+
]
|
140
|
+
expected = [{ rows: 4, columns: 3, start_index: 1 }]
|
141
|
+
assert_equal expected, TableExtractor.extract_tables(lines)
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_table_without_starting_pipe
|
145
|
+
lines = [
|
146
|
+
'Some introductory text.',
|
147
|
+
'Platform| Target Environment| Command',
|
148
|
+
'|-|-|-',
|
149
|
+
'| Pongo tapanuliensis| Pongo| Hominidae',
|
150
|
+
'| | Histiophryne| Antennariidae'
|
151
|
+
]
|
152
|
+
expected = [{ rows: 4, columns: 3, start_index: 1 }]
|
153
|
+
assert_equal expected, TableExtractor.extract_tables(lines)
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_table_with_colon_hyphens
|
157
|
+
lines = [
|
158
|
+
'| Name| Age| City',
|
159
|
+
'|:-:|:-|:-:',
|
160
|
+
'| John Doe| 30| New York',
|
161
|
+
'| Jane Doe| 25| Los Angeles'
|
162
|
+
]
|
163
|
+
expected = [{ rows: 4, columns: 3, start_index: 0 }]
|
164
|
+
assert_equal expected, TableExtractor.extract_tables(lines)
|
165
|
+
end
|
166
|
+
end
|
data/lib/tap.rb
CHANGED
@@ -35,8 +35,6 @@ unless defined?(Env)
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
# rubocop:disable Metrics/ParameterLists
|
39
|
-
|
40
38
|
## application-level debug control
|
41
39
|
#
|
42
40
|
# :reek:TooManyConstants
|
@@ -98,8 +96,8 @@ module Tap
|
|
98
96
|
|
99
97
|
# :reek:ControlParameter
|
100
98
|
# :reek:LongParameterList
|
101
|
-
def tap_inspect(name_ = nil, caller_first: nil, mask: TDD, name: DN,
|
102
|
-
type: nil)
|
99
|
+
def tap_inspect(name_ = nil, caller_first: nil, mask: TDD, name: DN,
|
100
|
+
source: nil, type: nil)
|
103
101
|
return self unless $tap_enable
|
104
102
|
return self unless (mask & $tap_mask).positive?
|
105
103
|
|
@@ -107,7 +105,8 @@ module Tap
|
|
107
105
|
outs = []
|
108
106
|
outs.push(source.to_s) if source.present?
|
109
107
|
|
110
|
-
vs = (caller_first || caller[0]).scan(/in `?(\S+)'$/)
|
108
|
+
vs = (caller_first || caller[0]).scan(/in `?(\S+)'$/)
|
109
|
+
.fetch(0, []).fetch(0, '')
|
111
110
|
outs.push("#{vs}()") if vs.present?
|
112
111
|
|
113
112
|
outs.push(tap_named_value(name_ || name, method(fn).call))
|
@@ -143,7 +142,7 @@ module Tap
|
|
143
142
|
# :reek:ControlParameter
|
144
143
|
# :reek:LongParameterList
|
145
144
|
def tap_yaml(name_ = nil, caller_first: nil, mask: TDD, name: DN, source: nil)
|
146
|
-
tap_inspect name_, caller_first:
|
145
|
+
tap_inspect name_, caller_first: caller_first || caller[0],
|
147
146
|
mask: mask, name: name, source: source, type: :yaml
|
148
147
|
end
|
149
148
|
|
data/lib/text_analyzer.rb
CHANGED
@@ -11,13 +11,17 @@ module TextAnalyzer
|
|
11
11
|
# @return [Array<Hash>, Array<Array<Hash>>] an array or nested arrays of highlighted segments
|
12
12
|
#
|
13
13
|
# @raise [ArgumentError] if the hierarchy structure is neither a String nor an Array
|
14
|
-
def self.analyze_hierarchy(
|
14
|
+
def self.analyze_hierarchy(
|
15
|
+
hierarchy, pattern, default_color, match_color,
|
16
|
+
text_sym: :text, style_sym: :color
|
17
|
+
)
|
15
18
|
case hierarchy
|
16
19
|
when String
|
17
20
|
highlight_segments(hierarchy, pattern, default_color, match_color)
|
21
|
+
|
18
22
|
when Hash
|
19
|
-
decorated = highlight_segments(hierarchy[
|
20
|
-
hierarchy[
|
23
|
+
decorated = highlight_segments(hierarchy[text_sym], pattern,
|
24
|
+
hierarchy[style_sym], match_color)
|
21
25
|
|
22
26
|
case decorated
|
23
27
|
when String
|
@@ -31,18 +35,19 @@ module TextAnalyzer
|
|
31
35
|
else
|
32
36
|
decorated
|
33
37
|
end
|
38
|
+
|
34
39
|
when Array
|
35
40
|
hierarchy.map do |element|
|
36
41
|
analyze_hierarchy(element, pattern, default_color, match_color)
|
37
42
|
end
|
38
|
-
when HierarchyString
|
39
43
|
|
44
|
+
when HierarchyString
|
40
45
|
hierarchy.replace_text! do |substring|
|
41
|
-
substring
|
46
|
+
substring # no change
|
42
47
|
end
|
43
48
|
|
44
49
|
else
|
45
|
-
|
50
|
+
warn [hierarchy.class, hierarchy].inspect
|
46
51
|
raise ArgumentError, 'Invalid hierarchy structure'
|
47
52
|
end
|
48
53
|
end
|
@@ -77,14 +82,14 @@ module TextAnalyzer
|
|
77
82
|
# @yieldparam segment [String] a segment of the text
|
78
83
|
# @yieldparam is_match [Boolean] true if the segment matches the pattern, false otherwise
|
79
84
|
def self.yield_matches_and_non_matches(text, pattern)
|
80
|
-
last_end =
|
85
|
+
last_end = nil
|
81
86
|
|
82
87
|
text.scan(pattern) do |match|
|
83
88
|
match_start = Regexp.last_match.begin(0)
|
84
89
|
match_end = Regexp.last_match.end(0)
|
85
90
|
|
86
91
|
# Yield the non-matching segment before the match
|
87
|
-
yield text[last_end...match_start], false if match_start > last_end
|
92
|
+
yield text[(last_end || 0)...match_start], false if last_end.nil? || match_start > last_end
|
88
93
|
|
89
94
|
# Yield the matching segment
|
90
95
|
yield match.first, true
|
@@ -92,9 +97,140 @@ module TextAnalyzer
|
|
92
97
|
last_end = match_end
|
93
98
|
end
|
94
99
|
|
100
|
+
last_end ||= 0
|
95
101
|
# Yield any remaining non-matching segment after the last match
|
96
102
|
return unless last_end < text.length
|
97
103
|
|
98
104
|
yield text[last_end..-1], false
|
99
105
|
end
|
100
106
|
end
|
107
|
+
|
108
|
+
return if $PROGRAM_NAME != __FILE__
|
109
|
+
|
110
|
+
require 'minitest/autorun'
|
111
|
+
require_relative 'hierarchy_string'
|
112
|
+
|
113
|
+
$default_color = :upcase
|
114
|
+
$match_color = :downcase
|
115
|
+
|
116
|
+
class TestTextAnalyzer < Minitest::Test
|
117
|
+
def test_analyze_hierarchy_with_string
|
118
|
+
text = 'This is a test string.'
|
119
|
+
pattern = /(test)/
|
120
|
+
|
121
|
+
expected_output = [[[
|
122
|
+
{ text: 'This is a ', color: $default_color },
|
123
|
+
{ text: 'test', color: $match_color },
|
124
|
+
{ text: ' string.', color: $default_color }
|
125
|
+
]]]
|
126
|
+
|
127
|
+
tree = HierarchyString.new([{ text: text, color: $default_color }])
|
128
|
+
assert_equal expected_output,
|
129
|
+
TextAnalyzer.analyze_hierarchy(tree.substrings, pattern, $default_color,
|
130
|
+
$match_color)
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_analyze_hierarchy_with_array
|
134
|
+
hierarchy = [
|
135
|
+
'This is a test string.',
|
136
|
+
'Another test line.'
|
137
|
+
]
|
138
|
+
pattern = /(test)/
|
139
|
+
|
140
|
+
expected_output = [
|
141
|
+
[
|
142
|
+
{ text: 'This is a ', color: $default_color },
|
143
|
+
{ text: 'test', color: $match_color },
|
144
|
+
{ text: ' string.', color: $default_color }
|
145
|
+
],
|
146
|
+
[
|
147
|
+
{ text: 'Another ', color: $default_color },
|
148
|
+
{ text: 'test', color: $match_color },
|
149
|
+
{ text: ' line.', color: $default_color }
|
150
|
+
]
|
151
|
+
]
|
152
|
+
|
153
|
+
assert_equal expected_output,
|
154
|
+
TextAnalyzer.analyze_hierarchy(hierarchy, pattern,
|
155
|
+
$default_color, $match_color)
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_analyze_hierarchy_with_nested_array
|
159
|
+
hierarchy = [
|
160
|
+
'This is a test string.',
|
161
|
+
['Another test line.', 'Yet another test.']
|
162
|
+
]
|
163
|
+
pattern = /(test)/
|
164
|
+
|
165
|
+
expected_output = [
|
166
|
+
[
|
167
|
+
{ text: 'This is a ', color: $default_color },
|
168
|
+
{ text: 'test', color: $match_color },
|
169
|
+
{ text: ' string.', color: $default_color }
|
170
|
+
],
|
171
|
+
[
|
172
|
+
[
|
173
|
+
{ text: 'Another ', color: $default_color },
|
174
|
+
{ text: 'test', color: $match_color },
|
175
|
+
{ text: ' line.', color: $default_color }
|
176
|
+
],
|
177
|
+
[
|
178
|
+
{ text: 'Yet another ', color: $default_color },
|
179
|
+
{ text: 'test', color: $match_color },
|
180
|
+
{ text: '.', color: $default_color }
|
181
|
+
]
|
182
|
+
]
|
183
|
+
]
|
184
|
+
|
185
|
+
assert_equal expected_output,
|
186
|
+
TextAnalyzer.analyze_hierarchy(hierarchy, pattern,
|
187
|
+
$default_color, $match_color)
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_analyze_hierarchy_with_invalid_type
|
191
|
+
hierarchy = 12_345
|
192
|
+
# hierarchy = HierarchyString.new([{ text: '12345', color: $default_color }])
|
193
|
+
pattern = /(test)/
|
194
|
+
|
195
|
+
assert_raises(ArgumentError) do
|
196
|
+
TextAnalyzer.analyze_hierarchy(hierarchy, pattern, $default_color,
|
197
|
+
$match_color)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def test_highlight_segments
|
202
|
+
text = 'This is a test string.'
|
203
|
+
pattern = /(test)/
|
204
|
+
|
205
|
+
expected_output = [
|
206
|
+
{ text: 'This is a ', color: $default_color },
|
207
|
+
{ text: 'test', color: $match_color },
|
208
|
+
{ text: ' string.', color: $default_color }
|
209
|
+
]
|
210
|
+
|
211
|
+
assert_equal expected_output,
|
212
|
+
TextAnalyzer.highlight_segments(text, pattern, $default_color,
|
213
|
+
$match_color)
|
214
|
+
end
|
215
|
+
|
216
|
+
def test_yield_matches_and_non_matches
|
217
|
+
text = 'This is a test string with multiple tests.'
|
218
|
+
pattern = /(test)/
|
219
|
+
segments = []
|
220
|
+
|
221
|
+
TextAnalyzer.yield_matches_and_non_matches(text,
|
222
|
+
pattern) do |segment, is_match|
|
223
|
+
segments << { text: segment, is_match: is_match }
|
224
|
+
end
|
225
|
+
|
226
|
+
expected_output = [
|
227
|
+
{ text: 'This is a ', is_match: false },
|
228
|
+
{ text: 'test', is_match: true },
|
229
|
+
{ text: ' string with multiple ', is_match: false },
|
230
|
+
{ text: 'test', is_match: true },
|
231
|
+
{ text: 's.', is_match: false }
|
232
|
+
]
|
233
|
+
|
234
|
+
assert_equal expected_output, segments
|
235
|
+
end
|
236
|
+
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.
|
4
|
+
version: 2.4.0
|
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-09-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: clipboard
|
@@ -106,6 +106,15 @@ files:
|
|
106
106
|
- assets/output_of_execution.png
|
107
107
|
- assets/select_a_block.png
|
108
108
|
- assets/select_a_file.png
|
109
|
+
- bats/bats.bats
|
110
|
+
- bats/block-types.bats
|
111
|
+
- bats/cli.bats
|
112
|
+
- bats/fail.bats
|
113
|
+
- bats/history.bats
|
114
|
+
- bats/markup.bats
|
115
|
+
- bats/mde.bats
|
116
|
+
- bats/options.bats
|
117
|
+
- bats/test_helper.bash
|
109
118
|
- bin/bmde
|
110
119
|
- bin/colorize_env_vars.sh
|
111
120
|
- bin/console
|
@@ -113,6 +122,13 @@ files:
|
|
113
122
|
- bin/setup
|
114
123
|
- bin/tab_completion.sh
|
115
124
|
- bin/tab_completion.sh.erb
|
125
|
+
- docs/dev/block-type-opts.md
|
126
|
+
- docs/dev/block-type-port.md
|
127
|
+
- docs/dev/block-type-vars.md
|
128
|
+
- docs/dev/pass-through-arguments.md
|
129
|
+
- docs/dev/specs-import.md
|
130
|
+
- docs/dev/specs.md
|
131
|
+
- docs/dev/text-decoration.md
|
116
132
|
- examples/bash-blocks.md
|
117
133
|
- examples/block-names.md
|
118
134
|
- examples/block_names.md
|
@@ -149,9 +165,13 @@ files:
|
|
149
165
|
- examples/port-blocks.md
|
150
166
|
- examples/save.md
|
151
167
|
- examples/search.md
|
168
|
+
- examples/table-markup.md
|
169
|
+
- examples/text-markup.md
|
152
170
|
- examples/vars-blocks.md
|
153
171
|
- examples/wrap.md
|
154
172
|
- lib/ansi_formatter.rb
|
173
|
+
- lib/ansi_string.rb
|
174
|
+
- lib/argument_processor.rb
|
155
175
|
- lib/array.rb
|
156
176
|
- lib/array_util.rb
|
157
177
|
- lib/block_label.rb
|
@@ -163,17 +183,20 @@ files:
|
|
163
183
|
- lib/colorize.rb
|
164
184
|
- lib/constants.rb
|
165
185
|
- lib/directory_searcher.rb
|
186
|
+
- lib/doh.rb
|
166
187
|
- lib/env.rb
|
167
188
|
- lib/exceptions.rb
|
168
189
|
- lib/fcb.rb
|
169
190
|
- lib/filter.rb
|
170
191
|
- lib/find_files.rb
|
192
|
+
- lib/format_table.rb
|
171
193
|
- lib/fout.rb
|
172
194
|
- lib/hash.rb
|
173
195
|
- lib/hash_delegator.rb
|
174
196
|
- lib/hierarchy_string.rb
|
175
197
|
- lib/input_sequencer.rb
|
176
198
|
- lib/instance_method_wrapper.rb
|
199
|
+
- lib/layered_hash.rb
|
177
200
|
- lib/link_history.rb
|
178
201
|
- lib/markdown_exec.rb
|
179
202
|
- lib/markdown_exec/version.rb
|
@@ -190,9 +213,9 @@ files:
|
|
190
213
|
- lib/saved_assets.rb
|
191
214
|
- lib/saved_files_matcher.rb
|
192
215
|
- lib/shared.rb
|
193
|
-
- lib/std_out_err_logger.rb
|
194
216
|
- lib/streams_out.rb
|
195
217
|
- lib/string_util.rb
|
218
|
+
- lib/table_extractor.rb
|
196
219
|
- lib/tap.rb
|
197
220
|
- lib/text_analyzer.rb
|
198
221
|
homepage: https://rubygems.org/gems/markdown_exec
|
data/lib/std_out_err_logger.rb
DELETED
@@ -1,119 +0,0 @@
|
|
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
|
-
warn(out)
|
40
|
-
end
|
41
|
-
elsif @file
|
42
|
-
super
|
43
|
-
else
|
44
|
-
$stdout.puts(out)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
return if $PROGRAM_NAME != __FILE__
|
50
|
-
|
51
|
-
require 'minitest/autorun'
|
52
|
-
|
53
|
-
class StdOutErrLoggerTest < Minitest::Test
|
54
|
-
# Redirect STDOUT and STDERR to capture them for assertions
|
55
|
-
def setup
|
56
|
-
@original_stdout = $stdout
|
57
|
-
@original_stderr = $stderr
|
58
|
-
$stdout = StringIO.new
|
59
|
-
$stderr = StringIO.new
|
60
|
-
end
|
61
|
-
|
62
|
-
def teardown
|
63
|
-
$stdout = @original_stdout
|
64
|
-
$stderr = @original_stderr
|
65
|
-
end
|
66
|
-
|
67
|
-
def test_initialize_without_file
|
68
|
-
logger = StdOutErrLogger.new
|
69
|
-
assert_nil logger.file
|
70
|
-
assert_equal Logger::DEBUG, logger.level
|
71
|
-
end
|
72
|
-
|
73
|
-
def test_initialize_with_file
|
74
|
-
Tempfile.open do |file|
|
75
|
-
logger = StdOutErrLogger.new(file.path)
|
76
|
-
assert_equal file.path, logger.file
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def test_logging_info
|
81
|
-
logger = StdOutErrLogger.new
|
82
|
-
logger.info('Info message')
|
83
|
-
assert_equal "Info message\n", $stdout.string
|
84
|
-
assert_empty $stderr.string
|
85
|
-
end
|
86
|
-
|
87
|
-
def test_logging_warning
|
88
|
-
logger = StdOutErrLogger.new
|
89
|
-
logger.warn('Warning message')
|
90
|
-
assert_empty $stdout.string
|
91
|
-
assert_equal "Warning message\n", $stderr.string
|
92
|
-
end
|
93
|
-
|
94
|
-
def test_logging_error
|
95
|
-
logger = StdOutErrLogger.new
|
96
|
-
logger.error('Error message')
|
97
|
-
assert_empty $stdout.string
|
98
|
-
assert_equal "Error message\n", $stderr.string
|
99
|
-
end
|
100
|
-
|
101
|
-
def test_logging_with_array
|
102
|
-
logger = StdOutErrLogger.new
|
103
|
-
logger.info(['Message line 1', 'Message line 2'])
|
104
|
-
assert_equal "Message line 1\nMessage line 2\n", $stdout.string
|
105
|
-
end
|
106
|
-
|
107
|
-
def test_logging_with_block
|
108
|
-
logger = StdOutErrLogger.new
|
109
|
-
logger.info { 'Block message' }
|
110
|
-
assert_equal "Block message\n", $stdout.string
|
111
|
-
end
|
112
|
-
|
113
|
-
def test_logging_unknown_severity
|
114
|
-
logger = StdOutErrLogger.new
|
115
|
-
logger.add(Logger::UNKNOWN, 'Unknown severity message')
|
116
|
-
assert_empty $stdout.string
|
117
|
-
assert_equal "Unknown severity message\n", $stderr.string
|
118
|
-
end
|
119
|
-
end
|