markdown_exec 2.5.0 → 2.6.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/CHANGELOG.md +15 -0
- data/Gemfile.lock +2 -2
- data/Rakefile +3 -3
- data/bats/block-types.bats +13 -7
- data/bats/import.bats +6 -0
- data/bats/markup.bats +6 -15
- data/bats/options-collapse.bats +26 -0
- data/bats/options.bats +1 -1
- data/bats/table.bats +8 -0
- data/bats/test_helper.bash +74 -49
- data/bats/variable-expansion.bats +46 -0
- data/bin/tab_completion.sh +1 -1
- data/docs/dev/bats-document-configuration.md +8 -1
- data/docs/dev/block-type-bash.md +1 -1
- data/docs/dev/block-type-opts.md +1 -5
- data/docs/dev/block-type-vars.md +4 -0
- data/docs/dev/import-missing.md +2 -0
- data/docs/dev/menu-cli.md +1 -1
- data/docs/dev/options-collapse.md +47 -0
- data/docs/dev/requiring-blocks.md +3 -0
- data/docs/dev/specs.md +2 -1
- data/docs/dev/table-crash.md +39 -0
- data/docs/dev/table-indent.md +26 -0
- data/docs/dev/text-decoration.md +2 -5
- data/docs/dev/variable-expansion.md +2 -4
- data/examples/bash-blocks.md +1 -1
- data/examples/block-names.md +1 -1
- data/examples/block-types.md +1 -1
- data/examples/data-files.md +1 -1
- data/examples/document_options.md +2 -2
- data/examples/indent.md +1 -1
- data/examples/interrupt.md +1 -1
- data/examples/link-blocks-vars.md +1 -1
- data/examples/linked.md +1 -1
- data/examples/linked1.md +1 -1
- data/examples/nickname.md +1 -1
- data/examples/opts-blocks-require.md +1 -1
- data/examples/opts-blocks.md +1 -1
- data/examples/opts_output_execution.md +1 -1
- data/examples/pass-through-arguments.md +1 -1
- data/examples/pause-after-execution.md +1 -1
- data/examples/port-blocks.md +1 -1
- data/examples/save.md +1 -1
- data/examples/text-markup.md +1 -1
- data/examples/variable-expansion.md +6 -2
- data/examples/vars-blocks.md +1 -1
- data/examples/wrap.md +1 -1
- data/lib/block_types.rb +4 -0
- data/lib/cached_nested_file_reader.rb +7 -4
- data/lib/collapser.rb +302 -0
- data/lib/constants.rb +10 -0
- data/lib/evaluate_shell_expressions.rb +0 -3
- data/lib/fcb.rb +13 -17
- data/lib/format_table.rb +11 -7
- data/lib/hash_delegator.rb +461 -272
- data/lib/hierarchy_string.rb +5 -1
- data/lib/markdown_exec/version.rb +1 -1
- data/lib/markdown_exec.rb +16 -32
- data/lib/mdoc.rb +100 -35
- data/lib/menu.src.yml +124 -17
- data/lib/menu.yml +102 -16
- data/lib/ww.rb +75 -22
- metadata +12 -9
- data/lib/append_to_bash_history.rb +0 -303
- data/lib/ce_get_cost_and_usage.rb +0 -23
- data/lib/doh.rb +0 -190
- data/lib/layered_hash.rb +0 -143
- data/lib/poly.rb +0 -171
data/examples/bash-blocks.md
CHANGED
data/examples/block-names.md
CHANGED
data/examples/block-types.md
CHANGED
data/examples/data-files.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
This document demonstrates the automatic loading of options in a block with a reserved name.
|
2
2
|
|
3
|
-
```opts :(
|
3
|
+
```opts :(document_opts)
|
4
4
|
menu_divider_format: "=> %{line} == %{line} <="
|
5
5
|
```
|
6
6
|
|
7
|
-
The divider below is named "Divider #1". Notice the "(
|
7
|
+
The divider below is named "Divider #1". Notice the "(document_opts)" block sets the "menu_divider_format" option to duplicate the divider name when it is displayed.
|
8
8
|
::: Divider #1
|
data/examples/indent.md
CHANGED
@@ -4,12 +4,12 @@ Indentation is either leading spaces or tabs.
|
|
4
4
|
Tabs are interpreted as 4 spaces.
|
5
5
|
|
6
6
|
## Related MDE options
|
7
|
+
divider_match | Pattern for topics/dividers in block selection menu
|
7
8
|
fenced_start_and_end_regex | Matches the start and end of a fenced code block
|
8
9
|
fenced_start_extended_regex | Match the start of a fenced block
|
9
10
|
heading1_match | MDE_HEADING1_MATCH
|
10
11
|
heading2_match | MDE_HEADING2_MATCH
|
11
12
|
heading3_match | MDE_HEADING3_MATCH
|
12
|
-
menu_divider_match | Pattern for topics/dividers in block selection menu
|
13
13
|
menu_note_match | Pattern for notes in block selection menu
|
14
14
|
menu_task_match | Pattern for tasks
|
15
15
|
|
data/examples/interrupt.md
CHANGED
data/examples/linked.md
CHANGED
data/examples/linked1.md
CHANGED
data/examples/nickname.md
CHANGED
data/examples/opts-blocks.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Demo options: output_execution_report, output_execution_summary
|
2
2
|
|
3
3
|
::: Options are initially True
|
4
|
-
```opts :(
|
4
|
+
```opts :(document_opts) +[document_options]
|
5
5
|
output_execution_report: true
|
6
6
|
output_execution_summary: true
|
7
7
|
pause_after_script_execution: true
|
data/examples/port-blocks.md
CHANGED
data/examples/save.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Demonstrate custom file names
|
2
|
-
```opts :(
|
2
|
+
```opts :(document_opts) +[custom]
|
3
3
|
pause_after_script_execution: true # for interactive demos
|
4
4
|
save_executed_script: true # demonstrate saved scripts
|
5
5
|
save_execution_output: true # demonstrate saved output
|
data/examples/text-markup.md
CHANGED
@@ -47,7 +47,7 @@ line_decor_post | Line-oriented text decoration (Post)
|
|
47
47
|
line_decor_pre | Line-oriented text decoration (Pre)
|
48
48
|
menu_note_match | Pattern for notes in block selection menu
|
49
49
|
|
50
|
-
```opts :(
|
50
|
+
```opts :(document_opts)
|
51
51
|
line_decor_post:
|
52
52
|
- :color_method: blue
|
53
53
|
:pattern: '!([^!]{0,64})!blue!'
|
@@ -68,7 +68,9 @@ glob: ${ALPHA}.sh
|
|
68
68
|
```
|
69
69
|
|
70
70
|
/ import bats-document-configuration.md
|
71
|
-
```opts :(
|
71
|
+
```opts :(document_opts)
|
72
|
+
divider4_center: false
|
73
|
+
|
72
74
|
dump_blocks_in_file: false # Dump BlocksInFile (stage 1)
|
73
75
|
dump_delegate_object: false # Dump @delegate_object
|
74
76
|
dump_inherited_lines: false # Dump inherited lines
|
@@ -88,7 +90,9 @@ script_execution_frame_color: plain
|
|
88
90
|
script_execution_head:
|
89
91
|
script_execution_tail:
|
90
92
|
|
93
|
+
table_center: false
|
94
|
+
|
91
95
|
user_must_approve: false
|
92
96
|
|
93
97
|
clear_screen_for_select_block: false
|
94
|
-
```
|
98
|
+
```
|
data/examples/vars-blocks.md
CHANGED
data/examples/wrap.md
CHANGED
@@ -100,7 +100,7 @@ shell_code_label_format_above: "# -^-"
|
|
100
100
|
shell_code_label_format_below: "# -v- +%{block_name} -o- %{document_filename} -o- %{time_now_date} -v-"
|
101
101
|
```
|
102
102
|
|
103
|
-
```opts :(
|
103
|
+
```opts :(document_opts)
|
104
104
|
execute_in_own_window: false
|
105
105
|
output_execution_report: false
|
106
106
|
output_execution_summary: false
|
data/lib/block_types.rb
CHANGED
@@ -2,7 +2,10 @@
|
|
2
2
|
|
3
3
|
class BlockType
|
4
4
|
ALL = [
|
5
|
+
CHROME = 'chrome',
|
6
|
+
DIVIDER = 'divider',
|
5
7
|
EDIT = 'edit',
|
8
|
+
HEADING = 'heading',
|
6
9
|
HISTORY = 'history',
|
7
10
|
LINK = 'link',
|
8
11
|
LOAD = 'load',
|
@@ -10,6 +13,7 @@ class BlockType
|
|
10
13
|
PORT = 'port',
|
11
14
|
SAVE = 'save',
|
12
15
|
SHELL = 'shell',
|
16
|
+
TEXT = 'text',
|
13
17
|
VARS = 'vars',
|
14
18
|
VIEW = 'view',
|
15
19
|
YAML = 'yaml'
|
@@ -39,11 +39,13 @@ class CachedNestedFileReader
|
|
39
39
|
)
|
40
40
|
end
|
41
41
|
|
42
|
-
def readlines(filename, depth = 0, context: '', import_paths: nil,
|
42
|
+
def readlines(filename, depth = 0, context: '', import_paths: nil,
|
43
|
+
indention: '', &block)
|
43
44
|
if @file_cache.key?(filename)
|
44
45
|
@file_cache[filename].each(&block) if block
|
45
46
|
return @file_cache[filename]
|
46
47
|
end
|
48
|
+
raise Errno::ENOENT, filename unless filename
|
47
49
|
|
48
50
|
directory_path = File.dirname(filename)
|
49
51
|
processed_lines = []
|
@@ -60,6 +62,8 @@ class CachedNestedFileReader
|
|
60
62
|
File.join(directory_path, name_strip)
|
61
63
|
end
|
62
64
|
|
65
|
+
raise Errno::ENOENT, name_strip unless included_file_path
|
66
|
+
|
63
67
|
processed_lines += readlines(included_file_path, depth + 1,
|
64
68
|
context: "#{filename}:#{ind + 1}",
|
65
69
|
import_paths: import_paths,
|
@@ -73,9 +77,8 @@ class CachedNestedFileReader
|
|
73
77
|
end
|
74
78
|
|
75
79
|
@file_cache[filename] = processed_lines
|
76
|
-
rescue Errno::ENOENT
|
77
|
-
|
78
|
-
warn_format('readlines', "No such file -- #{filename} @@ #{context}",
|
80
|
+
rescue Errno::ENOENT => err_filename
|
81
|
+
warn_format('readlines', "#{err_filename} @@ #{context}",
|
79
82
|
{ abort: true })
|
80
83
|
end
|
81
84
|
end
|
data/lib/collapser.rb
ADDED
@@ -0,0 +1,302 @@
|
|
1
|
+
require_relative 'constants'
|
2
|
+
|
3
|
+
class Collapser
|
4
|
+
attr_accessor :options, :state
|
5
|
+
|
6
|
+
def initialize(
|
7
|
+
collapsed_level: nil,
|
8
|
+
collapsible_types: COLLAPSIBLE_TYPES,
|
9
|
+
options: {},
|
10
|
+
state: Hash.new(nil)
|
11
|
+
)
|
12
|
+
@collapsed_level = collapsed_level
|
13
|
+
@collapsible_types = collapsible_types.dup
|
14
|
+
@options = options.dup
|
15
|
+
@state = state.dup # do not dup
|
16
|
+
end
|
17
|
+
|
18
|
+
def collapse_per_options?(fcb, options: @options)
|
19
|
+
criteria = options["#{fcb.type}#{fcb.level}_collapse".to_sym]
|
20
|
+
return false if criteria.nil?
|
21
|
+
|
22
|
+
criteria
|
23
|
+
end
|
24
|
+
|
25
|
+
def collapse_per_state?(fcb, default: false, state: @state)
|
26
|
+
return false if state.nil?
|
27
|
+
|
28
|
+
criteria = state[fcb.id]
|
29
|
+
return default if criteria.nil?
|
30
|
+
|
31
|
+
!!criteria
|
32
|
+
end
|
33
|
+
|
34
|
+
def collapse_per_token?(fcb)
|
35
|
+
fcb.token == COLLAPSIBLE_TOKEN_COLLAPSE
|
36
|
+
end
|
37
|
+
|
38
|
+
def collapsible_per_options?(fcb, options: @options)
|
39
|
+
criteria = options["#{fcb.type}#{fcb.level}_collapsible".to_sym]
|
40
|
+
return false if criteria.nil?
|
41
|
+
|
42
|
+
criteria
|
43
|
+
end
|
44
|
+
|
45
|
+
def collapsible_per_type?(fcb, collapsible_types: @collapsible_types)
|
46
|
+
@collapsible_types.nil? || @collapsible_types.include?(fcb.type)
|
47
|
+
end
|
48
|
+
|
49
|
+
def collapse?(fcb, initialize: false)
|
50
|
+
if initialize
|
51
|
+
(collapse_per_options?(fcb) || collapse_per_token?(fcb)) && !expand_per_token?(fcb)
|
52
|
+
else
|
53
|
+
collapse_per_state?(fcb, default: false)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def collapsible?(fcb)
|
58
|
+
collapsible_per_options?(fcb)
|
59
|
+
end
|
60
|
+
|
61
|
+
def expand_per_token?(fcb)
|
62
|
+
fcb.token == COLLAPSIBLE_TOKEN_EXPAND
|
63
|
+
end
|
64
|
+
|
65
|
+
def hide?(fcb,
|
66
|
+
collapsed_level: @collapsed_level,
|
67
|
+
collapsible_types: @collapsible_types,
|
68
|
+
initialize: true)
|
69
|
+
|
70
|
+
fcb.collapsible = collapsible?(fcb)
|
71
|
+
if collapsed_level.nil?
|
72
|
+
# is not collapsing
|
73
|
+
fcb.collapse = collapse?(fcb, initialize: initialize)
|
74
|
+
collapsed_level = fcb.level if fcb.collapse
|
75
|
+
fcb.hide = false
|
76
|
+
|
77
|
+
elsif fcb.level.nil?
|
78
|
+
fcb.hide = true
|
79
|
+
|
80
|
+
elsif fcb.level > collapsed_level
|
81
|
+
# Currently collapsed; evaluate for the current block
|
82
|
+
fcb.collapse = collapse?(fcb, initialize: initialize)
|
83
|
+
collapsed_level = fcb.level if fcb.collapse
|
84
|
+
fcb.hide = true # block is at a deeper level thus hidden
|
85
|
+
|
86
|
+
else
|
87
|
+
# Currently expanded; evaluate for the current block
|
88
|
+
if fcb.collapsible
|
89
|
+
fcb.collapse = collapse?(fcb, initialize: initialize)
|
90
|
+
collapsed_level = fcb.collapse ? fcb.level : nil
|
91
|
+
fcb.hide = false
|
92
|
+
elsif collapsible_per_type?(fcb)
|
93
|
+
fcb.collapsible = false
|
94
|
+
fcb.collapse = false
|
95
|
+
fcb.hide = false
|
96
|
+
else
|
97
|
+
fcb.hide = true
|
98
|
+
end
|
99
|
+
end
|
100
|
+
@state[fcb.id] = fcb.level if fcb.collapse
|
101
|
+
|
102
|
+
collapsed_level
|
103
|
+
end
|
104
|
+
|
105
|
+
# Reject rows that should be hidden based on the hierarchy
|
106
|
+
def reject(fcbs, initialize: true, &block)
|
107
|
+
analyze(fcbs, initialize: initialize, reject: true, &block)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Reject rows that should be hidden based on the hierarchy
|
111
|
+
def analyze(fcbs, initialize: true, reject: false, &block)
|
112
|
+
fcbs.reject do |fcb|
|
113
|
+
@collapsed_level = hide?(fcb, initialize: initialize)
|
114
|
+
block.call fcb, @collapsed_level if block
|
115
|
+
|
116
|
+
reject && fcb.hide
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
return if $PROGRAM_NAME != __FILE__
|
122
|
+
|
123
|
+
require 'minitest/autorun'
|
124
|
+
require_relative 'ww'
|
125
|
+
|
126
|
+
# Updated FCB struct with an id for testing
|
127
|
+
FCB = Struct.new(:id, :type, :level, :token, :collapse, :collapsible, :hide)
|
128
|
+
OPTIONS = {
|
129
|
+
divider4_collapse: false,
|
130
|
+
divider4_collapsible: true,
|
131
|
+
heading1_collapse: false,
|
132
|
+
heading1_collapsible: false,
|
133
|
+
heading2_collapse: true,
|
134
|
+
heading2_collapsible: true,
|
135
|
+
heading3_collapse: false,
|
136
|
+
heading3_collapsible: true
|
137
|
+
}.freeze
|
138
|
+
STATE = {}.freeze
|
139
|
+
|
140
|
+
class CollapserTest < Minitest::Test
|
141
|
+
def setup
|
142
|
+
@collapser = Collapser.new(collapsible_types: COLLAPSIBLE_TYPES.dup,
|
143
|
+
options: OPTIONS.dup,
|
144
|
+
state: STATE).dup
|
145
|
+
end
|
146
|
+
|
147
|
+
def test_analyze
|
148
|
+
# Define test scenarios as arrays of FCB objects and expected filtered results
|
149
|
+
|
150
|
+
# :id, :type, :level, :token
|
151
|
+
ff_h1a = ['h1a', 'heading', 1, '']
|
152
|
+
ff_h1b = ['h1b', 'heading', 1, '']
|
153
|
+
ff_h2a = ['h2a', 'heading', 2, '']
|
154
|
+
ff_h2b = ['h2b', 'heading', 2, '']
|
155
|
+
ff_t1 = ['t1', 'text', nil, '']
|
156
|
+
ff_t2 = ['t2', 'text', nil, '']
|
157
|
+
ff_t3 = ['t3', 'text', nil, '']
|
158
|
+
ff_t4 = ['t4', 'text', nil, '']
|
159
|
+
ff_h1a_collapse = ['h1a', 'heading', 1, COLLAPSIBLE_TOKEN_COLLAPSE]
|
160
|
+
ff_h1a_expand = ['h1a', 'heading', 1, COLLAPSIBLE_TOKEN_EXPAND]
|
161
|
+
ff_h1b_expand = ['h1b', 'heading', 1, COLLAPSIBLE_TOKEN_EXPAND]
|
162
|
+
|
163
|
+
# :collapse, :collapsible, :hide
|
164
|
+
cc_init = [false, false, false]
|
165
|
+
cc_collapse = [true, false, false]
|
166
|
+
cc_collapse_collapsible = [true, true, false]
|
167
|
+
cc_collapsible = [false, true, false]
|
168
|
+
cc_collapsible_hide = [false, true, true]
|
169
|
+
cc_hide = [false, false, true]
|
170
|
+
cc_undefined_hide = [nil, nil, false]
|
171
|
+
|
172
|
+
fc_h1a__init = FCB.new(*ff_h1a, *cc_init)
|
173
|
+
fc_h1b__init = FCB.new(*ff_h1b, *cc_init)
|
174
|
+
fc_h2a__init = FCB.new(*ff_h2a, *cc_init)
|
175
|
+
fc_h2b__init = FCB.new(*ff_h2b, *cc_init)
|
176
|
+
fc_t1__init = FCB.new(*ff_t1, *cc_init)
|
177
|
+
fc_t2__init = FCB.new(*ff_t2, *cc_init)
|
178
|
+
fc_t3__init = FCB.new(*ff_t3, *cc_init)
|
179
|
+
fc_t4__init = FCB.new(*ff_t4, *cc_init)
|
180
|
+
|
181
|
+
fc_h1a__collapse = FCB.new(*ff_h1a, *cc_collapse)
|
182
|
+
|
183
|
+
fc_h1a__collapse_collapsible = FCB.new(*ff_h1a, *cc_collapse_collapsible)
|
184
|
+
fc_h2a__collapse_collapsible = FCB.new(*ff_h2a, *cc_collapse_collapsible)
|
185
|
+
|
186
|
+
fc_h1a__collapsible = FCB.new(*ff_h1a, *cc_collapsible)
|
187
|
+
fc_h2a__collapsible = FCB.new(*ff_h2a, *cc_collapsible)
|
188
|
+
|
189
|
+
fc_h1a__collapsible_hide = FCB.new(*ff_h1a, *cc_collapsible_hide)
|
190
|
+
|
191
|
+
fc_t1__hide = FCB.new(*ff_t1, *cc_hide)
|
192
|
+
fc_t2__hide = FCB.new(*ff_t2, *cc_hide)
|
193
|
+
fc_h2a__hide = FCB.new(*ff_h2a, *cc_hide)
|
194
|
+
|
195
|
+
analyze_cases = {
|
196
|
+
with_token: [
|
197
|
+
{ name: 'collapse',
|
198
|
+
fcbs: [FCB.new(*ff_h1a_collapse, *cc_init)],
|
199
|
+
expected: [FCB.new(*ff_h1a_collapse, *cc_collapse)] },
|
200
|
+
{ name: 'expand',
|
201
|
+
fcbs: [FCB.new(*ff_h1a_expand, *cc_init)],
|
202
|
+
expected: [FCB.new(*ff_h1a_expand, *cc_init)] },
|
203
|
+
{ name: 'collapse, against options',
|
204
|
+
fcbs: [FCB.new(*ff_h1a_collapse, *cc_init)],
|
205
|
+
options: { heading1_collapse: false },
|
206
|
+
expected: [FCB.new(*ff_h1a_collapse, *cc_collapse)] },
|
207
|
+
{ name: 'expand, against options',
|
208
|
+
fcbs: [FCB.new(*ff_h1a_expand, *cc_init)],
|
209
|
+
options: { heading1_collapse: true },
|
210
|
+
expected: [FCB.new(*ff_h1a_expand, *cc_init)] },
|
211
|
+
],
|
212
|
+
|
213
|
+
with_no_state: [
|
214
|
+
{ name: ' ',
|
215
|
+
fcbs: [FCB.new(*ff_h1a_expand, *cc_init), fc_t1__init, fc_h2a__init, fc_t2__init, FCB.new(*ff_h1b_expand, *cc_init), fc_t3__init, fc_h2b__init, fc_t4__init],
|
216
|
+
options: { heading2_collapse: true },
|
217
|
+
expected: [FCB.new(*ff_h1a_expand, *cc_init), fc_t1__init, FCB.new(*ff_h2a, *cc_collapse), FCB.new(*ff_h1b_expand, *cc_init), fc_t3__init, FCB.new(*ff_h2b, *cc_collapse)] },
|
218
|
+
|
219
|
+
{ name: 'not collapsible',
|
220
|
+
fcbs: [fc_h1a__init],
|
221
|
+
options: {},
|
222
|
+
expected: [fc_h1a__init] },
|
223
|
+
|
224
|
+
{ name: 'collapse, not collapsible',
|
225
|
+
fcbs: [fc_h1a__init],
|
226
|
+
options: { heading1_collapse: true },
|
227
|
+
expected: [fc_h1a__collapse] },
|
228
|
+
|
229
|
+
{ name: 'collapsible, not collapsed',
|
230
|
+
fcbs: [fc_h1a__init],
|
231
|
+
options: { heading1_collapsible: true },
|
232
|
+
expected: [fc_h1a__collapsible] },
|
233
|
+
|
234
|
+
{ name: 'collapsible, not collapsed, with a dependent',
|
235
|
+
fcbs: [fc_h1a__init, fc_t1__init],
|
236
|
+
options: { heading1_collapsible: true },
|
237
|
+
expected: [fc_h1a__init, fc_t1__init] },
|
238
|
+
|
239
|
+
{ name: 'collapsible, collapsed',
|
240
|
+
fcbs: [fc_h1a__init],
|
241
|
+
options: { heading1_collapse: true,
|
242
|
+
heading1_collapsible: true },
|
243
|
+
expected: [fc_h1a__collapse_collapsible] },
|
244
|
+
|
245
|
+
{ name: 'collapsible, collapsed, with a dependent',
|
246
|
+
fcbs: [fc_h1a__init, fc_t1__init],
|
247
|
+
options: { heading1_collapse: true,
|
248
|
+
heading1_collapsible: true },
|
249
|
+
expected: [fc_h1a__collapse_collapsible,
|
250
|
+
fc_t1__hide] },
|
251
|
+
|
252
|
+
{ name: 'collapsible, collapsed, with a dependent and lower levels',
|
253
|
+
fcbs: [fc_h1a__init, fc_t1__init, fc_h2a__init],
|
254
|
+
options: { heading1_collapse: true,
|
255
|
+
heading1_collapsible: true },
|
256
|
+
expected: [fc_h1a__collapse_collapsible,
|
257
|
+
fc_t1__hide,
|
258
|
+
fc_h2a__hide] },
|
259
|
+
|
260
|
+
{ name: 'collapsible, collapsed, with a dependent and higher levels',
|
261
|
+
fcbs: [fc_h1a__init, fc_h2a__init, fc_t1__init],
|
262
|
+
options: { heading2_collapse: true,
|
263
|
+
heading2_collapsible: true },
|
264
|
+
expected: [fc_h1a__init,
|
265
|
+
fc_h2a__collapse_collapsible,
|
266
|
+
fc_t1__hide] },
|
267
|
+
],
|
268
|
+
|
269
|
+
with_empty_state: [
|
270
|
+
{ name: 'expanded remains expanded',
|
271
|
+
fcbs: [fc_h1a__init],
|
272
|
+
options: { heading1_collapsible: true },
|
273
|
+
initialize: false,
|
274
|
+
expected: [fc_h1a__collapsible] },
|
275
|
+
],
|
276
|
+
|
277
|
+
with_collapsed_state: [
|
278
|
+
{ name: 'collapsed remains collapsed',
|
279
|
+
fcbs: [fc_h1a__collapse_collapsible],
|
280
|
+
options: { heading1_collapsible: true },
|
281
|
+
state: { "h1a" => 1 },
|
282
|
+
initialize: false,
|
283
|
+
expected: [fc_h1a__collapse_collapsible] },
|
284
|
+
]
|
285
|
+
}
|
286
|
+
|
287
|
+
analyze_cases.each do |name, test_cases|
|
288
|
+
test_cases.each_with_index do |test_case, index|
|
289
|
+
@collapser = Collapser.new(collapsed_level: test_case[:collapsed_level],
|
290
|
+
collapsible_types: test_case[:collapsible_types] || COLLAPSIBLE_TYPES,
|
291
|
+
options: (test_case[:options] || OPTIONS).dup,
|
292
|
+
state: (test_case[:state] || STATE).dup)
|
293
|
+
analysis = @collapser.analyze(
|
294
|
+
test_case[:fcbs],
|
295
|
+
initialize: test_case[:initialize].nil? ? true : test_case[:initialize]
|
296
|
+
)
|
297
|
+
assert_equal test_case[:expected], analysis,
|
298
|
+
"Failed on test case #{index + 1} #{name} #{test_case[:name]}"
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
data/lib/constants.rb
CHANGED
@@ -30,6 +30,16 @@ BLOCK_TYPE_COLOR_OPTIONS = {
|
|
30
30
|
BlockType::VARS => :menu_vars_color
|
31
31
|
}.freeze
|
32
32
|
|
33
|
+
|
34
|
+
COLLAPSIBLE_SYMBOL_COLLAPSED = '⬢' # '<+>' # '∆'
|
35
|
+
COLLAPSIBLE_SYMBOL_EXPANDED = '⬡' # '< >' # '…'
|
36
|
+
|
37
|
+
# in regexp (?<collapse>[+-~]?)
|
38
|
+
COLLAPSIBLE_TOKEN_COLLAPSE = '+'
|
39
|
+
COLLAPSIBLE_TOKEN_EXPAND = '-'
|
40
|
+
|
41
|
+
COLLAPSIBLE_TYPES = [BlockType::DIVIDER, BlockType::HEADING].freeze
|
42
|
+
|
33
43
|
class ExecutionStreams
|
34
44
|
STD_ERR = :stderr
|
35
45
|
STD_IN = :stdin
|
@@ -21,11 +21,9 @@ def evaluate_shell_expressions(initial_code, expressions, shell: '/bin/bash',
|
|
21
21
|
script << "\necho #{token}#{index}\n"
|
22
22
|
script << expression << "\n"
|
23
23
|
end
|
24
|
-
# !!v script
|
25
24
|
|
26
25
|
# Execute
|
27
26
|
stdout_str, stderr_str, status = Open3.capture3(shell, "-c", script)
|
28
|
-
# !!v stdout_str, stderr_str, status
|
29
27
|
|
30
28
|
unless status.success?
|
31
29
|
raise "Shell script execution failed: #{stderr_str}"
|
@@ -38,7 +36,6 @@ def evaluate_shell_expressions(initial_code, expressions, shell: '/bin/bash',
|
|
38
36
|
result_hash[sprintf(key_format, key)] = output_parts[index].chomp
|
39
37
|
end
|
40
38
|
end
|
41
|
-
# !!v result_hash
|
42
39
|
|
43
40
|
result_hash
|
44
41
|
end
|