cli_class_tool 1.0.0 → 2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 26a3ec0d29127e28be8a7f8d5cdeccf36dbe19fa2ef06d7cd11f82caf4963dd8
4
- data.tar.gz: 8a210596d6735be7f3a5f41df93b43c023b46315055f5c5622c833e0de743da8
3
+ metadata.gz: 6c961eaba9a0c3c12f12b82c9f7414e1f33370b242c73cab1f5d8d7d3f6459f6
4
+ data.tar.gz: 9ca127c47253b78a57908f55a2951d69c492f127fc45072927b13c935432c375
5
5
  SHA512:
6
- metadata.gz: 72e72cbdcbaf6eac25b87f57ae63f628e4ea28b7e7093d7473fc5324751b459de25a6f49986c10ae7ded00390f57b0534c502e49a80471340d9cf54bd22600fb
7
- data.tar.gz: 18df3b843eae58f00e46eddcc24b3c38183c57dfcf835a57bc21f0ec12ecca967d1e4712c100810b80c4e4dba3fa2b6f1c2de4ceb5e6dda49ea08e48b5ce8f4d
6
+ metadata.gz: ea040b33b39357299b3879dffdce2692ac97d8e90101c53344440642e3a11f73d9308161c70a15d265eef5ad6dd39ba115f7f9e00549941a53bc7a8a906a3a5f
7
+ data.tar.gz: 70436783a49a9cfb90a42ccdca5a0016954483b9a82b1df0db29e570c6416784c42c81c0e0746cfe11471442038021c0371987bfe5b01e04945f649d213c8849
data/CHANGELOG CHANGED
@@ -1,3 +1,18 @@
1
+ ------------------
2
+ 2.0.0 (2026-09-18)
3
+ ------------------
4
+
5
+ * Refactor Common.run, runSystem, runGit, and runGitInteractive to accept optional named arguments (env:, catch_err:, silent_err:)
6
+ * Replace check_err positional boolean with catch_err: keyword argument (default: false) across all run methods
7
+ * Replace opts[:env] with env: keyword argument across all run methods
8
+ * Add silent_err: keyword argument to redirect stderr to /dev/null
9
+
10
+ ------------------
11
+ 1.1.0 (2026-09-09)
12
+ ------------------
13
+
14
+ * Extend String class with support for all 16 standard/high-intensity ANSI colors and a chainable `.bold` method that merges ANSI escape sequences
15
+
1
16
  ------------------
2
17
  1.0.0 (2026-09-09)
3
18
  ------------------
data/README.md CHANGED
@@ -207,6 +207,48 @@ confirm(opts, "format the disk", ignored_default: true)
207
207
 
208
208
  ---
209
209
 
210
+ ## Command Execution (`run`, `runSystem`, `runGit`, `runGitInteractive`)
211
+
212
+ `CLIClassTool::Common` provides shell and git execution methods that run within the context of the instance's target `@path`.
213
+
214
+ ### Available Methods
215
+
216
+ - `run(cmd, env: nil, catch_err: false, silent_err: false)`: Executes a command in a subshell, returning the stripped stdout (`String`).
217
+ - `CLIClassTool::Common.run(path, cmd, env: nil, catch_err: false, silent_err: false)`: Class method convenience helper that instantiates a `Common` object for `path` and runs `cmd`.
218
+ - `runSystem(cmd, env: nil, catch_err: false, silent_err: false)`: Executes a command interactively using `system()`, returning `true` on success and `false` on failure.
219
+ - `runGit(cmd, env: nil, catch_err: false, silent_err: false)`: Runs `git #{cmd}` in a subshell, returning the stripped stdout (`String`).
220
+ - `runGitInteractive(cmd, env: nil, catch_err: false, silent_err: false)`: Runs `git #{cmd}` interactively using `system()`, returning `true` on success and `false` on failure.
221
+
222
+ ### Optional Named Arguments
223
+
224
+ - `env` (`String`, default: `nil`): Optional environment variable prefix prepended to the command (e.g. `env: "FOO=bar"` or `env: "GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=user.name GIT_CONFIG_VALUE_0=TestRunner"`).
225
+ - `catch_err` (`Boolean`, default: `false`): Controls error handling on non-zero exit codes:
226
+ - `catch_err: false` (default): Command failures abort and raise a project-specific `RunError`.
227
+ - `catch_err: true`: Suppresses raising `RunError`, returning the command output (or `false` for `system` methods).
228
+ - `silent_err` (`Boolean`, default: `false`): When `true`, redirects stderr output to `/dev/null` (`2>/dev/null`).
229
+
230
+ ### Examples
231
+
232
+ ```ruby
233
+ # Basic execution (raises RunError if command exits non-zero)
234
+ branch = run("git rev-parse --abbrev-ref HEAD")
235
+
236
+ # Running with environment variables
237
+ run("make", env: "CC=clang CFLAGS='-O2'")
238
+
239
+ # Suppressing errors on expected failures
240
+ output = run("grep -r 'pattern' .", catch_err: true)
241
+
242
+ # Suppressing error output (stderr redirected to /dev/null)
243
+ runGit("rev-parse --verify non_existing_ref", catch_err: true, silent_err: true)
244
+
245
+ # Interactive execution via system()
246
+ runSystem("make menuconfig")
247
+ runGitInteractive("rebase -i origin/main")
248
+ ```
249
+
250
+ ---
251
+
210
252
  ## Dynamic Class Overrides (Addons)
211
253
 
212
254
  `CLIClassTool` natively supports dynamic class overrides (addons). This allows projects to load repository-specific or custom subclasses that extend or override base action behaviors without modifying the core codebase.
@@ -421,4 +463,28 @@ rescue MyProjectError => e
421
463
  end
422
464
  ```
423
465
 
466
+ ---
467
+
468
+ ## String Colorization & Styling Extension
469
+
470
+ `CLIClassTool` extends the core Ruby `String` class with standard ANSI escape sequence methods for terminal colorization and formatting.
471
+
472
+ ### 16-Color Palette Support
473
+
474
+ The following color methods are available on any string:
475
+
476
+ * **Standard Colors**: `.black`, `.red`, `.green`, `.brown` (alias `.yellow`), `.blue`, `.magenta`, `.cyan`, `.white`
477
+ * **High-Intensity / Bright Colors**: `.gray` (alias `.grey`), `.light_red`, `.light_green`, `.light_yellow`, `.light_blue`, `.light_magenta`, `.light_cyan`, `.light_white`
478
+
479
+ ### Bold Mode and Method Chaining
480
+
481
+ You can style text as bold using the `.bold` method. All methods support seamless chaining/merging, meaning ANSI escape sequences are parsed and merged into a single escape code (e.g., `\e[1;31m`) rather than nested redundantly.
482
+
483
+ ```ruby
484
+ puts "Success!".green # Green text
485
+ puts "Warning!".brown.bold # Bold brown (yellow) text
486
+ puts "Fatal Error!".bold.red # Bold red text
487
+ puts "System Message".bold # Bold text using default terminal color
424
488
  ```
489
+
490
+ These methods automatically check if `$stdout` is a TTY and safely fall back to standard, unformatted strings if output is piped or redirected (non-TTY mode).
@@ -136,12 +136,12 @@ module CLIClassTool
136
136
 
137
137
  private
138
138
  # Raise error if system command failed
139
- # @param check_err [Boolean] Whether to check for errors
139
+ # @param catch_err [Boolean] Whether to catch (suppress raising) errors
140
140
  # @param sysret [Process::Status] System return status
141
141
  # @param ret [String, nil] Optional return message
142
- # @raise [StandardError] If command failed
143
- def abort_if_err(check_err, sysret, ret = nil)
144
- if sysret.exitstatus != 0 && check_err == true
142
+ # @raise [StandardError] If command failed and catch_err is false
143
+ def abort_if_err(catch_err, sysret, ret = nil)
144
+ if sysret.exitstatus != 0 && !catch_err
145
145
  unless parent_module.const_defined?(:RunError)
146
146
  raise "CLIClassTool parent module #{parent_module} must extend CLIClassTool::Utils to define RunError"
147
147
  end
@@ -177,58 +177,73 @@ module CLIClassTool
177
177
  # Run a shell command
178
178
  #
179
179
  # @param cmd [String] Command to run
180
- # @param check_err [Boolean] Raise error on failure
180
+ # @param env [String, nil] Environment variable prefix (e.g., "FOO=bar")
181
+ # @param catch_err [Boolean] If true, do not raise error on failure
182
+ # @param silent_err [Boolean] If true, redirect stderr to /dev/null
181
183
  # @return [String] Command output
182
- # @raise [StandardError] If command fails and check_err is true
183
- def run(cmd, check_err = true)
184
+ # @raise [StandardError] If command fails and catch_err is false
185
+ def run(cmd, env: nil, catch_err: false, silent_err: false)
184
186
  cmd_debug('', cmd)
185
- ret = `cd #{@path} && #{cmd}`.chomp()
186
- abort_if_err(check_err, $?, ret)
187
+ env_prefix = env ? "#{env} " : ""
188
+ redirect = silent_err ? " 2>/dev/null" : ""
189
+ ret = `cd #{@path} && #{env_prefix}#{cmd}#{redirect}`.chomp()
190
+ abort_if_err(catch_err, $?, ret)
187
191
  return ret
188
192
  end
189
193
 
190
- def self.run(path, cmd, check_err = true)
194
+ def self.run(path, cmd, env: nil, catch_err: false, silent_err: false)
191
195
  obj = Common.new(path, self)
192
- return obj.run(cmd, check_err)
196
+ return obj.run(cmd, env: env, catch_err: catch_err, silent_err: silent_err)
193
197
  end
198
+
194
199
  # Run a shell command using system() (interactive)
195
200
  #
196
201
  # @param cmd [String] Command to run
197
- # @param check_err [Boolean] Raise error on failure
202
+ # @param env [String, nil] Environment variable prefix (e.g., "FOO=bar")
203
+ # @param catch_err [Boolean] If true, do not raise error on failure
204
+ # @param silent_err [Boolean] If true, redirect stderr to /dev/null
198
205
  # @return [Boolean] Command success status
199
- # @raise [StandardError] If command fails and check_err is true
200
- def runSystem(cmd, check_err = true)
206
+ # @raise [StandardError] If command fails and catch_err is false
207
+ def runSystem(cmd, env: nil, catch_err: false, silent_err: false)
201
208
  cmd_debug('interactive', cmd)
202
- ret = system("cd #{@path} && #{cmd}")
203
- abort_if_err(check_err, $?)
209
+ env_prefix = env ? "#{env} " : ""
210
+ redirect = silent_err ? " 2>/dev/null" : ""
211
+ ret = system("cd #{@path} && #{env_prefix}#{cmd}#{redirect}")
212
+ abort_if_err(catch_err, $?)
204
213
  return ret
205
214
  end
206
215
 
207
216
  # Run a git command
208
217
  #
209
218
  # @param cmd [String] Git command arguments
210
- # @param opts [Hash] Options (e.g., :env)
211
- # @param check_err [Boolean] Raise error on failure
219
+ # @param env [String, nil] Environment variable prefix (e.g., "FOO=bar")
220
+ # @param catch_err [Boolean] If true, do not raise error on failure
221
+ # @param silent_err [Boolean] If true, redirect stderr to /dev/null
212
222
  # @return [String] Command output
213
- # @raise [StandardError] If command fails and check_err is true
214
- def runGit(cmd, opts={}, check_err = true)
223
+ # @raise [StandardError] If command fails and catch_err is false
224
+ def runGit(cmd, env: nil, catch_err: false, silent_err: false)
215
225
  cmd_debug('git', cmd)
216
- ret = `cd #{@path} && #{opts[:env]} git #{cmd}`.chomp()
217
- abort_if_err(check_err, $?, ret)
226
+ env_prefix = env ? "#{env} " : ""
227
+ redirect = silent_err ? " 2>/dev/null" : ""
228
+ ret = `cd #{@path} && #{env_prefix}git #{cmd}#{redirect}`.chomp()
229
+ abort_if_err(catch_err, $?, ret)
218
230
  return ret
219
231
  end
220
232
 
221
233
  # Run a git command interactively
222
234
  #
223
235
  # @param cmd [String] Git command arguments
224
- # @param opts [Hash] Options (e.g., :env)
225
- # @param check_err [Boolean] Raise error on failure
236
+ # @param env [String, nil] Environment variable prefix (e.g., "FOO=bar")
237
+ # @param catch_err [Boolean] If true, do not raise error on failure
238
+ # @param silent_err [Boolean] If true, redirect stderr to /dev/null
226
239
  # @return [Boolean] Command success status
227
- # @raise [StandardError] If command fails and check_err is true
228
- def runGitInteractive(cmd, opts={}, check_err = true)
240
+ # @raise [StandardError] If command fails and catch_err is false
241
+ def runGitInteractive(cmd, env: nil, catch_err: false, silent_err: false)
229
242
  cmd_debug('git interactive', cmd)
230
- ret = system("cd #{@path} && #{opts[:env]} git #{cmd}")
231
- abort_if_err(check_err, $?)
243
+ env_prefix = env ? "#{env} " : ""
244
+ redirect = silent_err ? " 2>/dev/null" : ""
245
+ ret = system("cd #{@path} && #{env_prefix}git #{cmd}#{redirect}")
246
+ abort_if_err(catch_err, $?)
232
247
  return ret
233
248
  end
234
249
 
@@ -10,12 +10,33 @@ class String
10
10
  def colorize(color_code)
11
11
  @@is_a_tty = $stdout.isatty() if @@is_a_tty == nil
12
12
  if @@is_a_tty then
13
- return "\e[#{color_code}m#{self}\e[0m"
13
+ if self =~ /\A\e\[([\d;]+)m(.*)\e\[0m\z/
14
+ codes = $1.split(';')
15
+ content = $2
16
+ new_codes = codes.dup
17
+ if color_code.to_i == 1
18
+ new_codes.unshift("1") unless new_codes.include?("1")
19
+ else
20
+ new_codes.reject! { |c| (30..37).include?(c.to_i) || (90..97).include?(c.to_i) }
21
+ new_codes << color_code.to_s
22
+ end
23
+ new_codes.uniq!
24
+ new_codes.sort_by! { |c| c.to_i }
25
+ return "\e[#{new_codes.join(';')}m#{content}\e[0m"
26
+ else
27
+ return "\e[#{color_code}m#{self}\e[0m"
28
+ end
14
29
  else
15
30
  return self
16
31
  end
17
32
  end
18
33
 
34
+ # Make the string black
35
+ # @return [String] Black string
36
+ def black
37
+ colorize(30)
38
+ end
39
+
19
40
  # Make the string red
20
41
  # @return [String] Red string
21
42
  def red
@@ -34,6 +55,12 @@ class String
34
55
  colorize(33)
35
56
  end
36
57
 
58
+ # Make the string yellow
59
+ # @return [String] Yellow string
60
+ def yellow
61
+ colorize(33)
62
+ end
63
+
37
64
  # Make the string blue
38
65
  # @return [String] Blue string
39
66
  def blue
@@ -45,4 +72,71 @@ class String
45
72
  def magenta
46
73
  colorize(35)
47
74
  end
75
+
76
+ # Make the string cyan
77
+ # @return [String] Cyan string
78
+ def cyan
79
+ colorize(36)
80
+ end
81
+
82
+ # Make the string white
83
+ # @return [String] White string
84
+ def white
85
+ colorize(37)
86
+ end
87
+
88
+ # Make the string bold
89
+ # @return [String] Bold string
90
+ def bold
91
+ colorize(1)
92
+ end
93
+
94
+ # Make the string gray/grey / light black
95
+ # @return [String] Gray string
96
+ def gray
97
+ colorize(90)
98
+ end
99
+ alias grey gray
100
+
101
+ # Make the string light red
102
+ # @return [String] Light red string
103
+ def light_red
104
+ colorize(91)
105
+ end
106
+
107
+ # Make the string light green
108
+ # @return [String] Light green string
109
+ def light_green
110
+ colorize(92)
111
+ end
112
+
113
+ # Make the string light yellow
114
+ # @return [String] Light yellow string
115
+ def light_yellow
116
+ colorize(93)
117
+ end
118
+
119
+ # Make the string light blue
120
+ # @return [String] Light blue string
121
+ def light_blue
122
+ colorize(94)
123
+ end
124
+
125
+ # Make the string light magenta
126
+ # @return [String] Light magenta string
127
+ def light_magenta
128
+ colorize(95)
129
+ end
130
+
131
+ # Make the string light cyan
132
+ # @return [String] Light cyan string
133
+ def light_cyan
134
+ colorize(96)
135
+ end
136
+
137
+ # Make the string light white
138
+ # @return [String] Light white string
139
+ def light_white
140
+ colorize(97)
141
+ end
48
142
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cli_class_tool
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nicolas Morey
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-09-09 00:00:00.000000000 Z
10
+ date: 2026-09-18 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rake
@@ -83,7 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
83
83
  - !ruby/object:Gem::Version
84
84
  version: '0'
85
85
  requirements: []
86
- rubygems_version: 4.0.16
86
+ rubygems_version: 4.0.20
87
87
  specification_version: 4
88
88
  summary: A lightweight object-oriented framework for class-based command-line interface
89
89
  (CLI) applications.