cli_class_tool 0.1.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 +7 -0
- data/LICENSE +674 -0
- data/README.md +245 -0
- data/lib/cli_class_tool/common.rb +170 -0
- data/lib/cli_class_tool/string.rb +48 -0
- data/lib/cli_class_tool/utils.rb +261 -0
- data/lib/cli_class_tool.rb +3 -0
- metadata +89 -0
data/README.md
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# CLIClassTool
|
|
2
|
+
|
|
3
|
+
`CLIClassTool` is a lightweight, object-oriented framework for building class-based command-line interface (CLI) applications. It decouples the generic execution, logging, and action routing engine from project-specific business logic, making it extremely easy to synchronize across multiple projects or package as a shared gem.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Directory Structure
|
|
8
|
+
|
|
9
|
+
To use `CLIClassTool` in your project, copy or subtree the `cli_class_tool/` directory under your library path (typically `lib/`):
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
lib/
|
|
13
|
+
└── cli_class_tool/
|
|
14
|
+
├── README.md
|
|
15
|
+
├── common.rb # Generic common helper class (logging, shell exec, prompt)
|
|
16
|
+
├── string.rb # Generic String class extension for ANSI colors
|
|
17
|
+
└── utils.rb # Generic action routing and runner engine
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## How to Use inside a Project
|
|
23
|
+
|
|
24
|
+
### 1. Define Your Custom Action Classes
|
|
25
|
+
Define classes representing categories of your CLI commands. These classes should inherit from your project's subclassed `Common` (which inherits from `CLIClassTool::Common`):
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
module MyProject
|
|
29
|
+
# Inherit from CLIClassTool::Common
|
|
30
|
+
class Common < CLIClassTool::Common
|
|
31
|
+
# Add any project-specific helpers here
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
module MyProject
|
|
36
|
+
class Suse < Common
|
|
37
|
+
# 1. Declare the list of available actions (methods)
|
|
38
|
+
ACTION_LIST = [ :source_rebase, :checkpatch ]
|
|
39
|
+
|
|
40
|
+
# 2. Define action method help/descriptions
|
|
41
|
+
ACTION_HELP = {
|
|
42
|
+
:source_rebase => "Rebase SUSE kernel sources to the latest tip",
|
|
43
|
+
:checkpatch => "Run checkpatch on pending patches"
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# 3. Implement action methods
|
|
47
|
+
def source_rebase(opts)
|
|
48
|
+
log(:INFO, "Rebasing...")
|
|
49
|
+
run("git pull --rebase")
|
|
50
|
+
return 0 # Return 0 for success (or an Integer exit code)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def checkpatch(opts)
|
|
54
|
+
# Uses inherited `run` and logging methods
|
|
55
|
+
ret = run("git diff HEAD~1")
|
|
56
|
+
log(:VERBOSE, ret)
|
|
57
|
+
return 0
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 2. Initialize and Load CLIClassTool
|
|
64
|
+
In your library entrypoint (e.g. `lib/my-project.rb`), require the `cli_class_tool` components, set up your project-specific namespace, and extend `CLIClassTool::Utils`:
|
|
65
|
+
|
|
66
|
+
```ruby
|
|
67
|
+
# Add lib to load path if necessary
|
|
68
|
+
$LOAD_PATH.push(File.dirname(__FILE__))
|
|
69
|
+
|
|
70
|
+
require 'cli_class_tool'
|
|
71
|
+
|
|
72
|
+
module MyProject
|
|
73
|
+
# Define project-specific base Common class
|
|
74
|
+
class Common < CLIClassTool::Common
|
|
75
|
+
# Project-specific methods can be defined here
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Require all your custom action classes
|
|
80
|
+
require 'my_project/suse'
|
|
81
|
+
require 'my_project/other_actions'
|
|
82
|
+
|
|
83
|
+
module MyProject
|
|
84
|
+
# List of classes that implement various CLI actions
|
|
85
|
+
ACTION_CLASS = [ Suse, OtherActions ]
|
|
86
|
+
|
|
87
|
+
# Extend CLIClassTool::Utils to map methods onto MyProject module
|
|
88
|
+
extend CLIClassTool::Utils
|
|
89
|
+
end
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### 3. Create the Executable Runner
|
|
93
|
+
In your executable bin (e.g. `bin/mytool`), parse options and call the `execAction` utility to invoke the target action class:
|
|
94
|
+
|
|
95
|
+
```ruby
|
|
96
|
+
#!/usr/bin/ruby
|
|
97
|
+
require 'optparse'
|
|
98
|
+
require 'my-project'
|
|
99
|
+
|
|
100
|
+
opts = { action: :source_rebase } # Typically parsed from command-line arguments
|
|
101
|
+
|
|
102
|
+
# 1. Optionally parse options
|
|
103
|
+
optsParser = OptionParser.new
|
|
104
|
+
MyProject.setOpts(opts[:action], optsParser, opts)
|
|
105
|
+
optsParser.parse!(ARGV)
|
|
106
|
+
|
|
107
|
+
# 2. Check options validity
|
|
108
|
+
MyProject.checkOpts(opts)
|
|
109
|
+
|
|
110
|
+
# 3. Execute action dynamically
|
|
111
|
+
# Uses the class `load` factory method if defined, falling back to `.new`.
|
|
112
|
+
# If an exception is thrown, it will be caught and logged cleanly, returning the correct exit status.
|
|
113
|
+
exit MyProject.execAction(opts, opts[:action])
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Logging Levels
|
|
119
|
+
By inheriting from `CLIClassTool::Common`, your action classes have access to a rich `log` helper supporting several standard output and color levels:
|
|
120
|
+
|
|
121
|
+
- `log(:DEBUG, "msg")`: Prints to STDOUT when `ENV["DEBUG"]` is active (Magenta).
|
|
122
|
+
- `log(:VERBOSE, "msg")`: Prints to STDOUT when `MyProject.verbose_log == true` (Blue).
|
|
123
|
+
- `log(:INFO, "msg")`: General informative logs (Green).
|
|
124
|
+
- `log(:PROGRESS, "msg")`: In-place update logs (Green with `\r` carriage return).
|
|
125
|
+
- `log(:WARNING, "msg")`: Warning logs (Brown).
|
|
126
|
+
- `log(:ERROR, "msg")`: Prints to STDERR (Red).
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Dynamic Class Overrides (Addons)
|
|
131
|
+
|
|
132
|
+
`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.
|
|
133
|
+
|
|
134
|
+
### 1. Set Up `getExtendedClass`
|
|
135
|
+
|
|
136
|
+
To enable class overrides, define a `getExtendedClass` class/module method on your parent module:
|
|
137
|
+
|
|
138
|
+
```ruby
|
|
139
|
+
module MyProject
|
|
140
|
+
# Map of repository names to overridden classes
|
|
141
|
+
@@custom_classes = {}
|
|
142
|
+
|
|
143
|
+
def self.registerCustom(repo_name, classes)
|
|
144
|
+
@@custom_classes[repo_name] = classes
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Resolve the customized/overridden subclass (addon) if registered
|
|
148
|
+
def self.getExtendedClass(default_class, repo_name = File.basename(Dir.pwd))
|
|
149
|
+
custom = @@custom_classes[repo_name]
|
|
150
|
+
if custom != nil && custom[default_class] != nil
|
|
151
|
+
return custom[default_class]
|
|
152
|
+
else
|
|
153
|
+
return default_class
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
If defined, `CLIClassTool` will automatically:
|
|
160
|
+
- Execute actions using the extended class instead of the base class.
|
|
161
|
+
- For options setup (`setOpts`) and validation checks (`checkOpts`), it will sequentially call BOTH the base class hooks and the extended class hooks to ensure clean options merging.
|
|
162
|
+
|
|
163
|
+
### 2. Dynamically Loading Addons
|
|
164
|
+
|
|
165
|
+
`CLIClassTool` provides a `loadAddons(path)` helper to dynamically scan a folder and load all custom Ruby classes/addons present in it.
|
|
166
|
+
|
|
167
|
+
```ruby
|
|
168
|
+
module MyProject
|
|
169
|
+
extend CLIClassTool::Utils
|
|
170
|
+
|
|
171
|
+
# Load all core addons
|
|
172
|
+
loadAddons(File.expand_path('addons', __dir__))
|
|
173
|
+
|
|
174
|
+
# Load optional user addons from an environment variable path
|
|
175
|
+
if ENV["MY_PROJECT_ADDON_DIR"]
|
|
176
|
+
loadAddons(ENV["MY_PROJECT_ADDON_DIR"])
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### 3. Factory Class Loading & Validation
|
|
182
|
+
|
|
183
|
+
`CLIClassTool` provides helper methods to implement safe, validated factory class loading. This ensures that subclasses are only instantiated through the authorized factory methods rather than being directly instantiated:
|
|
184
|
+
|
|
185
|
+
- `loadClass(default_class, addon_key, *args)`: Safely loads and instantiates an overridden/extended class instance.
|
|
186
|
+
- `checkDirectConstructor(class)`: Raises an error if the class is directly instantiated instead of going through `loadClass`.
|
|
187
|
+
|
|
188
|
+
#### Example Setup:
|
|
189
|
+
|
|
190
|
+
```ruby
|
|
191
|
+
module MyProject
|
|
192
|
+
class Suse < Common
|
|
193
|
+
def initialize(path)
|
|
194
|
+
# Validate that constructor was only called through loadClass factory
|
|
195
|
+
MyProject.checkDirectConstructor(self.class)
|
|
196
|
+
@path = path
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Factory loading method
|
|
200
|
+
def self.load(path=".")
|
|
201
|
+
# Safely instantiate via CLIClassTool loadClass
|
|
202
|
+
return MyProject.loadClass(Suse, "suse-addon-key", path)
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### 4. Fully Automated CLI Runner (`run_cli`)
|
|
209
|
+
|
|
210
|
+
`CLIClassTool` provides a highly configurable, automated CLI runner (`run_cli`) that eliminates repetitive parsing and formatting boilerplate from your executable binaries.
|
|
211
|
+
|
|
212
|
+
- `run_cli(opts={}, argv=ARGV) { |parser, phase, action_opts| ... }`
|
|
213
|
+
|
|
214
|
+
#### Built-in Default Options:
|
|
215
|
+
To simplify applications, `run_cli` natively defines and handles standard options by default:
|
|
216
|
+
- `--verbose`: Handled both globally and action-specifically, setting `MyProject.verbose_log = true`.
|
|
217
|
+
- `-y`, `--yes` and `-n`, `--no`: Handled action-specifically, setting `opts[:yn_default] = :yes` or `:no` respectively (which is natively recognized by the inherited `confirm` method).
|
|
218
|
+
|
|
219
|
+
#### Customization Phases:
|
|
220
|
+
- `:global`: Customize options parsed globally before the action is matched.
|
|
221
|
+
- `:action`: Customize options parsed specifically for the targeted action.
|
|
222
|
+
|
|
223
|
+
#### Addon Help Integration (`getCustomClasses`):
|
|
224
|
+
If your project uses dynamic class overrides (addons) and defines a `getCustomClasses` method on the parent module returning a hash/list of registered addon names, `run_cli` will automatically append a list of these custom repository addons to the `--help` output of the CLI for seamless help integration.
|
|
225
|
+
|
|
226
|
+
#### Example Executable (`bin/mytool`):
|
|
227
|
+
|
|
228
|
+
```ruby
|
|
229
|
+
#!/usr/bin/ruby
|
|
230
|
+
require 'my-project'
|
|
231
|
+
|
|
232
|
+
opts = {
|
|
233
|
+
:default_setting => "value"
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
# The entire CLI parsing, formatting, listing, option checking, and action routing is fully automated!
|
|
237
|
+
# Built-in options like --verbose, -y/--yes, -n/--no are parsed and processed automatically.
|
|
238
|
+
MyProject.run_cli(opts) do |parser, phase, action_opts|
|
|
239
|
+
case phase
|
|
240
|
+
when :global
|
|
241
|
+
parser.on("-c", "--config FILE") { |val| MyProject::Config.path = val }
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
```
|
|
245
|
+
```
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Main module for generic CLI class-based tools and utilities
|
|
2
|
+
module CLIClassTool
|
|
3
|
+
|
|
4
|
+
# Common utility class providing logging, configuration, and shell execution methods
|
|
5
|
+
class Common
|
|
6
|
+
# List of available actions for this class
|
|
7
|
+
ACTION_LIST = [ :list_actions ]
|
|
8
|
+
# Help text for actions
|
|
9
|
+
ACTION_HELP = {}
|
|
10
|
+
|
|
11
|
+
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
|
+
# Internal log method
|
|
21
|
+
# @param lvl [String] Log level string (colored)
|
|
22
|
+
# @param str [String] Message
|
|
23
|
+
# @param out [IO] Output stream (default $stdout)
|
|
24
|
+
def _log(lvl, str, out=$stdout)
|
|
25
|
+
out.puts("# " + lvl.to_s() + ": " + str)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Internal relog method (update current line)
|
|
29
|
+
# @param lvl [String] Log level string (colored)
|
|
30
|
+
# @param str [String] Message
|
|
31
|
+
# @param out [IO] Output stream (default $stdout)
|
|
32
|
+
def _relog(lvl, str, out=$stdout)
|
|
33
|
+
out.print("# " + lvl.to_s() + ": " + str + "\r")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Raise error if system command failed
|
|
37
|
+
# @param check_err [Boolean] Whether to check for errors
|
|
38
|
+
# @param sysret [Process::Status] System return status
|
|
39
|
+
# @param ret [String, nil] Optional return message
|
|
40
|
+
# @raise [StandardError] If command failed
|
|
41
|
+
def abort_if_err(check_err, sysret, ret = nil)
|
|
42
|
+
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))
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Debug command execution
|
|
49
|
+
# @param cmd_type [String] Type of command (e.g., 'git')
|
|
50
|
+
# @param cmd [String] The command string
|
|
51
|
+
def cmd_debug(cmd_type, cmd)
|
|
52
|
+
log(:DEBUG, "Called from #{caller[1]}")
|
|
53
|
+
log(:DEBUG, "Running #{cmd_type} command '#{cmd}'")
|
|
54
|
+
end
|
|
55
|
+
protected
|
|
56
|
+
# Log a message with a specific level
|
|
57
|
+
#
|
|
58
|
+
# @param lvl [Symbol] Log level (:DEBUG, :INFO, :WARNING, :ERROR, etc.)
|
|
59
|
+
# @param str [String] Message to log
|
|
60
|
+
def log(lvl, str)
|
|
61
|
+
case lvl
|
|
62
|
+
when :DEBUG
|
|
63
|
+
_log("DEBUG".magenta(), str) if ENV["DEBUG"].to_s() != ""
|
|
64
|
+
when :DEBUG_CI
|
|
65
|
+
_log("DEBUG_CI".magenta(), str) if ENV["DEBUG_CI"].to_s() != ""
|
|
66
|
+
when :VERBOSE
|
|
67
|
+
_log("INFO".blue(), str) if parent_module.verbose_log == true
|
|
68
|
+
when :INFO
|
|
69
|
+
_log("INFO".green(), str)
|
|
70
|
+
when :PROGRESS
|
|
71
|
+
_relog("INFO".green(), str)
|
|
72
|
+
when :WARNING
|
|
73
|
+
_log("WARNING".brown(), str)
|
|
74
|
+
when :ERROR
|
|
75
|
+
_log("ERROR".red(), str, $stderr)
|
|
76
|
+
else
|
|
77
|
+
_log(lvl, str)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Prompt the user for confirmation
|
|
82
|
+
#
|
|
83
|
+
# @param opts [Hash] Options hash
|
|
84
|
+
# @param msg [String] Confirmation message
|
|
85
|
+
# @param ignore_default [Boolean] Ignore default yes/no options
|
|
86
|
+
# @param allowed_reps [Array<String>] Allowed responses
|
|
87
|
+
# @return [String] User response
|
|
88
|
+
def confirm(opts, msg, ignore_default=false, allowed_reps=[ "y", "n" ])
|
|
89
|
+
rep = 't'
|
|
90
|
+
while allowed_reps.index(rep) == nil && rep != '' do
|
|
91
|
+
puts "Do you wish to #{msg} ? (#{allowed_reps.join("/")}): "
|
|
92
|
+
case (ignore_default == true ? nil : opts[:yn_default])
|
|
93
|
+
when :no
|
|
94
|
+
puts "Auto-replying no due to --no option"
|
|
95
|
+
rep = 'n'
|
|
96
|
+
when :yes
|
|
97
|
+
puts "Auto-replying yes due to --yes option"
|
|
98
|
+
rep = 'y'
|
|
99
|
+
else
|
|
100
|
+
rep = STDIN.gets.chomp()
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
return rep
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
public
|
|
107
|
+
# Run a shell command
|
|
108
|
+
#
|
|
109
|
+
# @param cmd [String] Command to run
|
|
110
|
+
# @param check_err [Boolean] Raise error on failure
|
|
111
|
+
# @return [String] Command output
|
|
112
|
+
# @raise [StandardError] If command fails and check_err is true
|
|
113
|
+
def run(cmd, check_err = true)
|
|
114
|
+
cmd_debug('', cmd)
|
|
115
|
+
ret = `cd #{@path} && #{cmd}`.chomp()
|
|
116
|
+
abort_if_err(check_err, $?, ret)
|
|
117
|
+
return ret
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Run a shell command using system() (interactive)
|
|
121
|
+
#
|
|
122
|
+
# @param cmd [String] Command to run
|
|
123
|
+
# @param check_err [Boolean] Raise error on failure
|
|
124
|
+
# @return [Boolean] Command success status
|
|
125
|
+
# @raise [StandardError] If command fails and check_err is true
|
|
126
|
+
def runSystem(cmd, check_err = true)
|
|
127
|
+
cmd_debug('interactive', cmd)
|
|
128
|
+
ret = system("cd #{@path} && #{cmd}")
|
|
129
|
+
abort_if_err(check_err, $?)
|
|
130
|
+
return ret
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Run a git command
|
|
134
|
+
#
|
|
135
|
+
# @param cmd [String] Git command arguments
|
|
136
|
+
# @param opts [Hash] Options (e.g., :env)
|
|
137
|
+
# @param check_err [Boolean] Raise error on failure
|
|
138
|
+
# @return [String] Command output
|
|
139
|
+
# @raise [StandardError] If command fails and check_err is true
|
|
140
|
+
def runGit(cmd, opts={}, check_err = true)
|
|
141
|
+
cmd_debug('git', cmd)
|
|
142
|
+
ret = `cd #{@path} && #{opts[:env]} git #{cmd}`.chomp()
|
|
143
|
+
abort_if_err(check_err, $?, ret)
|
|
144
|
+
return ret
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Run a git command interactively
|
|
148
|
+
#
|
|
149
|
+
# @param cmd [String] Git command arguments
|
|
150
|
+
# @param opts [Hash] Options (e.g., :env)
|
|
151
|
+
# @param check_err [Boolean] Raise error on failure
|
|
152
|
+
# @return [Boolean] Command success status
|
|
153
|
+
# @raise [StandardError] If command fails and check_err is true
|
|
154
|
+
def runGitInteractive(cmd, opts={}, check_err = true)
|
|
155
|
+
cmd_debug('git interactive', cmd)
|
|
156
|
+
ret = system("cd #{@path} && #{opts[:env]} git #{cmd}")
|
|
157
|
+
abort_if_err(check_err, $?)
|
|
158
|
+
return ret
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# List available actions
|
|
162
|
+
#
|
|
163
|
+
# @param opts [Hash] Options hash
|
|
164
|
+
# @return [Integer] 0
|
|
165
|
+
def list_actions(opts)
|
|
166
|
+
puts parent_module.getActionAttr("ACTION_LIST").map(){|x| parent_module.actionToString(x)}.join("\n")
|
|
167
|
+
return 0
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Extension to the core String class to add colorization support
|
|
2
|
+
class String
|
|
3
|
+
# colorization
|
|
4
|
+
@@is_a_tty = nil
|
|
5
|
+
|
|
6
|
+
# Colorize the string using ANSI escape codes
|
|
7
|
+
#
|
|
8
|
+
# @param color_code [Integer] ANSI color code
|
|
9
|
+
# @return [String] Colorized string if TTY, else original string
|
|
10
|
+
def colorize(color_code)
|
|
11
|
+
@@is_a_tty = $stdout.isatty() if @@is_a_tty == nil
|
|
12
|
+
if @@is_a_tty then
|
|
13
|
+
return "\e[#{color_code}m#{self}\e[0m"
|
|
14
|
+
else
|
|
15
|
+
return self
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Make the string red
|
|
20
|
+
# @return [String] Red string
|
|
21
|
+
def red
|
|
22
|
+
colorize(31)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Make the string green
|
|
26
|
+
# @return [String] Green string
|
|
27
|
+
def green
|
|
28
|
+
colorize(32)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Make the string brown (yellow)
|
|
32
|
+
# @return [String] Brown string
|
|
33
|
+
def brown
|
|
34
|
+
colorize(33)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Make the string blue
|
|
38
|
+
# @return [String] Blue string
|
|
39
|
+
def blue
|
|
40
|
+
colorize(34)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Make the string magenta
|
|
44
|
+
# @return [String] Magenta string
|
|
45
|
+
def magenta
|
|
46
|
+
colorize(35)
|
|
47
|
+
end
|
|
48
|
+
end
|