command_kit 0.1.0.pre1
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/.document +3 -0
- data/.github/workflows/ruby.yml +29 -0
- data/.gitignore +7 -0
- data/.rspec +1 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +29 -0
- data/Gemfile +14 -0
- data/LICENSE.txt +20 -0
- data/README.md +283 -0
- data/Rakefile +23 -0
- data/command_kit.gemspec +60 -0
- data/gemspec.yml +14 -0
- data/lib/command_kit.rb +1 -0
- data/lib/command_kit/arguments.rb +161 -0
- data/lib/command_kit/arguments/argument.rb +111 -0
- data/lib/command_kit/arguments/argument_value.rb +81 -0
- data/lib/command_kit/arguments/usage.rb +6 -0
- data/lib/command_kit/colors.rb +355 -0
- data/lib/command_kit/command.rb +42 -0
- data/lib/command_kit/command_name.rb +95 -0
- data/lib/command_kit/commands.rb +299 -0
- data/lib/command_kit/commands/auto_load.rb +153 -0
- data/lib/command_kit/commands/auto_load/subcommand.rb +90 -0
- data/lib/command_kit/commands/auto_require.rb +138 -0
- data/lib/command_kit/commands/command.rb +12 -0
- data/lib/command_kit/commands/help.rb +43 -0
- data/lib/command_kit/commands/parent_command.rb +21 -0
- data/lib/command_kit/commands/subcommand.rb +51 -0
- data/lib/command_kit/console.rb +141 -0
- data/lib/command_kit/description.rb +89 -0
- data/lib/command_kit/env.rb +43 -0
- data/lib/command_kit/env/home.rb +71 -0
- data/lib/command_kit/env/path.rb +71 -0
- data/lib/command_kit/examples.rb +99 -0
- data/lib/command_kit/exception_handler.rb +55 -0
- data/lib/command_kit/help.rb +62 -0
- data/lib/command_kit/help/man.rb +125 -0
- data/lib/command_kit/inflector.rb +84 -0
- data/lib/command_kit/main.rb +103 -0
- data/lib/command_kit/options.rb +179 -0
- data/lib/command_kit/options/option.rb +171 -0
- data/lib/command_kit/options/option_value.rb +90 -0
- data/lib/command_kit/options/parser.rb +227 -0
- data/lib/command_kit/options/quiet.rb +53 -0
- data/lib/command_kit/options/usage.rb +6 -0
- data/lib/command_kit/options/verbose.rb +55 -0
- data/lib/command_kit/options/version.rb +62 -0
- data/lib/command_kit/os.rb +47 -0
- data/lib/command_kit/pager.rb +115 -0
- data/lib/command_kit/printing.rb +32 -0
- data/lib/command_kit/printing/indent.rb +78 -0
- data/lib/command_kit/program_name.rb +57 -0
- data/lib/command_kit/stdio.rb +138 -0
- data/lib/command_kit/usage.rb +102 -0
- data/lib/command_kit/version.rb +4 -0
- data/lib/command_kit/xdg.rb +138 -0
- data/spec/arguments/argument_spec.rb +169 -0
- data/spec/arguments/argument_value_spec.rb +126 -0
- data/spec/arguments_spec.rb +213 -0
- data/spec/colors_spec.rb +470 -0
- data/spec/command_kit_spec.rb +8 -0
- data/spec/command_name_spec.rb +130 -0
- data/spec/command_spec.rb +49 -0
- data/spec/commands/auto_load/subcommand_spec.rb +82 -0
- data/spec/commands/auto_load_spec.rb +128 -0
- data/spec/commands/auto_require_spec.rb +142 -0
- data/spec/commands/fixtures/test_auto_load/cli/commands/test1.rb +10 -0
- data/spec/commands/fixtures/test_auto_load/cli/commands/test2.rb +10 -0
- data/spec/commands/fixtures/test_auto_require/lib/test_auto_require/cli/commands/test1.rb +10 -0
- data/spec/commands/help_spec.rb +66 -0
- data/spec/commands/parent_command_spec.rb +40 -0
- data/spec/commands/subcommand_spec.rb +99 -0
- data/spec/commands_spec.rb +767 -0
- data/spec/console_spec.rb +201 -0
- data/spec/description_spec.rb +203 -0
- data/spec/env/home_spec.rb +46 -0
- data/spec/env/path_spec.rb +78 -0
- data/spec/env_spec.rb +123 -0
- data/spec/examples_spec.rb +235 -0
- data/spec/exception_handler_spec.rb +103 -0
- data/spec/help_spec.rb +119 -0
- data/spec/inflector_spec.rb +104 -0
- data/spec/main_spec.rb +179 -0
- data/spec/options/option_spec.rb +258 -0
- data/spec/options/option_value_spec.rb +67 -0
- data/spec/options/parser_spec.rb +265 -0
- data/spec/options_spec.rb +137 -0
- data/spec/os_spec.rb +46 -0
- data/spec/pager_spec.rb +154 -0
- data/spec/printing/indent_spec.rb +130 -0
- data/spec/printing_spec.rb +76 -0
- data/spec/program_name_spec.rb +62 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/stdio_spec.rb +264 -0
- data/spec/usage_spec.rb +237 -0
- data/spec/xdg_spec.rb +191 -0
- metadata +156 -0
data/gemspec.yml
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
name: command_kit
|
|
2
|
+
summary: A toolkit for building Ruby CLI commands
|
|
3
|
+
description:
|
|
4
|
+
A Ruby toolkit for building clean, correct, and robust CLI commands as
|
|
5
|
+
Ruby classes.
|
|
6
|
+
license: MIT
|
|
7
|
+
authors: Postmodern
|
|
8
|
+
email: postmodern.mod3@gmail.com
|
|
9
|
+
homepage: https://github.com/postmodern/command_kit#readme
|
|
10
|
+
|
|
11
|
+
required_ruby_version: ">= 2.7.0"
|
|
12
|
+
|
|
13
|
+
development_dependencies:
|
|
14
|
+
bundler: ~> 2.0
|
data/lib/command_kit.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'command_kit/version'
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
require 'command_kit/help'
|
|
2
|
+
require 'command_kit/arguments/argument'
|
|
3
|
+
|
|
4
|
+
module CommandKit
|
|
5
|
+
#
|
|
6
|
+
# Provides a thin DSL for defining arguments as attributes.
|
|
7
|
+
#
|
|
8
|
+
# ## Examples
|
|
9
|
+
#
|
|
10
|
+
# include CommandKit::Arguments
|
|
11
|
+
#
|
|
12
|
+
# argument :output, type: String,
|
|
13
|
+
# desc: 'The output file'
|
|
14
|
+
#
|
|
15
|
+
# argument :input, type: Array,
|
|
16
|
+
# desc: 'The input file(s)'
|
|
17
|
+
#
|
|
18
|
+
module Arguments
|
|
19
|
+
include Help
|
|
20
|
+
|
|
21
|
+
module ModuleMethods
|
|
22
|
+
#
|
|
23
|
+
# Extends {ClassMethods} or {ModuleMethods}, depending on whether
|
|
24
|
+
# {Arguments} is being included into a class or module.
|
|
25
|
+
#
|
|
26
|
+
# @param [Class, Module] context
|
|
27
|
+
# The class or module which is including {Arguments}.
|
|
28
|
+
#
|
|
29
|
+
def included(context)
|
|
30
|
+
super(context)
|
|
31
|
+
|
|
32
|
+
if context.class == Module
|
|
33
|
+
context.extend ModuleMethods
|
|
34
|
+
else
|
|
35
|
+
context.extend ClassMethods
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
extend ModuleMethods
|
|
41
|
+
|
|
42
|
+
#
|
|
43
|
+
# Defines class-level methods.
|
|
44
|
+
#
|
|
45
|
+
module ClassMethods
|
|
46
|
+
#
|
|
47
|
+
# All defined arguments for the class.
|
|
48
|
+
#
|
|
49
|
+
# @return [Hash{Symbol => Argument}]
|
|
50
|
+
# The defined argument for the class and it's superclass.
|
|
51
|
+
#
|
|
52
|
+
def arguments
|
|
53
|
+
@arguments ||= if superclass.kind_of?(ClassMethods)
|
|
54
|
+
superclass.arguments.dup
|
|
55
|
+
else
|
|
56
|
+
{}
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
#
|
|
61
|
+
# Defines an argument for the class.
|
|
62
|
+
#
|
|
63
|
+
# @param [Symbol] name
|
|
64
|
+
# The argument name.
|
|
65
|
+
#
|
|
66
|
+
# @yield [(arg)]
|
|
67
|
+
# If a block is given, it will be passed the parsed argument.
|
|
68
|
+
#
|
|
69
|
+
# @yieldparam [Object, nil] arg
|
|
70
|
+
# The parsed argument.
|
|
71
|
+
#
|
|
72
|
+
# @return [Argument]
|
|
73
|
+
# The newly defined argument.
|
|
74
|
+
#
|
|
75
|
+
# @example Define an argument:
|
|
76
|
+
# argument :bar, desc: "Bar argument"
|
|
77
|
+
#
|
|
78
|
+
# @example With a custom usage string:
|
|
79
|
+
# option :bar, usage: 'BAR',
|
|
80
|
+
# desc: "Bar argument"
|
|
81
|
+
#
|
|
82
|
+
# @example With a custom block:
|
|
83
|
+
# argument :bar, desc: "Bar argument" do |bar|
|
|
84
|
+
# # ...
|
|
85
|
+
# end
|
|
86
|
+
#
|
|
87
|
+
# @example With a custom type:
|
|
88
|
+
# argument :bar, type: Integer,
|
|
89
|
+
# desc: "Bar argument"
|
|
90
|
+
#
|
|
91
|
+
# @example With a default value:
|
|
92
|
+
# argument :bar, default: "bar.txt",
|
|
93
|
+
# desc: "Bar argument"
|
|
94
|
+
#
|
|
95
|
+
# @example An optional argument:
|
|
96
|
+
# argument :bar, required: true,
|
|
97
|
+
# desc: "Bar argument"
|
|
98
|
+
#
|
|
99
|
+
# @example A repeating argument:
|
|
100
|
+
# argument :bar, repeats: true,
|
|
101
|
+
# desc: "Bar argument"
|
|
102
|
+
#
|
|
103
|
+
def argument(name,**kwargs,&block)
|
|
104
|
+
arguments[name] = Argument.new(name,**kwargs,&block)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
#
|
|
109
|
+
# Checks the minimum/maximum number of arguments, then calls the
|
|
110
|
+
# superclass'es `#main`.
|
|
111
|
+
#
|
|
112
|
+
# @param [Array<String>] argv
|
|
113
|
+
# The arguments passed to the program.
|
|
114
|
+
#
|
|
115
|
+
# @return [Integer]
|
|
116
|
+
# The exit status code. If too few or too many arguments are given, then
|
|
117
|
+
# an error message is printed and `1` is returned.
|
|
118
|
+
#
|
|
119
|
+
def main(argv=[])
|
|
120
|
+
required_args = self.class.arguments.each_value.count(&:required?)
|
|
121
|
+
optional_args = self.class.arguments.each_value.count(&:optional?)
|
|
122
|
+
has_repeats_arg = self.class.arguments.each_value.any?(&:repeats?)
|
|
123
|
+
|
|
124
|
+
if argv.length < required_args
|
|
125
|
+
print_error("insufficient number of arguments.")
|
|
126
|
+
help_usage
|
|
127
|
+
return 1
|
|
128
|
+
elsif argv.length > (required_args + optional_args) && !has_repeats_arg
|
|
129
|
+
print_error("too many arguments given")
|
|
130
|
+
help_usage
|
|
131
|
+
return 1
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
super(argv)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
#
|
|
138
|
+
# Prints any defined arguments, along with the usual `--help` information.
|
|
139
|
+
#
|
|
140
|
+
def help_arguments
|
|
141
|
+
unless (arguments = self.class.arguments).empty?
|
|
142
|
+
puts
|
|
143
|
+
puts 'Arguments:'
|
|
144
|
+
|
|
145
|
+
self.class.arguments.each_value do |arg|
|
|
146
|
+
puts " #{arg.usage.ljust(33)}#{arg.desc}"
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
#
|
|
152
|
+
# Calls the superclass'es `#help` method, if it's defined, then calls
|
|
153
|
+
# {#help_arguments}.
|
|
154
|
+
#
|
|
155
|
+
def help
|
|
156
|
+
super if defined?(super)
|
|
157
|
+
|
|
158
|
+
help_arguments
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
require 'command_kit/arguments/argument_value'
|
|
2
|
+
|
|
3
|
+
module CommandKit
|
|
4
|
+
module Arguments
|
|
5
|
+
#
|
|
6
|
+
# Represents a defined argument.
|
|
7
|
+
#
|
|
8
|
+
class Argument < ArgumentValue
|
|
9
|
+
|
|
10
|
+
# @return [Symbol]
|
|
11
|
+
attr_reader :name
|
|
12
|
+
|
|
13
|
+
# @return [Boolean]
|
|
14
|
+
attr_reader :repeats
|
|
15
|
+
|
|
16
|
+
# @return [String, nil]
|
|
17
|
+
attr_reader :desc
|
|
18
|
+
|
|
19
|
+
# @return [Regexp, nil]
|
|
20
|
+
attr_reader :pattern
|
|
21
|
+
|
|
22
|
+
# @return [Proc, nil]
|
|
23
|
+
attr_reader :parser
|
|
24
|
+
|
|
25
|
+
# @return [Proc, nil]
|
|
26
|
+
attr_reader :block
|
|
27
|
+
|
|
28
|
+
#
|
|
29
|
+
# Initializes the argument.
|
|
30
|
+
#
|
|
31
|
+
# @param [Symbol] name
|
|
32
|
+
#
|
|
33
|
+
# @param [Class, Hash, Array, Regexp] type
|
|
34
|
+
#
|
|
35
|
+
# @param [String, nil] usage
|
|
36
|
+
#
|
|
37
|
+
# @param [Object, Proc, nil] default
|
|
38
|
+
#
|
|
39
|
+
# @param [Boolean] required
|
|
40
|
+
#
|
|
41
|
+
# @param [Boolean] repeats
|
|
42
|
+
#
|
|
43
|
+
# @param [String] desc
|
|
44
|
+
#
|
|
45
|
+
# @note `usage` will be assigned a default value based on `type` and
|
|
46
|
+
# `name`.
|
|
47
|
+
#
|
|
48
|
+
# @yield [(value)]
|
|
49
|
+
#
|
|
50
|
+
# @yieldparam [Object, nil] value
|
|
51
|
+
#
|
|
52
|
+
def initialize(name, type: String,
|
|
53
|
+
usage: name.to_s.upcase,
|
|
54
|
+
default: nil,
|
|
55
|
+
required: true,
|
|
56
|
+
repeats: false,
|
|
57
|
+
desc: ,
|
|
58
|
+
&block)
|
|
59
|
+
super(
|
|
60
|
+
type: type,
|
|
61
|
+
usage: usage,
|
|
62
|
+
default: default,
|
|
63
|
+
required: required
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
@name = name
|
|
67
|
+
@repeats = repeats
|
|
68
|
+
@desc = desc
|
|
69
|
+
|
|
70
|
+
@pattern, @parser = self.class.parser(@type)
|
|
71
|
+
|
|
72
|
+
@block = block
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
#
|
|
76
|
+
# Looks up the option parser for the given `OptionParser` type.
|
|
77
|
+
#
|
|
78
|
+
# @param [Class] type
|
|
79
|
+
# The `OptionParser` type class.
|
|
80
|
+
#
|
|
81
|
+
# @return [(Regexp, Proc), nil]
|
|
82
|
+
# The matching pattern and converter proc.
|
|
83
|
+
#
|
|
84
|
+
def self.parser(type)
|
|
85
|
+
OptionParser::DefaultList.search(:atype,type)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
#
|
|
89
|
+
# Specifies whether the argument can be repeated repeat times.
|
|
90
|
+
#
|
|
91
|
+
# @return [Boolean]
|
|
92
|
+
#
|
|
93
|
+
def repeats?
|
|
94
|
+
@repeats
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
#
|
|
98
|
+
# The usage string for the argument.
|
|
99
|
+
#
|
|
100
|
+
# @return [String]
|
|
101
|
+
#
|
|
102
|
+
def usage
|
|
103
|
+
string = @usage
|
|
104
|
+
string = "#{string} ..." if repeats?
|
|
105
|
+
string = "[#{string}]" if optional?
|
|
106
|
+
string
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
module CommandKit
|
|
2
|
+
module Arguments
|
|
3
|
+
#
|
|
4
|
+
# Represents an individual argument value.
|
|
5
|
+
#
|
|
6
|
+
class ArgumentValue
|
|
7
|
+
|
|
8
|
+
# The desired type of the argument value.
|
|
9
|
+
#
|
|
10
|
+
# @return [Class, Hash, Array, Regexp, nil]
|
|
11
|
+
attr_reader :type
|
|
12
|
+
|
|
13
|
+
# The default parsed value for the argument value.
|
|
14
|
+
#
|
|
15
|
+
# @return [Object, Proc, nil]
|
|
16
|
+
attr_reader :default
|
|
17
|
+
|
|
18
|
+
# Specifies whether the argument value is required or optional.
|
|
19
|
+
#
|
|
20
|
+
# @return [Boolean]
|
|
21
|
+
attr_reader :required
|
|
22
|
+
|
|
23
|
+
# The usage string to describe the argument value.
|
|
24
|
+
#
|
|
25
|
+
# @return [String]
|
|
26
|
+
attr_reader :usage
|
|
27
|
+
|
|
28
|
+
#
|
|
29
|
+
# Initializes the argument value.
|
|
30
|
+
#
|
|
31
|
+
# @param [Class, Hash, Array, Regexp] type
|
|
32
|
+
# The type of the argument value.
|
|
33
|
+
#
|
|
34
|
+
# @param [Boolean] required
|
|
35
|
+
# Specifies whether the argument value is required or optional.
|
|
36
|
+
#
|
|
37
|
+
# @param [String] usage
|
|
38
|
+
# The usage string to represent the argument value.
|
|
39
|
+
#
|
|
40
|
+
# @param [Object, Proc, nil] default
|
|
41
|
+
# The default parsed value for the argument value.
|
|
42
|
+
#
|
|
43
|
+
def initialize(type: nil, required: true, default: nil, usage: )
|
|
44
|
+
@type = type
|
|
45
|
+
@required = required
|
|
46
|
+
@default = default
|
|
47
|
+
@usage = usage
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
#
|
|
51
|
+
# Determines if the argument is required or not.
|
|
52
|
+
#
|
|
53
|
+
# @return [Boolean]
|
|
54
|
+
#
|
|
55
|
+
def required?
|
|
56
|
+
@required
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
#
|
|
60
|
+
# Determines whether the argument can be omitted.
|
|
61
|
+
#
|
|
62
|
+
# @return [Boolean]
|
|
63
|
+
#
|
|
64
|
+
def optional?
|
|
65
|
+
!@required
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
#
|
|
69
|
+
# Returns a new default value.
|
|
70
|
+
#
|
|
71
|
+
# @return [Object]
|
|
72
|
+
#
|
|
73
|
+
def default_value
|
|
74
|
+
if @default.respond_to?(:call) then @default.call
|
|
75
|
+
else @default.dup
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'command_kit/stdio'
|
|
4
|
+
require 'command_kit/env'
|
|
5
|
+
|
|
6
|
+
module CommandKit
|
|
7
|
+
#
|
|
8
|
+
# Defines ANSI color codes.
|
|
9
|
+
#
|
|
10
|
+
# ## Examples
|
|
11
|
+
#
|
|
12
|
+
# include CommandKit::Colors
|
|
13
|
+
#
|
|
14
|
+
# def run
|
|
15
|
+
# puts colors.green("hello world")
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# ### Printing color error messages
|
|
19
|
+
#
|
|
20
|
+
# stderr.puts colors(stderr).red("error!")
|
|
21
|
+
#
|
|
22
|
+
# ## Environment Variables
|
|
23
|
+
#
|
|
24
|
+
# * `TERM` - Specifies the type of terminal. When set to `DUMB`, it will
|
|
25
|
+
# disable color output.
|
|
26
|
+
#
|
|
27
|
+
# ## Alternatives
|
|
28
|
+
#
|
|
29
|
+
# * [ansi](http://rubyworks.github.io/ansi/)
|
|
30
|
+
# * [colorize](https://github.com/fazibear/colorize#readme)
|
|
31
|
+
#
|
|
32
|
+
# @see https://en.wikipedia.org/wiki/ANSI_escape_code
|
|
33
|
+
#
|
|
34
|
+
module Colors
|
|
35
|
+
|
|
36
|
+
include Stdio
|
|
37
|
+
include Env
|
|
38
|
+
|
|
39
|
+
#
|
|
40
|
+
# Applies ANSI formatting to text.
|
|
41
|
+
#
|
|
42
|
+
module ANSI
|
|
43
|
+
# ANSI reset code
|
|
44
|
+
RESET = "\e[0m"
|
|
45
|
+
|
|
46
|
+
# @see RESET
|
|
47
|
+
CLEAR = RESET
|
|
48
|
+
|
|
49
|
+
# ANSI code for bold text
|
|
50
|
+
BOLD = "\e[1m"
|
|
51
|
+
|
|
52
|
+
# ANSI code to disable boldness
|
|
53
|
+
RESET_INTENSITY = "\e[22m"
|
|
54
|
+
|
|
55
|
+
# ANSI color code for black
|
|
56
|
+
BLACK = "\e[30m"
|
|
57
|
+
|
|
58
|
+
# ANSI color code for red
|
|
59
|
+
RED = "\e[31m"
|
|
60
|
+
|
|
61
|
+
# ANSI color code for green
|
|
62
|
+
GREEN = "\e[32m"
|
|
63
|
+
|
|
64
|
+
# ANSI color code for yellow
|
|
65
|
+
YELLOW = "\e[33m"
|
|
66
|
+
|
|
67
|
+
# ANSI color code for blue
|
|
68
|
+
BLUE = "\e[34m"
|
|
69
|
+
|
|
70
|
+
# ANSI color code for megenta
|
|
71
|
+
MAGENTA = "\e[35m"
|
|
72
|
+
|
|
73
|
+
# ANSI color code for cyan
|
|
74
|
+
CYAN = "\e[36m"
|
|
75
|
+
|
|
76
|
+
# ANSI color code for white
|
|
77
|
+
WHITE = "\e[37m"
|
|
78
|
+
|
|
79
|
+
# ANSI color for the default foreground color
|
|
80
|
+
RESET_COLOR = "\e[39m"
|
|
81
|
+
|
|
82
|
+
module_function
|
|
83
|
+
|
|
84
|
+
#
|
|
85
|
+
# Resets text formatting.
|
|
86
|
+
#
|
|
87
|
+
# @return [RESET]
|
|
88
|
+
#
|
|
89
|
+
# @see RESET
|
|
90
|
+
#
|
|
91
|
+
def reset
|
|
92
|
+
RESET
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
#
|
|
96
|
+
# @see reset
|
|
97
|
+
#
|
|
98
|
+
def clear
|
|
99
|
+
reset
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
#
|
|
103
|
+
# Bolds the text.
|
|
104
|
+
#
|
|
105
|
+
# @param [String, nil] string
|
|
106
|
+
# An optional string.
|
|
107
|
+
#
|
|
108
|
+
# @return [String, BOLD]
|
|
109
|
+
# The bolded string or just {BOLD} if no arguments were given.
|
|
110
|
+
#
|
|
111
|
+
# @see BOLD
|
|
112
|
+
#
|
|
113
|
+
def bold(string=nil)
|
|
114
|
+
if string then "#{BOLD}#{string}#{RESET_INTENSITY}"
|
|
115
|
+
else BOLD
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
#
|
|
120
|
+
# Sets the text color to black.
|
|
121
|
+
#
|
|
122
|
+
# @param [String, nil] string
|
|
123
|
+
# An optional string.
|
|
124
|
+
#
|
|
125
|
+
# @return [String, BLACK]
|
|
126
|
+
# The colorized string or just {BLACK} if no arguments were given.
|
|
127
|
+
#
|
|
128
|
+
# @see BLACK
|
|
129
|
+
#
|
|
130
|
+
def black(string=nil)
|
|
131
|
+
if string then "#{BLACK}#{string}#{RESET_COLOR}"
|
|
132
|
+
else BLACK
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
#
|
|
137
|
+
# Sets the text color to red.
|
|
138
|
+
#
|
|
139
|
+
# @param [String, nil] string
|
|
140
|
+
# An optional string.
|
|
141
|
+
#
|
|
142
|
+
# @return [String, RED]
|
|
143
|
+
# The colorized string or just {RED} if no arguments were given.
|
|
144
|
+
#
|
|
145
|
+
# @see RED
|
|
146
|
+
#
|
|
147
|
+
def red(string=nil)
|
|
148
|
+
if string then "#{RED}#{string}#{RESET_COLOR}"
|
|
149
|
+
else RED
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
#
|
|
154
|
+
# Sets the text color to green.
|
|
155
|
+
#
|
|
156
|
+
# @param [String, nil] string
|
|
157
|
+
# An optional string.
|
|
158
|
+
#
|
|
159
|
+
# @return [String, GREEN]
|
|
160
|
+
# The colorized string or just {GREEN} if no arguments were given.
|
|
161
|
+
#
|
|
162
|
+
# @see GREEN
|
|
163
|
+
#
|
|
164
|
+
def green(string=nil)
|
|
165
|
+
if string then "#{GREEN}#{string}#{RESET_COLOR}"
|
|
166
|
+
else GREEN
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
#
|
|
171
|
+
# Sets the text color to yellow.
|
|
172
|
+
#
|
|
173
|
+
# @param [String, nil] string
|
|
174
|
+
# An optional string.
|
|
175
|
+
#
|
|
176
|
+
# @return [String, YELLOW]
|
|
177
|
+
# The colorized string or just {YELLOW} if no arguments were given.
|
|
178
|
+
#
|
|
179
|
+
# @see YELLOW
|
|
180
|
+
#
|
|
181
|
+
def yellow(string=nil)
|
|
182
|
+
if string then "#{YELLOW}#{string}#{RESET_COLOR}"
|
|
183
|
+
else YELLOW
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
#
|
|
188
|
+
# Sets the text color to blue.
|
|
189
|
+
#
|
|
190
|
+
# @param [String, nil] string
|
|
191
|
+
# An optional string.
|
|
192
|
+
#
|
|
193
|
+
# @return [String, BLUE]
|
|
194
|
+
# The colorized string or just {BLUE} if no arguments were given.
|
|
195
|
+
#
|
|
196
|
+
# @see BLUE
|
|
197
|
+
#
|
|
198
|
+
def blue(string=nil)
|
|
199
|
+
if string then "#{BLUE}#{string}#{RESET_COLOR}"
|
|
200
|
+
else BLUE
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
#
|
|
205
|
+
# Sets the text color to magenta.
|
|
206
|
+
#
|
|
207
|
+
# @param [String, nil] string
|
|
208
|
+
# An optional string.
|
|
209
|
+
#
|
|
210
|
+
# @return [String, MAGENTA]
|
|
211
|
+
# The colorized string or just {MAGENTA} if no arguments were given.
|
|
212
|
+
#
|
|
213
|
+
# @see MAGENTA
|
|
214
|
+
#
|
|
215
|
+
def magenta(string=nil)
|
|
216
|
+
if string then "#{MAGENTA}#{string}#{RESET_COLOR}"
|
|
217
|
+
else MAGENTA
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
#
|
|
222
|
+
# Sets the text color to cyan.
|
|
223
|
+
#
|
|
224
|
+
# @param [String, nil] string
|
|
225
|
+
# An optional string.
|
|
226
|
+
#
|
|
227
|
+
# @return [String, CYAN]
|
|
228
|
+
# The colorized string or just {CYAN} if no arguments were given.
|
|
229
|
+
#
|
|
230
|
+
# @see CYAN
|
|
231
|
+
#
|
|
232
|
+
def cyan(string=nil)
|
|
233
|
+
if string then "#{CYAN}#{string}#{RESET_COLOR}"
|
|
234
|
+
else CYAN
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
#
|
|
239
|
+
# Sets the text color to white.
|
|
240
|
+
#
|
|
241
|
+
# @param [String, nil] string
|
|
242
|
+
# An optional string.
|
|
243
|
+
#
|
|
244
|
+
# @return [String, WHITE]
|
|
245
|
+
# The colorized string or just {WHITE} if no arguments were given.
|
|
246
|
+
#
|
|
247
|
+
# @see WHITE
|
|
248
|
+
#
|
|
249
|
+
def white(string=nil)
|
|
250
|
+
if string then "#{WHITE}#{string}#{RESET_COLOR}"
|
|
251
|
+
else WHITE
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
#
|
|
257
|
+
# Dummy module with the same interface as {ANSI}, but for when ANSI is not
|
|
258
|
+
# supported.
|
|
259
|
+
#
|
|
260
|
+
module PlainText
|
|
261
|
+
RESET = \
|
|
262
|
+
CLEAR = \
|
|
263
|
+
BOLD = \
|
|
264
|
+
RESET_INTENSITY = \
|
|
265
|
+
BLACK = \
|
|
266
|
+
RED = \
|
|
267
|
+
GREEN = \
|
|
268
|
+
YELLOW = \
|
|
269
|
+
BLUE = \
|
|
270
|
+
MAGENTA = \
|
|
271
|
+
CYAN = \
|
|
272
|
+
WHITE = \
|
|
273
|
+
RESET_COLOR = ''
|
|
274
|
+
|
|
275
|
+
module_function
|
|
276
|
+
|
|
277
|
+
def reset
|
|
278
|
+
RESET
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def clear
|
|
282
|
+
reset
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
def bold(string=nil)
|
|
286
|
+
string || ''
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def black(string=nil)
|
|
290
|
+
string || ''
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def red(string=nil)
|
|
294
|
+
string || ''
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def green(string=nil)
|
|
298
|
+
string || ''
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def yellow(string=nil)
|
|
302
|
+
string || ''
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def blue(string=nil)
|
|
306
|
+
string || ''
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def magenta(string=nil)
|
|
310
|
+
string || ''
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
def cyan(string=nil)
|
|
314
|
+
string || ''
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
def white(string=nil)
|
|
318
|
+
string || ''
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
#
|
|
323
|
+
# Checks if the stream supports ANSI output.
|
|
324
|
+
#
|
|
325
|
+
# @param [IO] stream
|
|
326
|
+
#
|
|
327
|
+
# @return [Boolean]
|
|
328
|
+
#
|
|
329
|
+
# @note
|
|
330
|
+
# When the env variable `TERM` is set to `dumb`, it will disable color
|
|
331
|
+
# output. Color output will also be disabled if the given stream is not
|
|
332
|
+
# a TTY.
|
|
333
|
+
#
|
|
334
|
+
def ansi?(stream=stdout)
|
|
335
|
+
env['TERM'] != 'dumb' && stream.tty?
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
#
|
|
339
|
+
# Returns the colors available for the given stream.
|
|
340
|
+
#
|
|
341
|
+
# @param [IO] stream
|
|
342
|
+
#
|
|
343
|
+
# @return [ANSI, PlainText]
|
|
344
|
+
# The ANSI module or PlainText dummy module.
|
|
345
|
+
#
|
|
346
|
+
def colors(stream=stdout)
|
|
347
|
+
color = if ansi?(stream) then ANSI
|
|
348
|
+
else PlainText
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
yield color if block_given?
|
|
352
|
+
return color
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
end
|