cli_class_tool 0.2.1 → 0.4.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 +17 -0
- data/README.md +55 -0
- data/lib/cli_class_tool/common.rb +81 -30
- 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: bad275062a9f72ff201812eb6cd7871b9321b80b57f379f817cab483de42b738
|
|
4
|
+
data.tar.gz: e3cb70b12fe4831a4fdd194eaa4c67118efcfd9ffc0f1903524d74bdaf805e1a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 43cc9f0156398b92a5d1c7370c6c8c7dcf61d80e4ad9b18bec8a4a5bedceec7aa9e9af40e5d801554c7369aa746bac98c204ad949d2d27b381c4e14cbec93312
|
|
7
|
+
data.tar.gz: '0948e6f13057dd174140d84a7845c33a25e758a9ef018e10afb9c75bb734e87dffaf191e81091e01fe8c1dc9ff66437672364343d7ffc054f76cf0d591ebec1d'
|
data/CHANGELOG
CHANGED
|
@@ -1,7 +1,24 @@
|
|
|
1
|
+
------------------
|
|
2
|
+
0.4.0 (2026-06-05)
|
|
3
|
+
------------------
|
|
4
|
+
|
|
5
|
+
* Add basic initializer for Common
|
|
6
|
+
* Add Common::run() that will auto spawn a Common object and run the command with it.
|
|
7
|
+
* log function can now be used in alternate object or class by including/extending CLIClassTool::Logger
|
|
8
|
+
|
|
9
|
+
------------------
|
|
10
|
+
0.3.0 (2026-06-02)
|
|
11
|
+
------------------
|
|
12
|
+
|
|
13
|
+
* Enforce module/class namespaces for all action classes (potentially breaking change)
|
|
14
|
+
* Support automatic project-specific `RunError` generation with customized base error inheritance
|
|
15
|
+
|
|
1
16
|
------------------
|
|
2
17
|
0.2.1 (2026-06-01)
|
|
3
18
|
------------------
|
|
4
19
|
|
|
20
|
+
* Fix issue with conflicting addon files
|
|
21
|
+
|
|
5
22
|
------------------
|
|
6
23
|
0.2.0 (2026-06-01)
|
|
7
24
|
------------------
|
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
|
|
|
@@ -1,22 +1,9 @@
|
|
|
1
1
|
# Main module for generic CLI class-based tools and utilities
|
|
2
2
|
module CLIClassTool
|
|
3
3
|
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
# List of available actions for this class
|
|
7
|
-
ACTION_LIST = [ :list_actions ]
|
|
8
|
-
# Help text for actions
|
|
9
|
-
ACTION_HELP = {}
|
|
10
|
-
|
|
4
|
+
# Logger for CLIClassTool::Common
|
|
5
|
+
module Logger
|
|
11
6
|
private
|
|
12
|
-
# Get the parent module of this class (e.g. KernelWork or XXX)
|
|
13
|
-
def parent_module
|
|
14
|
-
@parent_module ||= begin
|
|
15
|
-
parts = self.class.name.split('::')
|
|
16
|
-
parts.size > 1 ? Object.const_get(parts[0...-1].join('::')) : Object
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
7
|
# Internal log method
|
|
21
8
|
# @param lvl [String] Log level string (colored)
|
|
22
9
|
# @param str [String] Message
|
|
@@ -33,26 +20,33 @@ module CLIClassTool
|
|
|
33
20
|
out.print("# " + lvl.to_s() + ": " + str + "\r")
|
|
34
21
|
end
|
|
35
22
|
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
# @param
|
|
39
|
-
# @param ret [String, nil] Optional return message
|
|
23
|
+
# Compute the parent module of an object or a class
|
|
24
|
+
#
|
|
25
|
+
# @param obj [Object,Class] Object or class to get the Module from
|
|
40
26
|
# @raise [StandardError] If command failed
|
|
41
|
-
def
|
|
42
|
-
if
|
|
43
|
-
|
|
44
|
-
|
|
27
|
+
def obj_to_parent_mod(obj)
|
|
28
|
+
return obj if obj.is_a?(Module)
|
|
29
|
+
theClass = obj.is_a?(Class) ? obj : obj.class
|
|
30
|
+
if theClass.name.nil?
|
|
31
|
+
return Object
|
|
32
|
+
else
|
|
33
|
+
parts = theClass.name.split('::')
|
|
34
|
+
if parts.size <= 1
|
|
35
|
+
raise "CLIClassTool action classes must be defined within a named module/class namespace"
|
|
36
|
+
end
|
|
37
|
+
return Object.const_get(parts[0...-1].join('::'))
|
|
45
38
|
end
|
|
46
39
|
end
|
|
47
40
|
|
|
48
|
-
#
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
41
|
+
# Get the parent module of this class (e.g. KernelWork or XXX)
|
|
42
|
+
def parent_module
|
|
43
|
+
return @parent_module if @parent_module != nil
|
|
44
|
+
|
|
45
|
+
@parent_module = obj_to_parent_mod(self)
|
|
46
|
+
return @parent_module
|
|
54
47
|
end
|
|
55
|
-
|
|
48
|
+
|
|
49
|
+
public
|
|
56
50
|
# Log a message with a specific level
|
|
57
51
|
#
|
|
58
52
|
# @param lvl [Symbol] Log level (:DEBUG, :INFO, :WARNING, :ERROR, etc.)
|
|
@@ -102,8 +96,61 @@ module CLIClassTool
|
|
|
102
96
|
end
|
|
103
97
|
return rep
|
|
104
98
|
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Common utility class providing logging, configuration, and shell execution methods
|
|
102
|
+
class Common
|
|
103
|
+
# Hook to enforce namespace loading at load time
|
|
104
|
+
def self.inherited(subclass)
|
|
105
|
+
if subclass.name
|
|
106
|
+
parts = subclass.name.to_s.split('::')
|
|
107
|
+
if parts.size <= 1
|
|
108
|
+
raise "CLIClassTool action classes must be defined within a named module/class namespace"
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# List of available actions for this class
|
|
114
|
+
ACTION_LIST = [ :list_actions ]
|
|
115
|
+
# Help text for actions
|
|
116
|
+
ACTION_HELP = {}
|
|
117
|
+
|
|
118
|
+
# Give the Logger mathods to Common
|
|
119
|
+
include CLIClassTool::Logger
|
|
120
|
+
|
|
121
|
+
private
|
|
122
|
+
# Raise error if system command failed
|
|
123
|
+
# @param check_err [Boolean] Whether to check for errors
|
|
124
|
+
# @param sysret [Process::Status] System return status
|
|
125
|
+
# @param ret [String, nil] Optional return message
|
|
126
|
+
# @raise [StandardError] If command failed
|
|
127
|
+
def abort_if_err(check_err, sysret, ret = nil)
|
|
128
|
+
if sysret.exitstatus != 0 && check_err == true
|
|
129
|
+
unless parent_module.const_defined?(:RunError)
|
|
130
|
+
raise "CLIClassTool parent module #{parent_module} must extend CLIClassTool::Utils to define RunError"
|
|
131
|
+
end
|
|
132
|
+
raise(parent_module::RunError.new(sysret.exitstatus, ret))
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Debug command execution
|
|
137
|
+
# @param cmd_type [String] Type of command (e.g., 'git')
|
|
138
|
+
# @param cmd [String] The command string
|
|
139
|
+
def cmd_debug(cmd_type, cmd)
|
|
140
|
+
log(:DEBUG, "Called from #{caller[1]}")
|
|
141
|
+
log(:DEBUG, "Running #{cmd_type} command '#{cmd}'")
|
|
142
|
+
end
|
|
143
|
+
|
|
105
144
|
|
|
106
145
|
public
|
|
146
|
+
# Simple initializer for a Common object
|
|
147
|
+
#
|
|
148
|
+
# @param path [String] Path to run commands from
|
|
149
|
+
def initialize(path=".", caller_obj=self)
|
|
150
|
+
@path = path
|
|
151
|
+
@parent_module = obj_to_parent_mod(caller_obj)
|
|
152
|
+
end
|
|
153
|
+
|
|
107
154
|
# Run a shell command
|
|
108
155
|
#
|
|
109
156
|
# @param cmd [String] Command to run
|
|
@@ -117,6 +164,10 @@ module CLIClassTool
|
|
|
117
164
|
return ret
|
|
118
165
|
end
|
|
119
166
|
|
|
167
|
+
def self.run(path, cmd, check_err = true)
|
|
168
|
+
obj = Common.new(path, self)
|
|
169
|
+
return obj.run(cmd, check_err)
|
|
170
|
+
end
|
|
120
171
|
# Run a shell command using system() (interactive)
|
|
121
172
|
#
|
|
122
173
|
# @param cmd [String] Command to run
|
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.4.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-05 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: rake
|