markdown_exec 2.7.5 → 2.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e0463a06b2bac6770c2443819a9cedee15e7aa3404649f077924074fd3c639ab
4
- data.tar.gz: 0f8b10556113950d468d92cfc11510178d7019d5b0e1c3f7ba0f61fdcab57414
3
+ metadata.gz: d752af0db5e1c1a770b64f9341c3d08e1e9bc8612230a9cb44ddc7fddc4c3051
4
+ data.tar.gz: 5ba8524b3323bd8333b82a5d0607fbb9db59a5157a1c7ae0564b3f624f26addd
5
5
  SHA512:
6
- metadata.gz: 32d0e93870011249641e929ab4c6963905321301b508831ef5b56f7be925f69857e0bab3b4f030cfe39f6a8dff83376a099bd568616df872b8d4b7291c2f5227
7
- data.tar.gz: aad2c863dd5bf6da344342e9336f6efa7045ec51d1471581b42bd26f42c1b1368d380b5f64781fb653154fd45f5f47db4d1fd7f22c8cc2f78c31a4781307b0dc
6
+ metadata.gz: 29b210e56b46a1edf099c02267e2b3c7cdae6701f7ee99d5a946d06eea7272da3534765110ec36a6de017a10d0f4833c9075c27dacb0cec8b050192d3892d748
7
+ data.tar.gz: e73cd906ce9035c8c78d2e301866af4a76bc7a730c5109fc8cc59ecf64679cb578fb04b324e700df064886d250c394c441f77850b9e21230d346d08bd92a9a5f
data/.rubocop.yml CHANGED
@@ -97,6 +97,9 @@ Style/GlobalVars:
97
97
  Style/IfUnlessModifier: # 2024-08 suggests lines that are too long
98
98
  Enabled: false
99
99
 
100
+ Style/KeywordParametersOrder:
101
+ Enabled: false
102
+
100
103
  Style/Lambda:
101
104
  Enabled: false
102
105
 
data/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.8.0] - 2025-02-10
4
+
5
+ ### Added
6
+
7
+ - Block type `ux` to facilitate the evaluation, display, and editing of shell variables.
8
+ The body of the `ux` block is in YAML.
9
+
10
+ A valid shell variable name is required as block key `name`. The remaining block keys are optional.
11
+
12
+ When the block is executed, its value is computed from the `default`, `exec`, `prompt`, `transform`, and `validate` keys and its output is assigned to the shell variable.
13
+
14
+ When a document is loaded, if one or more block names match `document_load_ux_block_name`, they are executed.
15
+ `ux_auto_load_force_default` limits the setting of the shell variable resulting from the execution of blocks executed at this time.
16
+
17
+ When an `ux` block is executed (after initial document load):
18
+ If the `default` value is the `exec` symbol, the command in the `exec` key is executed and its output is processed.
19
+ Else if the `allowed` value has one or more items, the user must pick from one of the items.
20
+ Else if the `prompt` value exists, the user must enter a value or nothing for the `default` value. The user is prompted with `prompt_ux_enter_a_value`.
21
+ Else the `default` value, as a string, is processed.
22
+
23
+ The output is validated/parsed by the regular expression in `validate`.
24
+ If the string matches, named groups are formatted with `menu_ux_row_format` and assigned to the shell variable.
25
+
26
+ The default `menu_ux_row_format` looks like a shell variable assignment.
27
+ If the output of `menu_ux_row_format` matches an immediately preceding table, the row is merged into that table.
28
+ Else the output is decorated with `menu_ux_color`.
29
+ - Improve final output of `test` Rake task so failures are visible.
30
+
3
31
  ## [2.7.5] - 2025-02-02
4
32
 
5
33
  ### Added
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- markdown_exec (2.7.5)
4
+ markdown_exec (2.8.1)
5
5
  clipboard (~> 1.3.6)
6
6
  open3 (~> 0.1.1)
7
7
  optparse (~> 0.1.1)
data/Rakefile CHANGED
@@ -155,9 +155,30 @@ end
155
155
 
156
156
  desc 'test'
157
157
  task :test do
158
- system 'bundle exec rspec'
158
+ success = true
159
+
160
+ # Run all tests and track failures
161
+ rspec_success = system('bundle exec rspec')
162
+ success = false unless rspec_success
163
+
159
164
  Rake::Task['minitest'].invoke
165
+ minitest_success = $?.success?
166
+ success = false unless minitest_success
167
+
160
168
  Rake::Task['bats'].invoke
169
+ bats_success = $?.success?
170
+ success = false unless bats_success
171
+
172
+ # Report failures and exit with non-zero status if any test failed
173
+ unless success
174
+ failed_tests = []
175
+ failed_tests << 'RSpec' unless rspec_success
176
+ failed_tests << 'Minitest' unless minitest_success
177
+ failed_tests << 'Bats' unless bats_success
178
+
179
+ puts "\nThe following test suites failed: #{failed_tests.join(', ')}"
180
+ exit 1
181
+ end
161
182
  end
162
183
 
163
184
  private
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bats
2
+
3
+ load 'test_helper'
4
+
5
+ @test 'Initial values' {
6
+ spec_mde_xansi_dname_doc_blocks_expect docs/dev/block-type-ux-auto.md \
7
+ 'v1 = _v2 = _v3 = 12_v4 = 21_v5 = markdown_exec_v6 = 31'
8
+ }
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bats
2
+
3
+ load 'test_helper'
4
+
5
+ @test 'Output of executed commands as initial value' {
6
+ spec_mde_xansi_dname_doc_blocks_expect docs/dev/block-type-ux-exec.md \
7
+ "ux0=_ux1=Unknown_ux2=markdown_exec_ux3=markdown_exec_ux4=Xform: 'markdown'"
8
+ }
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bats
2
+
3
+ load 'test_helper'
4
+
5
+ @test 'Row format merges with prior table' {
6
+ spec_mde_xansi_dname_doc_blocks_expect docs/dev/block-type-ux-row-format.md \
7
+ ' | Variable | Value | Prompt |_ | --------- | ---------------- | ------------------- |_ | Species | Pongo tapanulien | New species? |_ | Name: Gen | Value: Pongo | Prompt: New genus? |_ | Family | Hominidae | Enter a value: |'
8
+ }
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bats
2
+
3
+ load 'test_helper'
4
+
5
+ @test 'Transformed output of executed commands' {
6
+ spec_mde_xansi_dname_doc_blocks_expect docs/dev/block-type-ux-transform.md \
7
+ '_Execution output has a trailing newline._Var0=markdown_exec_00000000 6d 61 72 6b 64 6f 77 6e 5f 65 78 65 63 0a |markdown_exec.|__With validate and transform, output has no newline._Var1=markdown_exec_00000000 6d 61 72 6b 64 6f 77 6e 5f 65 78 65 63 |markdown_exec|__With transform :chomp, output has no newline._Var2=markdown_exec_00000000 6d 61 72 6b 64 6f 77 6e 5f 65 78 65 63 |markdown_exec|__With transform :upcase, output is in upper case w/ newline._Var3=MARKDOWN_EXEC_00000000 4d 41 52 4b 44 4f 57 4e 5f 45 58 45 43 0a |MARKDOWN_EXEC.|'
8
+ }
@@ -4,5 +4,5 @@ load 'test_helper'
4
4
 
5
5
  @test 'Command substitution' {
6
6
  spec_mde_xansi_dname_doc_blocks_expect docs/dev/command-substitution.md \
7
- 'CURRENT BASE NAME IS: MARKDOWN_EXEC_current base name is: markdown_exec_current base name is: markdown_exec_| current base name |_| ----------------- |_| markdown_exec |_: notice the string is not expanded in Shell block types (names or body)._ echo "current base name is now $(basename `pwd`)"__load: file_markdown_exec.sh'
7
+ 'CURRENT BASE NAME IS: MARKDOWN_EXEC_current base name is: markdown_exec_current base name is: markdown_exec_| current base name |_| ----------------- |_| markdown_exec |_: notice the string is not expanded in Shell block types (names or body)._ echo "current base name is now $(basename `pwd`)"__load: file_markdown_exec.sh_Status not zero: $(err)'
8
8
  }
@@ -4,5 +4,5 @@ load 'test_helper'
4
4
 
5
5
  @test 'Text and Headings' {
6
6
  spec_mde_xansi_dname_doc_blocks_expect docs/dev/line-wrapping.md \
7
- " DEMO WRAPPING LONG LINES__MDE detects the screen's dimensions:_height (lines) and width (characters)__Normal document text is displayed as_disabled menu lines. The width of these_lines is limited according to the screen's_width.__Test Indented Lines__ Indented with two spaces, this line_ should wrap in an aesthetically pleasing_ way.__ Indented with a tab, this line should_ wrap in an aesthetically pleasing way.__ SPECIES GENUS FAMILY ORDER CLASS PHYLUM_ KINGDOM DOMAIN_species genus family order class phylum_kingdom domain"
7
+ " DEMO WRAPPING LONG LINES__MDE detects the screen's dimensions:_height (lines) and width (characters)__Normal document text is displayed as_disabled menu lines. The width of these_lines is limited according to the_screen's width.__Test Indented Lines__ Indented with two spaces, this line_ should wrap in an aesthetically_ pleasing way.__ Indented with a tab, this line should_ wrap in an aesthetically pleasing_ way.__ SPECIES GENUS FAMILY ORDER CLASS PHYLUM_ KINGDOM DOMAIN_species genus family order class phylum_kingdom domain"
8
8
  }
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bats
2
+
3
+ load 'test_helper'
4
+
5
+ @test 'Tables - truncate columns' {
6
+ spec_mde_xansi_dname_doc_blocks_expect docs/dev/table-column-truncate.md \
7
+ 'DEMONSTRATE TRUNCATION OF TEXT IN TABLE CELLS__| Common Name | Species | Genus | Family | Year Di |_| ------------ | ------------ | ----- | ------- | ------- |_| Tapanuli Ora | Pongo tapanu | Pongo | Hominid | 2017 |_| Psychedelic | Histiophryne | Histi | Antenna | 2009 |_| Ruby Seadrag | Phyllopteryx | Phyll | Syngnat | 2015 |_| Illacme tobi | Illacme tobi | Illac | Siphono | 2016 |_| Spiny Dandel | Taraxacum ja | Tarax | Asterac | 2022 |__'
8
+ }
data/bats/table.bats CHANGED
@@ -4,7 +4,7 @@ load 'test_helper'
4
4
 
5
5
  @test 'Tables - indented' {
6
6
  spec_mde_xansi_dname_doc_blocks_expect docs/dev/table-indent.md \
7
- 'DEMONSTRATE TABLE INDENTATION__Table flush at left._Centered columns._| Common Name | Species | Genus | Family | Year Discovered |_| -------------------- | ------------------------- | ------------ | ------------- | --------------- |_| Tapanuli Orangutan | Pongo tapanuliensis | Pongo | Hominidae | 2017 |_| Psychedelic Frogfish | Histiophryne psychedelica | Histiophryne | Antennariidae | 2009 |_| Ruby Seadragon | Phyllopteryx dewysea | Phyllopteryx | Syngnathidae | 2015 |__ Table indented with two spaces._ Left-justified columns._ | Common Name | Species | Genus | Family | Year Discovered |_ | -------------------------- | -------------- | ------- | --------------- | --------------- |_ | Illacme tobini (Millipede) | Illacme tobini | Illacme | Siphonorhinidae | 2016 |__ Table indented with one tab._ Right-justified columns._ | Common Name | Species | Genus | Family | Year Discovered |_ | --------------- | ------------------- | --------- | ---------- | --------------- |_ | Spiny Dandelion | Taraxacum japonicum | Taraxacum | Asteraceae | 2022 |'
7
+ 'DEMONSTRATE TABLE INDENTATION__Table flush at left._Centered columns._| Common Name | Species | Genus | Family | Year Discover |_| ------------------ | ---------------------- | ---------- | ----------- | ------------- |_| Tapanuli Orangutan | Pongo tapanuliensis | Pongo | Hominidae | 2017 |_| Psychedelic Frogfi | Histiophryne psychedel | Histiophry | Antennariid | 2009 |_| Ruby Seadragon | Phyllopteryx dewysea | Phyllopter | Syngnathida | 2015 |__ Table indented with two spaces._ Left-justified columns._ | Common Name | Species | Genus | Family | Year Discovere |_ | ------------------------- | ------------- | ------ | -------------- | -------------- |_ | Illacme tobini (Millipede | Illacme tobin | Illacm | Siphonorhinida | 2016 |__ Table indented with one tab._ Right-justified columns._ | Common Name | Species | Genus | Family | Year Discovered |_ | --------------- | ------------------- | --------- | ---------- | --------------- |_ | Spiny Dandelion | Taraxacum japonicum | Taraxacum | Asteraceae | 2022 |'
8
8
  }
9
9
 
10
10
  @test 'Tables - invalid' {
@@ -13,7 +13,7 @@ __filedirs_all()
13
13
  }
14
14
 
15
15
  _mde_echo_version() {
16
- echo "2.7.5"
16
+ echo "2.8.1"
17
17
  }
18
18
 
19
19
  _mde() {
@@ -10,6 +10,9 @@ dump_selected_block: false # Dump selected block
10
10
  execute_in_own_window: false
11
11
 
12
12
  menu_divider_format:
13
+
14
+ menu_for_saved_lines: false
15
+
13
16
  menu_with_back: false
14
17
  menu_with_exit: false
15
18
  menu_with_shell: false
@@ -0,0 +1,43 @@
1
+ / v2025-02-08
2
+ / name only
3
+ ```ux
4
+ name: v1
5
+ ```
6
+ / name and default
7
+ / transform and validate options not applied to default
8
+ ```ux
9
+ default: 11
10
+ name: v2
11
+ ```
12
+ / name and default; auto-load
13
+ / prompt option is ignored during auto-load
14
+ ```ux :[document_ux_v3]
15
+ default: 12
16
+ name: v3
17
+ ```
18
+ / name, default, exec; auto-load static
19
+ ```ux :[document_ux_v4]
20
+ default: 21
21
+ exec: basename $(pwd)
22
+ name: v4
23
+ ```
24
+ / name, default, exec; auto-load executed `basename $(pwd)`
25
+ / allowed is ignored by exec
26
+ ```ux :[document_ux_v5]
27
+ default: :exec
28
+ exec: basename $(pwd)
29
+ name: v5
30
+ ```
31
+ / name, default, allowed; auto-load static default
32
+ ```ux :[document_ux_v6]
33
+ allowed:
34
+ - 32
35
+ - 33
36
+ default: 31
37
+ name: v6
38
+ ```
39
+ @import bats-document-configuration.md
40
+ ```opts :(document_opts)
41
+ menu_ux_row_format: '%{name} = ${%{name}}'
42
+ ux_auto_load_force_default: true
43
+ ```
@@ -0,0 +1,42 @@
1
+ / auto-load block, does not execute command to calculate
2
+ / click block to calculate
3
+ ```ux :[document_ux0]
4
+ exec: basename $(pwd)
5
+ name: ux0
6
+ ```
7
+ / auto-load block and execute command to calculate
8
+ / click block to recalculate
9
+ ```ux :[document_ux1]
10
+ default: Unknown
11
+ exec: basename $(pwd)
12
+ name: ux1
13
+ ```
14
+ / auto-load block and execute command to calculate
15
+ / click block to recalculate
16
+ ```ux :[document_ux2]
17
+ default: :exec
18
+ exec: basename $(pwd)
19
+ name: ux2
20
+ ```
21
+ / required block defining a function used in exec
22
+ ```bash :(bash3)
23
+ # function from bash3
24
+ val () { basename $(pwd) ; }
25
+ ```
26
+ ```ux :[document_ux3] +(bash3)
27
+ default: :exec
28
+ exec: val
29
+ name: ux3
30
+ ```
31
+ / default is computed
32
+ / output of execution is validated/parsed
33
+ / parsing is transformed
34
+ ```ux :[document_ux4]
35
+ default: :exec
36
+ exec: basename $(pwd)
37
+ name: ux4
38
+ transform: "Xform: '%{name}'"
39
+ validate: |
40
+ ^(?<name>.*)(_.*)$
41
+ ```
42
+ @import bats-document-configuration.md
@@ -0,0 +1,47 @@
1
+ / v2025-02-08
2
+ | Variable| Value| Prompt
3
+ | -| -| -
4
+ / auto-load default value
5
+ / custom prompt
6
+ / select list
7
+ / default value
8
+ ```ux :[document_ux_Species]
9
+ allowed:
10
+ - Pongo tapanuliensis
11
+ - Histiophryne psychedelica
12
+ - Phyllopteryx dewysea
13
+ default: Pongo tapanuliensis
14
+ name: Species
15
+ prompt: New species?
16
+ ```
17
+ / auto-load default value
18
+ / cell text is prefixed Name/Value/Prompt
19
+ / select list contains additional text
20
+ / selected value is validated with named groups
21
+ / selected value is transformed; named capture is prefixed Xform
22
+ ```ux :[document_ux_Genus]
23
+ allowed:
24
+ - 1. Pongo
25
+ - 2. Histiophryne
26
+ - 3. Phyllopteryx
27
+ default: Pongo
28
+ menu_format: "| Name: %{name}| Value: ${%{name}}| Prompt: %{prompt}"
29
+ name: Genus
30
+ prompt: New genus?
31
+ transform: "Xform: '%{name}'"
32
+ validate: |
33
+ ^\d+\. *(?<name>[^ ].*)$
34
+ ```
35
+ / default
36
+ / auto-load default value
37
+ ```ux :[document_ux_Family]
38
+ default: Hominidae
39
+ name: Family
40
+ ```
41
+ @import bats-document-configuration.md
42
+ ```opts :(document_opts)
43
+ menu_ux_row_format: '| %{name}| ${%{name}}| %{prompt}'
44
+ screen_width: 64
45
+ table_center: true
46
+ ux_auto_load_force_default: true
47
+ ```
@@ -0,0 +1,41 @@
1
+ :::
2
+ **Execution output has a trailing newline.**
3
+ ```ux :[document_ux_transform_0]
4
+ default: :exec
5
+ exec: basename $(pwd)
6
+ name: Var0
7
+ ```
8
+ $(echo -n "$Var0" | hexdump -C)
9
+ :::
10
+ **With validate and transform, output has no newline.**
11
+ ```ux :[document_ux_transform_1]
12
+ default: :exec
13
+ exec: basename $(pwd)
14
+ name: Var1
15
+ transform: '%{name}'
16
+ validate: (?<name>.+)
17
+ ```
18
+ $(echo -n "$Var1" | hexdump -C)
19
+ :::
20
+ **With transform `:chomp`, output has no newline.**
21
+ ```ux :[document_ux_transform_2]
22
+ default: :exec
23
+ exec: basename $(pwd)
24
+ name: Var2
25
+ transform: :chomp
26
+ ```
27
+ $(echo -n "$Var2" | hexdump -C)
28
+ :::
29
+ **With transform `:upcase`, output is in upper case w/ newline.**
30
+ ```ux :[document_ux_transform_3]
31
+ default: :exec
32
+ exec: basename $(pwd)
33
+ name: Var3
34
+ transform: :upcase
35
+ ```
36
+ $(echo -n "$Var3" | hexdump -C)
37
+ @import bats-document-configuration.md
38
+ ```opts :(document_opts)
39
+ divider4_collapsible: false
40
+ table_center: false
41
+ ```
@@ -11,6 +11,7 @@ echo "current base name is now $(basename `pwd`)"
11
11
  ```link
12
12
  load: file_$(basename `pwd`).sh
13
13
  ```
14
+ Status not zero: $(err)
14
15
  / This should not be evaluated $(err). It errs with "Error: HashDelegator.blocks_from_nested_files -- Shell script execution failed: /bin/bash: line 2: err: command not found"
15
16
  @import bats-document-configuration.md
16
17
  ```opts :(document_opts)
@@ -0,0 +1,17 @@
1
+ # Demonstrate Truncation of Text in Table Cells
2
+
3
+ | Common Name| Species| Genus| Family| Year Discovered
4
+ | -| -|:-|-:|:-:
5
+ | Tapanuli Orangutan| Pongo tapanuliensis| Pongo| Hominidae| 2017
6
+ | Psychedelic Frogfish| Histiophryne psychedelica| Histiophryne| Antennariidae| 2009
7
+ | Ruby Seadragon| Phyllopteryx dewysea| Phyllopteryx| Syngnathidae| 2015
8
+ | Illacme tobini (Millipede)| Illacme tobini| Illacme| Siphonorhinidae| 2016
9
+ | Spiny Dandelion| Taraxacum japonicum| Taraxacum| Asteraceae| 2022
10
+ ```
11
+ ```
12
+ @import bats-document-configuration.md
13
+ ```opts :(document_opts)
14
+ heading1_center: false
15
+ screen_width: 60
16
+ table_center: false
17
+ ```
@@ -22,5 +22,6 @@ Centered columns.
22
22
  @import bats-document-configuration.md
23
23
  ```opts :(document_opts)
24
24
  heading1_center: false
25
+ screen_width: 100
25
26
  table_center: false
26
27
  ```
data/examples/colors.md CHANGED
@@ -33,6 +33,7 @@ menu_opts_color: fg_rgbh_1f_00_1f
33
33
  menu_opts_set_color: fg_rgbh_7f_00_1f
34
34
  menu_save_color: fg_rgbh_e0_e0_20
35
35
  menu_task_color: fg_rgbh_1f_1f_1f
36
+ menu_ux_color: fg_rgbh_2f_c0_2f
36
37
  menu_vars_color: fg_rgbh_1f_a0_1f
37
38
  menu_vars_set_color: fg_rgbh_00_1f_1f
38
39
  output_execution_label_name_color: fg_rgbh_00_1f_00
@@ -60,6 +61,7 @@ menu_opts_set_color: fg_rgbh_7f_00_ff
60
61
  # menu_save_color: fg_rgbh_ea_ea_20
61
62
  menu_save_color: fg_rgbh_ff_ff_20
62
63
  menu_task_color: fg_rgbh_ff_ff_ff
64
+ menu_ux_color: fg_rgbh_df_c0_df
63
65
  menu_vars_color: fg_rgbh_ff_a0_ff
64
66
  menu_vars_set_color: fg_rgbh_00_ff_ff
65
67
  output_execution_label_name_color: fg_rgbh_00_ff_00
data/lib/block_types.rb CHANGED
@@ -14,6 +14,7 @@ class BlockType
14
14
  SAVE = 'save',
15
15
  SHELL = 'shell',
16
16
  TEXT = 'text',
17
+ UX = 'ux',
17
18
  VARS = 'vars',
18
19
  VIEW = 'view',
19
20
  YAML = 'yaml'
data/lib/constants.rb CHANGED
@@ -27,12 +27,12 @@ BLOCK_TYPE_COLOR_OPTIONS = {
27
27
  BlockType::OPTS => :menu_opts_color,
28
28
  BlockType::SAVE => :menu_save_color,
29
29
  BlockType::SHELL => :menu_bash_color,
30
+ BlockType::UX => :menu_ux_color,
30
31
  BlockType::VARS => :menu_vars_color
31
32
  }.freeze
32
33
 
33
-
34
34
  COLLAPSIBLE_SYMBOL_COLLAPSED = '⬢' # '<+>' # '∆'
35
- COLLAPSIBLE_SYMBOL_EXPANDED = '⬡' # '< >' # '…'
35
+ COLLAPSIBLE_SYMBOL_EXPANDED = '⬡' # '< >' # '…'
36
36
 
37
37
  # in regexp (?<collapse>[+-~]?)
38
38
  COLLAPSIBLE_TOKEN_COLLAPSE = '+'
@@ -100,8 +100,10 @@ end
100
100
 
101
101
  # selected block and subsequent menu state
102
102
  #
103
+ BlockSelection = Struct.new(:id)
103
104
  SelectedBlockMenuState = Struct.new(:block, :source, :state)
104
105
 
105
106
  class TtyMenu
107
+ ENABLE = nil
106
108
  DISABLE = ''
107
109
  end
@@ -5,8 +5,12 @@
5
5
 
6
6
  require 'open3'
7
7
 
8
+ class EvaluateShellExpression
9
+ StatusFail = :script_execution_failed unless const_defined?(:StatusFail)
10
+ end
11
+
8
12
  def evaluate_shell_expressions(initial_code, expressions, shell: '/bin/bash',
9
- key_format: "%%<%s>",
13
+ key_format: '%%<%s>',
10
14
  initial_code_required: false)
11
15
  # !!p initial_code expressions key_format shell
12
16
  return if (initial_code_required && (initial_code.nil? || initial_code.empty?)) ||
@@ -18,23 +22,26 @@ def evaluate_shell_expressions(initial_code, expressions, shell: '/bin/bash',
18
22
 
19
23
  # Construct a single shell script
20
24
  script = initial_code.dup
21
- expressions.each_with_index do |(key, expression), index|
25
+ expressions.each_with_index do |(_key, expression), index|
22
26
  script << "\necho #{token}#{index}\n"
23
27
  script << expression << "\n"
24
28
  end
25
29
 
26
30
  # Execute
27
- stdout_str, stderr_str, status = Open3.capture3(shell, "-c", script)
31
+ stdout_str, stderr_str, status = Open3.capture3(shell, '-c', script)
28
32
 
29
33
  unless status.success?
30
- raise "Shell script execution failed: #{stderr_str}"
34
+ return EvaluateShellExpression::StatusFail
31
35
  end
32
36
 
33
37
  # Extract output for expressions
34
38
  result_hash = {}
35
- stdout_str.split(/\n?#{token}\d+\n/)[1..-1].tap do |output_parts|
36
- expressions.each_with_index do |(key, _expression), index|
37
- result_hash[sprintf(key_format, key)] = output_parts[index].chomp
39
+ part = stdout_str.split(/\n?#{token}\d+\n/)
40
+ unless part.empty?
41
+ part[1..-1].tap do |output_parts|
42
+ expressions.each_with_index do |(key, _expression), index|
43
+ result_hash[format(key_format, key)] = output_parts[index].chomp
44
+ end
38
45
  end
39
46
  end
40
47
 
@@ -58,23 +65,23 @@ class TestShellExpressionEvaluator < Minitest::Test
58
65
  end
59
66
 
60
67
  def test_single_expression
61
- expressions = { "greeting" => "echo 'Hello, World!'" }
68
+ expressions = { 'greeting' => "echo 'Hello, World!'" }
62
69
  result = evaluate_shell_expressions(@initial_code, expressions)
63
70
 
64
- assert_equal "Hello, World!", result["%<greeting>"]
71
+ assert_equal 'Hello, World!', result['%<greeting>']
65
72
  end
66
73
 
67
74
  def test_multiple_expressions
68
75
  expressions = {
69
- "greeting" => "echo 'Hello, World!'",
70
- "date" => "date +%Y-%m-%d",
71
- "kernel" => "uname -r"
76
+ 'greeting' => "echo 'Hello, World!'",
77
+ 'date' => 'date +%Y-%m-%d',
78
+ 'kernel' => 'uname -r'
72
79
  }
73
80
  result = evaluate_shell_expressions(@initial_code, expressions)
74
81
 
75
- assert_equal "Hello, World!", result["%<greeting>"]
76
- assert_match /\d{4}-\d{2}-\d{2}/, result["%<date>"]
77
- assert_match /\d+\.\d+\.\d+/, result["%<kernel>"]
82
+ assert_equal 'Hello, World!', result['%<greeting>']
83
+ assert_match(/\d{4}-\d{2}-\d{2}/, result['%<date>'])
84
+ assert_match(/\d+\.\d+\.\d+/, result['%<kernel>'])
78
85
  end
79
86
 
80
87
  def test_empty_expressions_list
@@ -85,13 +92,11 @@ class TestShellExpressionEvaluator < Minitest::Test
85
92
  end
86
93
 
87
94
  def test_invalid_expression
88
- expressions = { "invalid" => "invalid_command" }
95
+ expressions = { 'invalid' => 'invalid_command' }
89
96
 
90
- error = assert_raises(RuntimeError) do
91
- evaluate_shell_expressions(@initial_code, expressions)
92
- end
97
+ result = evaluate_shell_expressions(@initial_code, expressions)
93
98
 
94
- assert_match /Shell script execution failed/, error.message
99
+ assert_equal EvaluateShellExpression::StatusFail, result
95
100
  end
96
101
 
97
102
  def test_initial_code_execution
@@ -99,17 +104,17 @@ class TestShellExpressionEvaluator < Minitest::Test
99
104
  #!/bin/sh
100
105
  echo "Custom setup message"
101
106
  BASH
102
- expressions = { "test" => "echo Test after initial setup" }
107
+ expressions = { 'test' => 'echo Test after initial setup' }
103
108
 
104
109
  result = evaluate_shell_expressions(initial_code, expressions)
105
110
 
106
- assert_equal "Test after initial setup", result["%<test>"]
111
+ assert_equal 'Test after initial setup', result['%<test>']
107
112
  end
108
113
 
109
114
  def test_large_number_of_expressions
110
- expressions = (1..100).map { |i|
115
+ expressions = (1..100).map do |i|
111
116
  ["expr_#{i}", "echo Expression #{i}"]
112
- }.to_h
117
+ end.to_h
113
118
 
114
119
  result = evaluate_shell_expressions(@initial_code, expressions)
115
120