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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 641f72caf2c39cac1c5a222756c481f0de86b5fd7db14893001a64773400d894
4
- data.tar.gz: 612b9cca3cbd1b157780c490093657e77ba021bb973ca38e76e63f19de1e730e
3
+ metadata.gz: b709fe8b17a110ea17968fb9d7d4ff45e2ceac57bed76c3dcda67438880dcdc4
4
+ data.tar.gz: 1ff6831f0c5bfbc9d54d8dac31e18fdad3003ec0d527bfb3999e11a472b1591b
5
5
  SHA512:
6
- metadata.gz: f2ceb59e563ebe911176786f1e4ffdd3762c2ef0b9a62acad6323896c68741228468f3b21e53331f4b22774b4bd0ac8746048330408d84366b6fa4426a546ff6
7
- data.tar.gz: 3d848b3725fd1e80e061d04e358bbb71821708fc2ed490612ad4fe66b2ffc038396605cda7dfa28f89d7bdaaf703f6b038a0b66a68f18d18c12a2a12742667ab
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
- parts = self.class.name.split('::')
16
- parts.size > 1 ? Object.const_get(parts[0...-1].join('::')) : Object
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
- run_error_class = parent_module.const_defined?(:RunError) ? parent_module::RunError : RuntimeError
44
- raise(run_error_class.new(sysret.exitstatus, ret))
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
 
@@ -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)
@@ -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.2.1
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-01 00:00:00.000000000 Z
10
+ date: 2026-06-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rake