cli_class_tool 0.2.1 → 0.3.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 +10 -0
- data/README.md +55 -0
- data/lib/cli_class_tool/common.rb +23 -4
- data/lib/cli_class_tool/utils.rb +15 -1
- data/lib/cli_class_tool.rb +30 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b709fe8b17a110ea17968fb9d7d4ff45e2ceac57bed76c3dcda67438880dcdc4
|
|
4
|
+
data.tar.gz: 1ff6831f0c5bfbc9d54d8dac31e18fdad3003ec0d527bfb3999e11a472b1591b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f408128eb985f8ad45949c452be46aa55edc028f1dc060c2870afdbea358016258071e0cc8aadf155e867c0f8e7be4295e8045c699eb0f82c501feaeb9b7502b
|
|
7
|
+
data.tar.gz: 75d8bbfd502b9a331be9c57e25b7f824b2bf1d24c94f6fe477f64f2078dde1a76911b4964b0bdcf531098f895a753556778571f0a4354e1d2b733b1fedc56212
|
data/CHANGELOG
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
|
+
------------------
|
|
2
|
+
0.3.0 (2026-06-02)
|
|
3
|
+
------------------
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
* Enforce module/class namespaces for all action classes (potentially breaking change)
|
|
7
|
+
* Support automatic project-specific `RunError` generation with customized base error inheritance
|
|
8
|
+
|
|
1
9
|
------------------
|
|
2
10
|
0.2.1 (2026-06-01)
|
|
3
11
|
------------------
|
|
4
12
|
|
|
13
|
+
* Fix issue with conflicting addon files
|
|
14
|
+
|
|
5
15
|
------------------
|
|
6
16
|
0.2.0 (2026-06-01)
|
|
7
17
|
------------------
|
data/README.md
CHANGED
|
@@ -112,6 +112,61 @@ exit MyProject.execAction(opts, opts[:action])
|
|
|
112
112
|
|
|
113
113
|
---
|
|
114
114
|
|
|
115
|
+
## Namespace Requirement & Error Handling
|
|
116
|
+
|
|
117
|
+
### 1. Module Namespace Requirement
|
|
118
|
+
|
|
119
|
+
To ensure clean encapsulation and safe error resolution, all action classes and standard subclasses inheriting from `CLIClassTool::Common` **must** be defined within a named module/class namespace (such as `MyProject`):
|
|
120
|
+
|
|
121
|
+
```ruby
|
|
122
|
+
# Correct: Action class is scoped under MyProject namespace
|
|
123
|
+
module MyProject
|
|
124
|
+
class Suse < CLIClassTool::Common
|
|
125
|
+
# ...
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Incorrect: Defining action classes directly in the global namespace is forbidden
|
|
130
|
+
# and will raise an error at load-time:
|
|
131
|
+
class Suse < CLIClassTool::Common; end
|
|
132
|
+
# => "CLIClassTool action classes must be defined within a named module/class namespace"
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### 2. Automated `RunError` Generation & Customized Inheritance
|
|
136
|
+
|
|
137
|
+
When your project's parent module extends `CLIClassTool::Utils`, `CLIClassTool` automatically generates a nested `RunError` class (i.e. `MyProject::RunError`) specifically for your project on load.
|
|
138
|
+
|
|
139
|
+
By default, this generated error inherits from `CLIClassTool::RunError`. However, if you have a binary-specific or project-wide base error class defined, `CLIClassTool` will **automatically detect it** and make `RunError` inherit from it instead!
|
|
140
|
+
|
|
141
|
+
It looks for existing error classes in this order:
|
|
142
|
+
1. `#{base_name}Error` (e.g., `MyProjectError` in the global scope)
|
|
143
|
+
2. `#{base_name}::Error` (e.g., `MyProject::Error` within your namespace)
|
|
144
|
+
3. Falls back to `CLIClassTool::RunError`
|
|
145
|
+
|
|
146
|
+
#### Why is this useful?
|
|
147
|
+
This allows you to catch all potential CLI errors (including system command failures from `run`, `runGit`, etc.) in a single rescue block at the entry point of your binary:
|
|
148
|
+
|
|
149
|
+
```ruby
|
|
150
|
+
# Define your binary-specific error class
|
|
151
|
+
class MyProjectError < StandardError; end
|
|
152
|
+
|
|
153
|
+
module MyProject
|
|
154
|
+
extend CLIClassTool::Utils
|
|
155
|
+
# CLIClassTool automatically defines MyProject::RunError inheriting from MyProjectError!
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# In your executable (bin/mytool)
|
|
159
|
+
begin
|
|
160
|
+
MyProject.run_cli
|
|
161
|
+
rescue MyProjectError => e
|
|
162
|
+
# This cleanly catches MyProject::RunError, as well as any other custom MyProjectError!
|
|
163
|
+
STDERR.puts "# ERROR: #{e.message}"
|
|
164
|
+
exit e.respond_to?(:err_code) ? e.err_code : 1
|
|
165
|
+
end
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
115
170
|
## Logging Levels
|
|
116
171
|
By inheriting from `CLIClassTool::Common`, your action classes have access to a rich `log` helper supporting several standard output and color levels:
|
|
117
172
|
|
|
@@ -3,6 +3,16 @@ module CLIClassTool
|
|
|
3
3
|
|
|
4
4
|
# Common utility class providing logging, configuration, and shell execution methods
|
|
5
5
|
class Common
|
|
6
|
+
# Hook to enforce namespace loading at load time
|
|
7
|
+
def self.inherited(subclass)
|
|
8
|
+
if subclass.name
|
|
9
|
+
parts = subclass.name.to_s.split('::')
|
|
10
|
+
if parts.size <= 1
|
|
11
|
+
raise "CLIClassTool action classes must be defined within a named module/class namespace"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
6
16
|
# List of available actions for this class
|
|
7
17
|
ACTION_LIST = [ :list_actions ]
|
|
8
18
|
# Help text for actions
|
|
@@ -12,8 +22,15 @@ module CLIClassTool
|
|
|
12
22
|
# Get the parent module of this class (e.g. KernelWork or XXX)
|
|
13
23
|
def parent_module
|
|
14
24
|
@parent_module ||= begin
|
|
15
|
-
|
|
16
|
-
|
|
25
|
+
if self.class.name.nil?
|
|
26
|
+
Object
|
|
27
|
+
else
|
|
28
|
+
parts = self.class.name.split('::')
|
|
29
|
+
if parts.size <= 1
|
|
30
|
+
raise "CLIClassTool action classes must be defined within a named module/class namespace"
|
|
31
|
+
end
|
|
32
|
+
Object.const_get(parts[0...-1].join('::'))
|
|
33
|
+
end
|
|
17
34
|
end
|
|
18
35
|
end
|
|
19
36
|
|
|
@@ -40,8 +57,10 @@ module CLIClassTool
|
|
|
40
57
|
# @raise [StandardError] If command failed
|
|
41
58
|
def abort_if_err(check_err, sysret, ret = nil)
|
|
42
59
|
if sysret.exitstatus != 0 && check_err == true
|
|
43
|
-
|
|
44
|
-
|
|
60
|
+
unless parent_module.const_defined?(:RunError)
|
|
61
|
+
raise "CLIClassTool parent module #{parent_module} must extend CLIClassTool::Utils to define RunError"
|
|
62
|
+
end
|
|
63
|
+
raise(parent_module::RunError.new(sysret.exitstatus, ret))
|
|
45
64
|
end
|
|
46
65
|
end
|
|
47
66
|
|
data/lib/cli_class_tool/utils.rb
CHANGED
|
@@ -2,6 +2,21 @@ module CLIClassTool
|
|
|
2
2
|
# Generic utilities for CLI class-based actions
|
|
3
3
|
module Utils
|
|
4
4
|
|
|
5
|
+
# Hook called when a module extends CLIClassTool::Utils
|
|
6
|
+
def self.extended(base)
|
|
7
|
+
possible_name = base.name ? "#{base.name}Error" : nil
|
|
8
|
+
|
|
9
|
+
superclass = if possible_name && Object.const_defined?(possible_name)
|
|
10
|
+
Object.const_get(possible_name)
|
|
11
|
+
elsif base.const_defined?(:Error)
|
|
12
|
+
base.const_get(:Error)
|
|
13
|
+
else
|
|
14
|
+
CLIClassTool::RunError
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
CLIClassTool.define_run_error(base, superclass)
|
|
18
|
+
end
|
|
19
|
+
|
|
5
20
|
# Convert a string to an action symbol, validating it against available actions
|
|
6
21
|
#
|
|
7
22
|
# @param str [String] Action name
|
|
@@ -186,7 +201,6 @@ module CLIClassTool
|
|
|
186
201
|
def run_cli(opts = {}, argv = ARGV)
|
|
187
202
|
# Fetch actions and action helps
|
|
188
203
|
action_helps = self.getActionAttr("ACTION_HELP")
|
|
189
|
-
action_list = self.getActionAttr("ACTION_LIST")
|
|
190
204
|
|
|
191
205
|
# 1. Action Parser Setup
|
|
192
206
|
action_parser = OptionParser.new(nil, 60)
|
data/lib/cli_class_tool.rb
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
module CLIClassTool
|
|
2
|
+
class RunError < StandardError
|
|
3
|
+
attr_reader :err_code, :output
|
|
4
|
+
|
|
5
|
+
def initialize(err_code, output = nil)
|
|
6
|
+
@err_code = err_code
|
|
7
|
+
@output = output
|
|
8
|
+
super("Command failed with exit status #{err_code}#{output ? "\n#{output}" : ''}")
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.define_run_error(parent_module, superclass = CLIClassTool::RunError)
|
|
13
|
+
klass = Class.new(superclass)
|
|
14
|
+
|
|
15
|
+
if !(superclass <= CLIClassTool::RunError)
|
|
16
|
+
klass.class_eval do
|
|
17
|
+
attr_reader :err_code, :output
|
|
18
|
+
|
|
19
|
+
def initialize(err_code, output = nil)
|
|
20
|
+
@err_code = err_code
|
|
21
|
+
@output = output
|
|
22
|
+
super("Command failed with exit status #{err_code}#{output ? "\n#{output}" : ''}")
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
parent_module.const_set(:RunError, klass)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
1
31
|
require_relative 'cli_class_tool/string'
|
|
2
32
|
require_relative 'cli_class_tool/common'
|
|
3
33
|
require_relative 'cli_class_tool/utils'
|
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: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nicolas Morey
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-06-
|
|
10
|
+
date: 2026-06-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: rake
|