howzit 2.1.25 → 2.1.27

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: 330829109ccbd73e32ce82690327d2776c1a2f4e60004165fbcde80bdb2b68d6
4
- data.tar.gz: 402805ec02154f4ed0f219bc8975be8b1f24e5ca8726e2eb6040f905f32854c7
3
+ metadata.gz: cfddcd9969d36eaa46a5441a912b60a0d4622c7536ffd34c6aebe83cc3c840a3
4
+ data.tar.gz: 9e5d7fee17c7931fc03b455eebe411f1490e1c27d70545f5e5a3d62f492a2f50
5
5
  SHA512:
6
- metadata.gz: 6f6f3ad81b25dc520f43a4ba1ca063a093dece43129c5ba86ed4364ecc4de5d9222f86ba64dbc91220d73197586846d92ff7f7b98251739881a3d140f453c0ea
7
- data.tar.gz: 7b5eef5eb1cca9c57e3f7fa7af222911d43790b15bfb30b682c1c6f521cd1c54f8995a357141f1533830c888b91d79b107f3ec295b6238360719e1a6f2bb6032
6
+ metadata.gz: '019b3813e1f3ed8a79f70711a0f2dae38a83f0cfca205a32d9ab14794ba9815ce8d971d26f6bed0afbb90ce9d4ffd5d0d926cf50ef965cf806ffa45565203611'
7
+ data.tar.gz: c77fdeea70957604027d8152517498e8fe6df7043f36e139f8a81b23daca958d701a2dda786385921a6d9bf5c01acaca068375e7d3b9bd680091a3e988275069
data/CHANGELOG.md CHANGED
@@ -1,3 +1,23 @@
1
+ ### 2.1.27
2
+
3
+ 2025-12-26 08:59
4
+
5
+ #### IMPROVED
6
+
7
+ - Task titles now support variable substitution using ${VAR} syntax, so titles like "@run(echo test) Title with ${var}" will replace ${var} with its value from topic metadata. This applies to all task types (run, copy, open, include) and code block titles.
8
+
9
+ #### FIXED
10
+
11
+ - Task and topic names containing dollar signs (like $text$ or ${VAR}) now display correctly in run report output without causing color code interpretation issues. Dollar signs are properly escaped during formatting and unescaped in the final output.
12
+
13
+ ### 2.1.26
14
+
15
+ 2025-12-26 04:53
16
+
17
+ #### FIXED
18
+
19
+ - Bash script variables in run blocks now preserve ${VAR} syntax when the variable is not defined by howzit, allowing bash to handle them normally instead of being replaced with empty strings.
20
+
1
21
  ### 2.1.25
2
22
 
3
23
  2025-12-19 07:41
data/lib/howzit/colors.rb CHANGED
@@ -288,8 +288,8 @@ module Howzit
288
288
  d: dark, b: bold, u: underline, i: italic, x: reset }
289
289
 
290
290
  result = fmt.empty? ? input : format(fmt, colors)
291
- # Unescape braces that were escaped to prevent color code interpretation
292
- result.gsub(/\\\{/, '{').gsub(/\\\}/, '}')
291
+ # Unescape braces and dollar signs that were escaped to prevent color code interpretation
292
+ result.gsub(/\\\{/, '{').gsub(/\\\}/, '}').gsub(/\\\$/, '$')
293
293
  end
294
294
  end
295
295
 
@@ -30,13 +30,13 @@ module Howzit
30
30
  symbol = entry[:success] ? '✅' : '❌'
31
31
  parts = ["#{symbol} "]
32
32
  if prefix_topic && entry[:topic] && !entry[:topic].empty?
33
- # Escape braces in topic name to prevent color code interpretation
34
- topic_escaped = entry[:topic].gsub(/\{/, '\\{').gsub(/\}/, '\\}')
33
+ # Escape braces and dollar signs in topic name to prevent color code interpretation
34
+ topic_escaped = entry[:topic].gsub(/\{/, '\\{').gsub(/\}/, '\\}').gsub(/\$/, '\\$')
35
35
  parts << "{bw}#{topic_escaped}{x}: "
36
36
  end
37
- # Escape braces in task name to prevent color code interpretation
38
- task_escaped = entry[:task].gsub(/\{/, '\\{').gsub(/\}/, '\\}')
39
- parts << "{by}#{task_escaped}{x}"
37
+ # Escape braces and dollar signs in task name to prevent color code interpretation
38
+ task_escaped = entry[:task].gsub(/\{/, '\\{').gsub(/\}/, '\\}').gsub(/\$/, '\\$')
39
+ parts << "{by}#{task_escaped} {x}"
40
40
  unless entry[:success]
41
41
  reason = entry[:exit_status] ? "exit code #{entry[:exit_status]}" : 'failed'
42
42
  parts << " {br}(#{reason}){x}"
@@ -82,15 +82,15 @@ module Howzit
82
82
  task_parts_plain = []
83
83
 
84
84
  if prefix_topic && entry[:topic] && !entry[:topic].empty?
85
- # Escape braces in topic name to prevent color code interpretation
86
- topic_escaped = entry[:topic].gsub(/\{/, '\\{').gsub(/\}/, '\\}')
85
+ # Escape braces and dollar signs in topic name to prevent color code interpretation
86
+ topic_escaped = entry[:topic].gsub(/\{/, '\\{').gsub(/\}/, '\\}').gsub(/\$/, '\\$')
87
87
  task_parts << "{bw}#{topic_escaped}{x}: "
88
88
  task_parts_plain << "#{entry[:topic]}: "
89
89
  end
90
90
 
91
- # Escape braces in task name to prevent color code interpretation
92
- task_escaped = entry[:task].gsub(/\{/, '\\{').gsub(/\}/, '\\}')
93
- task_parts << "{by}#{task_escaped}{x}"
91
+ # Escape braces and dollar signs in task name to prevent color code interpretation
92
+ task_escaped = entry[:task].gsub(/\{/, '\\{').gsub(/\}/, '\\}').gsub(/\$/, '\\$')
93
+ task_parts << "{by}#{task_escaped} {x}"
94
94
  task_parts_plain << entry[:task]
95
95
 
96
96
  unless entry[:success]
@@ -337,7 +337,14 @@ module Howzit
337
337
  gsub!(/\$\{(?<name>[A-Z0-9_]+(?::.*?)?)\}/i) do
338
338
  m = Regexp.last_match
339
339
  arg, default = m['name'].split(/:/).map(&:strip)
340
- Howzit.named_arguments.key?(arg) && !Howzit.named_arguments[arg].nil? ? Howzit.named_arguments[arg] : default
340
+ if Howzit.named_arguments && Howzit.named_arguments.key?(arg) && !Howzit.named_arguments[arg].nil?
341
+ Howzit.named_arguments[arg]
342
+ elsif default
343
+ default
344
+ else
345
+ # Preserve the original ${VAR} syntax if variable is not defined and no default provided
346
+ m[0]
347
+ end
341
348
  end
342
349
  end
343
350
 
data/lib/howzit/topic.rb CHANGED
@@ -302,26 +302,31 @@ module Howzit
302
302
  title: title.dup, # Make a copy to avoid reference issues
303
303
  action: obj,
304
304
  parent: self }
305
+ # Set named_arguments before processing titles for variable substitution
306
+ Howzit.named_arguments = @named_args
305
307
  case cmd
306
308
  when /include/i
307
309
  if title =~ /\[(.*?)\] *$/
308
- Howzit.named_arguments = @named_args
309
310
  args = Regexp.last_match(1).split(/ *, */).map(&:render_arguments)
310
311
  Howzit.arguments = args
311
312
  arguments
312
313
  title.sub!(/ *\[.*?\] *$/, '')
313
- task_args[:title] = title
314
314
  end
315
+ # Apply variable substitution to title after bracket processing
316
+ task_args[:title] = title.render_arguments
315
317
 
316
318
  task_args[:type] = :include
317
319
  task_args[:arguments] = Howzit.named_arguments
318
320
  when /run/i
319
321
  task_args[:type] = :run
322
+ task_args[:title] = title.render_arguments
320
323
  when /copy/i
321
324
  task_args[:type] = :copy
322
325
  task_args[:action] = Shellwords.escape(obj)
326
+ task_args[:title] = title.render_arguments
323
327
  when /open|url/i
324
328
  task_args[:type] = :open
329
+ task_args[:title] = title.render_arguments
325
330
  end
326
331
 
327
332
  task_args
@@ -373,6 +378,8 @@ module Howzit
373
378
  if c[:cmd].nil?
374
379
  optional, default = define_optional(c[:optional2])
375
380
  title = c[:title2].nil? ? '' : c[:title2].strip
381
+ # Apply variable substitution to block title
382
+ title = title.render_arguments if title && !title.empty?
376
383
  block = c[:block]&.strip
377
384
  runnable << Howzit::Task.new({ type: :block,
378
385
  title: title,
@@ -3,5 +3,5 @@
3
3
  # Primary module for this gem.
4
4
  module Howzit
5
5
  # Current Howzit version.
6
- VERSION = '2.1.25'
6
+ VERSION = '2.1.27'
7
7
  end
@@ -47,5 +47,25 @@ describe Howzit::RunReport do
47
47
  # Second line should be separator
48
48
  expect(lines[1]).to match(/^\|[\s:-]+\|[\s:-]+\|$/)
49
49
  end
50
+
51
+ it 'preserves dollar signs in task names without interfering with color codes' do
52
+ Howzit::RunReport.log({ topic: 'Test Topic', task: '$text$', success: true, exit_status: 0 })
53
+ Howzit::RunReport.log({ topic: 'Test', task: 'echo ${VAR}', success: true, exit_status: 0 })
54
+ plain = Howzit::RunReport.format.uncolor
55
+ expect(plain).to include('$text$')
56
+ expect(plain).to include('${VAR}')
57
+ # Verify dollar signs are preserved and not causing color code issues
58
+ expect(plain).not_to include('{x}')
59
+ expect(plain.scan(/\$\{x\}/).length).to eq(0)
60
+ end
61
+
62
+ it 'preserves dollar signs in topic names without interfering with color codes' do
63
+ Howzit.multi_topic_run = true
64
+ Howzit::RunReport.log({ topic: '$dollar$ Topic', task: 'Some Task', success: true, exit_status: 0 })
65
+ plain = Howzit::RunReport.format.uncolor
66
+ expect(plain).to include('$dollar$ Topic')
67
+ expect(plain).not_to include('{x}')
68
+ expect(plain.scan(/\$\{x\}/).length).to eq(0)
69
+ end
50
70
  end
51
71
 
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'StringUtils' do
6
+ describe '#render_named_placeholders' do
7
+ before do
8
+ Howzit.named_arguments = {}
9
+ end
10
+
11
+ it 'preserves ${VAR} syntax when variable is not defined' do
12
+ str = 'echo ${MY_VAR}'.dup
13
+ str.render_named_placeholders
14
+ expect(str).to eq('echo ${MY_VAR}')
15
+ end
16
+
17
+ it 'preserves ${VAR} syntax for multiple undefined variables' do
18
+ str = 'echo ${VAR1} and ${VAR2}'.dup
19
+ str.render_named_placeholders
20
+ expect(str).to eq('echo ${VAR1} and ${VAR2}')
21
+ end
22
+
23
+ it 'replaces ${VAR} with value when variable is defined' do
24
+ Howzit.named_arguments = { 'MY_VAR' => 'hello' }
25
+ str = 'echo ${MY_VAR}'.dup
26
+ str.render_named_placeholders
27
+ expect(str).to eq('echo hello')
28
+ end
29
+
30
+ it 'uses default value when variable is not defined but default is provided' do
31
+ str = 'echo ${MY_VAR:default_value}'.dup
32
+ str.render_named_placeholders
33
+ expect(str).to eq('echo default_value')
34
+ end
35
+
36
+ it 'replaces variable when defined even if default is provided' do
37
+ Howzit.named_arguments = { 'MY_VAR' => 'actual_value' }
38
+ str = 'echo ${MY_VAR:default_value}'.dup
39
+ str.render_named_placeholders
40
+ expect(str).to eq('echo actual_value')
41
+ end
42
+
43
+ it 'preserves ${VAR} in bash script blocks' do
44
+ script = <<~SCRIPT
45
+ #!/bin/bash
46
+ echo "The value is ${ENV_VAR}"
47
+ echo "Another ${OTHER_VAR}"
48
+ SCRIPT
49
+ str = script.dup
50
+ str.render_named_placeholders
51
+ expect(str).to eq(script)
52
+ end
53
+
54
+ it 'handles mixed defined and undefined variables' do
55
+ Howzit.named_arguments = { 'DEFINED_VAR' => 'value1' }
56
+ str = 'echo ${DEFINED_VAR} and ${UNDEFINED_VAR}'.dup
57
+ str.render_named_placeholders
58
+ expect(str).to eq('echo value1 and ${UNDEFINED_VAR}')
59
+ end
60
+
61
+ it 'handles nil named_arguments gracefully' do
62
+ Howzit.named_arguments = nil
63
+ str = 'echo ${MY_VAR}'.dup
64
+ expect { str.render_named_placeholders }.not_to raise_error
65
+ expect(str).to eq('echo ${MY_VAR}')
66
+ end
67
+ end
68
+
69
+ describe '#render_arguments' do
70
+ before do
71
+ Howzit.named_arguments = {}
72
+ Howzit.arguments = nil
73
+ end
74
+
75
+ it 'preserves ${VAR} syntax through render_arguments' do
76
+ str = 'echo ${BASH_VAR}'.dup
77
+ result = str.render_arguments
78
+ expect(result).to eq('echo ${BASH_VAR}')
79
+ end
80
+ end
81
+ end
82
+
data/spec/topic_spec.rb CHANGED
@@ -101,4 +101,33 @@ describe Howzit::Topic do
101
101
  expect(topic.print_out({ single: true, header: true }).join("\n").uncolor).to match(/▶ ls -1/)
102
102
  end
103
103
  end
104
+
105
+
106
+ describe '.arguments' do
107
+ before do
108
+ Howzit.arguments = []
109
+ end
110
+
111
+ it 'extracts named arguments from topic title with defaults' do
112
+ topic = Howzit::Topic.new('Test Topic (var1:default1, var2:default2)', 'Content')
113
+ expect(topic.named_args['var1']).to eq('default1')
114
+ expect(topic.named_args['var2']).to eq('default2')
115
+ end
116
+
117
+ it 'does nothing when title has no arguments' do
118
+ topic = Howzit::Topic.new('Test Topic', 'Content')
119
+ expect(topic.named_args).to eq({})
120
+ end
121
+
122
+ it 'cleans title after extracting arguments' do
123
+ topic = Howzit::Topic.new('Test Topic (var:val)', 'Content')
124
+ expect(topic.title).to eq('Test Topic')
125
+ end
126
+
127
+ it 'uses provided arguments over defaults' do
128
+ Howzit.arguments = ['provided_value']
129
+ topic = Howzit::Topic.new('Test Topic (var:default_value)', 'Content')
130
+ expect(topic.named_args['var']).to eq('provided_value')
131
+ end
132
+ end
104
133
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: howzit
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.25
4
+ version: 2.1.27
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra
@@ -315,6 +315,7 @@ files:
315
315
  - spec/ruby_gem_spec.rb
316
316
  - spec/run_report_spec.rb
317
317
  - spec/spec_helper.rb
318
+ - spec/stringutils_spec.rb
318
319
  - spec/task_spec.rb
319
320
  - spec/topic_spec.rb
320
321
  - spec/util_spec.rb
@@ -349,6 +350,7 @@ test_files:
349
350
  - spec/ruby_gem_spec.rb
350
351
  - spec/run_report_spec.rb
351
352
  - spec/spec_helper.rb
353
+ - spec/stringutils_spec.rb
352
354
  - spec/task_spec.rb
353
355
  - spec/topic_spec.rb
354
356
  - spec/util_spec.rb