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
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CommandKit
|
|
4
|
+
module Help
|
|
5
|
+
#
|
|
6
|
+
# Allows displaying a man-page instead of the usual `--help` output.
|
|
7
|
+
#
|
|
8
|
+
# ## Environment Variables
|
|
9
|
+
#
|
|
10
|
+
# * `TERM` - Specifies the type of terminal. When set to `DUMB`, it will
|
|
11
|
+
# disable man-page help output.
|
|
12
|
+
#
|
|
13
|
+
module Man
|
|
14
|
+
module ModuleMethods
|
|
15
|
+
#
|
|
16
|
+
# Extends {ClassMethods} or {ModuleMethods}, depending on whether
|
|
17
|
+
# {Help::Man} is being included into a class or a module.
|
|
18
|
+
#
|
|
19
|
+
# @param [Class, Module] context
|
|
20
|
+
# The class or module including {Man}.
|
|
21
|
+
#
|
|
22
|
+
def included(context)
|
|
23
|
+
super(context)
|
|
24
|
+
|
|
25
|
+
if context.class == Module
|
|
26
|
+
context.extend ModuleMethods
|
|
27
|
+
else
|
|
28
|
+
context.extend ClassMethods
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
extend ModuleMethods
|
|
34
|
+
|
|
35
|
+
#
|
|
36
|
+
# Defines class-level methods.
|
|
37
|
+
#
|
|
38
|
+
module ClassMethods
|
|
39
|
+
#
|
|
40
|
+
# Gets or sets the directory where man-pages are stored.
|
|
41
|
+
#
|
|
42
|
+
# @param [String, nil] new_man_dir
|
|
43
|
+
# If a String is given, it will set The class'es man-page directory.
|
|
44
|
+
#
|
|
45
|
+
# @return [String, nil]
|
|
46
|
+
# The class'es or superclass'es man-page directory.
|
|
47
|
+
#
|
|
48
|
+
# @example
|
|
49
|
+
# man_dir File.expand_path('../../../man',__FILE__)
|
|
50
|
+
#
|
|
51
|
+
def man_dir(new_man_dir=nil)
|
|
52
|
+
if new_man_dir
|
|
53
|
+
@man_dir = File.expand_path(new_man_dir)
|
|
54
|
+
else
|
|
55
|
+
@man_dir || (superclass.man_dir if superclass.kind_of?(ClassMethods))
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
#
|
|
61
|
+
# Determines if displaying man pages is supported.
|
|
62
|
+
#
|
|
63
|
+
# @return [Boolean]
|
|
64
|
+
# Indicates whether the `TERM` environment variable is not `dumb`
|
|
65
|
+
# and `$stdout` is a TTY.
|
|
66
|
+
#
|
|
67
|
+
def self.supported?
|
|
68
|
+
ENV['TERM'] != 'dumb' && $stdout.tty?
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
#
|
|
72
|
+
# Returns the man-page file name for the given command name.
|
|
73
|
+
#
|
|
74
|
+
# @param [String] command
|
|
75
|
+
# The given command name.
|
|
76
|
+
#
|
|
77
|
+
# @return [String]
|
|
78
|
+
# The man-page file name.
|
|
79
|
+
#
|
|
80
|
+
def man_page(command=command_name)
|
|
81
|
+
"#{command}.1"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
#
|
|
85
|
+
# Displays the given man page.
|
|
86
|
+
#
|
|
87
|
+
# @param [String] page
|
|
88
|
+
# The man page file name.
|
|
89
|
+
#
|
|
90
|
+
# @return [Boolean, nil]
|
|
91
|
+
# Specifies whether the `man` command was successful or not.
|
|
92
|
+
# Returns `nil` when the `man` command is not installed.
|
|
93
|
+
#
|
|
94
|
+
def man(page=man_page)
|
|
95
|
+
system('man',page)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
#
|
|
99
|
+
# Displays the {#man_page} instead of the usual `--help` output.
|
|
100
|
+
#
|
|
101
|
+
# @raise [NotImplementedError]
|
|
102
|
+
# {ClassMethods#man_dir man_dir} does not have a value.
|
|
103
|
+
#
|
|
104
|
+
# @note
|
|
105
|
+
# if `TERM` is `dumb` or `$stdout` is not a TTY, fallsback to printing
|
|
106
|
+
# the usual `--help` output.
|
|
107
|
+
#
|
|
108
|
+
def help
|
|
109
|
+
if Man.supported?
|
|
110
|
+
unless self.class.man_dir
|
|
111
|
+
raise(NotImplementedError,"#{self.class}.man_dir not set")
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
man_path = File.join(self.class.man_dir,man_page)
|
|
115
|
+
|
|
116
|
+
if man(man_path).nil?
|
|
117
|
+
super
|
|
118
|
+
end
|
|
119
|
+
else
|
|
120
|
+
super
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CommandKit
|
|
4
|
+
#
|
|
5
|
+
# A very simple inflector.
|
|
6
|
+
#
|
|
7
|
+
# @note
|
|
8
|
+
# If you need something more powerful, checkout
|
|
9
|
+
# [dry-inflector](https://dry-rb.org/gems/dry-inflector/0.1/)
|
|
10
|
+
#
|
|
11
|
+
module Inflector
|
|
12
|
+
#
|
|
13
|
+
# Removes the namespace from a constant name.
|
|
14
|
+
#
|
|
15
|
+
# @param [#to_s] name
|
|
16
|
+
# The constant name.
|
|
17
|
+
#
|
|
18
|
+
# @return [String]
|
|
19
|
+
# The class or module's name, without the namespace.
|
|
20
|
+
#
|
|
21
|
+
def self.demodularize(name)
|
|
22
|
+
name.to_s.split('::').last
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
#
|
|
26
|
+
# Converts a CamelCased name to an under_scored name.
|
|
27
|
+
#
|
|
28
|
+
# @param [#to_s] name
|
|
29
|
+
# The CamelCased name.
|
|
30
|
+
#
|
|
31
|
+
# @return [String]
|
|
32
|
+
# The resulting under_scored name.
|
|
33
|
+
#
|
|
34
|
+
def self.underscore(name)
|
|
35
|
+
# sourced from: https://github.com/dry-rb/dry-inflector/blob/c918f967ff82611da374eb0847a77b7e012d3fa8/lib/dry/inflector.rb#L286-L287
|
|
36
|
+
name = name.to_s.dup
|
|
37
|
+
|
|
38
|
+
name.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
|
|
39
|
+
name.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
|
40
|
+
name.tr!('-','_')
|
|
41
|
+
name.downcase!
|
|
42
|
+
|
|
43
|
+
name
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
#
|
|
47
|
+
# Replaces all underscores with dashes.
|
|
48
|
+
#
|
|
49
|
+
# @param [#to_s] name
|
|
50
|
+
# The under_scored name.
|
|
51
|
+
#
|
|
52
|
+
# @return [String]
|
|
53
|
+
# The dasherized name.
|
|
54
|
+
#
|
|
55
|
+
def self.dasherize(name)
|
|
56
|
+
name.to_s.tr('_','-')
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
#
|
|
60
|
+
# Converts an under_scored name to a CamelCased name.
|
|
61
|
+
#
|
|
62
|
+
# @param [String] name
|
|
63
|
+
# The under_scored name.
|
|
64
|
+
#
|
|
65
|
+
# @return [String]
|
|
66
|
+
# The CamelCased name.
|
|
67
|
+
#
|
|
68
|
+
def self.camelize(name)
|
|
69
|
+
name = name.to_s.dup
|
|
70
|
+
|
|
71
|
+
# sourced from: https://github.com/dry-rb/dry-inflector/blob/c918f967ff82611da374eb0847a77b7e012d3fa8/lib/dry/inflector.rb#L329-L334
|
|
72
|
+
name.sub!(/^[a-z\d]*/,&:capitalize)
|
|
73
|
+
name.gsub!(%r{(?:[_-]|(/))([a-z\d]*)}i) do |match|
|
|
74
|
+
slash = Regexp.last_match(1)
|
|
75
|
+
word = Regexp.last_match(2)
|
|
76
|
+
|
|
77
|
+
"#{slash}#{word.capitalize}"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
name.gsub!('/','::')
|
|
81
|
+
name
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
module CommandKit
|
|
2
|
+
#
|
|
3
|
+
# Defines a `main` method.
|
|
4
|
+
#
|
|
5
|
+
# ## Examples
|
|
6
|
+
#
|
|
7
|
+
# include CommandKit::Main
|
|
8
|
+
#
|
|
9
|
+
# def main(argv=[])
|
|
10
|
+
# # ...
|
|
11
|
+
# return 0
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
14
|
+
module Main
|
|
15
|
+
module ModuleMethods
|
|
16
|
+
#
|
|
17
|
+
# Extends {ClassMethods} or {ModuleMethods}, depending on whether {Main}
|
|
18
|
+
# is being included into a class or a module.
|
|
19
|
+
#
|
|
20
|
+
# @param [Class, Module] context
|
|
21
|
+
# The class or module which is including {Main}.
|
|
22
|
+
#
|
|
23
|
+
def included(context)
|
|
24
|
+
super(context)
|
|
25
|
+
|
|
26
|
+
if context.class == Module
|
|
27
|
+
context.extend ModuleMethods
|
|
28
|
+
else
|
|
29
|
+
context.extend ClassMethods
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
extend ModuleMethods
|
|
35
|
+
|
|
36
|
+
#
|
|
37
|
+
# Class-level methods.
|
|
38
|
+
#
|
|
39
|
+
module ClassMethods
|
|
40
|
+
#
|
|
41
|
+
# Starts the command and then exits.
|
|
42
|
+
#
|
|
43
|
+
# @param [Array<String>] argv
|
|
44
|
+
# The Array of command-line arguments.
|
|
45
|
+
#
|
|
46
|
+
def start(argv=ARGV, **kwargs)
|
|
47
|
+
begin
|
|
48
|
+
exit main(argv, **kwargs)
|
|
49
|
+
rescue Interrupt
|
|
50
|
+
# https://tldp.org/LDP/abs/html/exitcodes.html
|
|
51
|
+
exit 130
|
|
52
|
+
rescue Errno::EPIPE
|
|
53
|
+
# STDOUT pipe broken
|
|
54
|
+
exit 0
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
#
|
|
59
|
+
# Initializes the command class with the given keyword arguments, then
|
|
60
|
+
# calls {Main#main main} with the given `argv`.
|
|
61
|
+
#
|
|
62
|
+
# @param [Array<String>] argv
|
|
63
|
+
# The Array of command-line arguments.
|
|
64
|
+
#
|
|
65
|
+
# @param [Hash{Symbol => Object}] kwargs
|
|
66
|
+
# Additional keyword arguments to initialize the command class with.
|
|
67
|
+
#
|
|
68
|
+
# @return [Integer]
|
|
69
|
+
# The exit status of the command.
|
|
70
|
+
#
|
|
71
|
+
def main(argv=[], **kwargs)
|
|
72
|
+
new(**kwargs).main(argv)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
#
|
|
77
|
+
# Place-holder `main` method, which parses options, before calling {#run}.
|
|
78
|
+
#
|
|
79
|
+
# @param [Array<String>] argv
|
|
80
|
+
# The Array of command-line arguments.
|
|
81
|
+
#
|
|
82
|
+
# @return [Integer]
|
|
83
|
+
# The exit status code.
|
|
84
|
+
#
|
|
85
|
+
def main(argv=[])
|
|
86
|
+
run(*argv)
|
|
87
|
+
return 0
|
|
88
|
+
rescue SystemExit => system_exit
|
|
89
|
+
return system_exit.status
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
#
|
|
93
|
+
# Place-holder method for command business logic.
|
|
94
|
+
#
|
|
95
|
+
# @param [Array<Object>] args
|
|
96
|
+
# Additional arguments for the command.
|
|
97
|
+
#
|
|
98
|
+
# @abstract
|
|
99
|
+
#
|
|
100
|
+
def run(*args)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
require 'command_kit/options/option'
|
|
2
|
+
require 'command_kit/options/parser'
|
|
3
|
+
|
|
4
|
+
module CommandKit
|
|
5
|
+
#
|
|
6
|
+
# Provides a thin DSL for defining options as attributes.
|
|
7
|
+
#
|
|
8
|
+
# ## Examples
|
|
9
|
+
#
|
|
10
|
+
# include CommandKit::Options
|
|
11
|
+
#
|
|
12
|
+
# option :foo, type: String,
|
|
13
|
+
# short: '-f',
|
|
14
|
+
# desc: "Foo option"
|
|
15
|
+
#
|
|
16
|
+
# option :bar, type: String,
|
|
17
|
+
# short: '-b',
|
|
18
|
+
# usage: 'STR:STR:...',
|
|
19
|
+
# desc: "Bar option" do |arg|
|
|
20
|
+
# @bar = arg.split(':')
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# option :number, type: Integer,
|
|
24
|
+
# desc: 'Numbers' do |num|
|
|
25
|
+
# @numbers << num
|
|
26
|
+
# end
|
|
27
|
+
#
|
|
28
|
+
# def initialize
|
|
29
|
+
# super
|
|
30
|
+
#
|
|
31
|
+
# @numbers = []
|
|
32
|
+
# end
|
|
33
|
+
#
|
|
34
|
+
module Options
|
|
35
|
+
include Parser
|
|
36
|
+
|
|
37
|
+
module ModuleMethods
|
|
38
|
+
#
|
|
39
|
+
# Extends {ClassMethods} or {ModuleMethods}, depending on whether
|
|
40
|
+
# {Options} is being included into a class or a module.
|
|
41
|
+
#
|
|
42
|
+
# @param [Class, Module] context
|
|
43
|
+
# The class or module which is including {Options}.
|
|
44
|
+
#
|
|
45
|
+
def included(context)
|
|
46
|
+
super(context)
|
|
47
|
+
|
|
48
|
+
if context.class == Module
|
|
49
|
+
context.extend ModuleMethods
|
|
50
|
+
else
|
|
51
|
+
context.extend ClassMethods
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
extend ModuleMethods
|
|
57
|
+
|
|
58
|
+
#
|
|
59
|
+
# Defines class-level methods.
|
|
60
|
+
#
|
|
61
|
+
module ClassMethods
|
|
62
|
+
#
|
|
63
|
+
# All defined options for the command class.
|
|
64
|
+
#
|
|
65
|
+
# @return [Hash{Symbol => Option}]
|
|
66
|
+
#
|
|
67
|
+
def options
|
|
68
|
+
@options ||= if superclass.kind_of?(ClassMethods)
|
|
69
|
+
superclass.options.dup
|
|
70
|
+
else
|
|
71
|
+
{}
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
#
|
|
76
|
+
# Defines an {Option option} for the class.
|
|
77
|
+
#
|
|
78
|
+
# @param [Symbol] name
|
|
79
|
+
# The option name.
|
|
80
|
+
#
|
|
81
|
+
# @yield [(value)]
|
|
82
|
+
# If a block is given, it will be passed the parsed option value.
|
|
83
|
+
#
|
|
84
|
+
# @yieldparam [Object, nil] value
|
|
85
|
+
# The parsed option value.
|
|
86
|
+
#
|
|
87
|
+
# @return [Option]
|
|
88
|
+
#
|
|
89
|
+
# @example Define an option:
|
|
90
|
+
# option :foo, desc: "Foo option"
|
|
91
|
+
#
|
|
92
|
+
# @example With a custom short option:
|
|
93
|
+
# option :foo, short: '-f',
|
|
94
|
+
# desc: "Foo option"
|
|
95
|
+
#
|
|
96
|
+
# @example With a custom long option:
|
|
97
|
+
# option :foo, short: '--foo-opt',
|
|
98
|
+
# desc: "Foo option"
|
|
99
|
+
#
|
|
100
|
+
# @example With a custom usage string:
|
|
101
|
+
# option :foo, value: {usage: 'FOO'},
|
|
102
|
+
# desc: "Foo option"
|
|
103
|
+
#
|
|
104
|
+
# @example With a custom block:
|
|
105
|
+
# option :foo, desc: "Foo option" do |value|
|
|
106
|
+
# @foo = Foo.new(value)
|
|
107
|
+
# end
|
|
108
|
+
#
|
|
109
|
+
# @example With a custom type:
|
|
110
|
+
# option :foo, value: {type: Integer},
|
|
111
|
+
# desc: "Foo option"
|
|
112
|
+
#
|
|
113
|
+
# @example With a default value:
|
|
114
|
+
# option :foo, value: {type: Integer, default: 1},
|
|
115
|
+
# desc: "Foo option"
|
|
116
|
+
#
|
|
117
|
+
# @example With a required value:
|
|
118
|
+
# option :foo, value: {type: String, required: true},
|
|
119
|
+
# desc: "Foo option"
|
|
120
|
+
#
|
|
121
|
+
# @example With a custom option value Hash map:
|
|
122
|
+
# option :flag, value: {
|
|
123
|
+
# type: {
|
|
124
|
+
# 'enabled' => :enabled,
|
|
125
|
+
# 'yes' => :enabled,
|
|
126
|
+
# 'disabled' => :disabled,
|
|
127
|
+
# 'no' => :disabled
|
|
128
|
+
# }
|
|
129
|
+
# },
|
|
130
|
+
# desc: "Flag option"
|
|
131
|
+
#
|
|
132
|
+
# @example With a custom option value Array enum:
|
|
133
|
+
# option :enum, value: {type: %w[yes no]},
|
|
134
|
+
# desc: "Enum option"
|
|
135
|
+
#
|
|
136
|
+
# @example With a custom option value Regexp:
|
|
137
|
+
# option :date, value: {type: /(\d+)-(\d+)-(\d{2,4})/},
|
|
138
|
+
# desc: "Regexp optin" do |date,d,m,y|
|
|
139
|
+
# # ...
|
|
140
|
+
# end
|
|
141
|
+
#
|
|
142
|
+
def option(name,**kwargs,&block)
|
|
143
|
+
options[name] = Option.new(name,**kwargs,&block)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Hash of parsed option values.
|
|
148
|
+
#
|
|
149
|
+
# @return [Hash{Symbol => Object}]
|
|
150
|
+
attr_reader :options
|
|
151
|
+
|
|
152
|
+
#
|
|
153
|
+
# Initializes {#options} and populates the
|
|
154
|
+
# {Parser#option_parser option parser}.
|
|
155
|
+
#
|
|
156
|
+
# @param [Hash{Symbol => Object}] options
|
|
157
|
+
# Optional pre-populated options hash.
|
|
158
|
+
#
|
|
159
|
+
def initialize(options: {}, **kwargs)
|
|
160
|
+
@options = options
|
|
161
|
+
|
|
162
|
+
super(**kwargs)
|
|
163
|
+
|
|
164
|
+
self.class.options.each_value do |option|
|
|
165
|
+
option_parser.on(*option.usage,option.type,option.desc) do |arg,*captures|
|
|
166
|
+
@options[option.name] = if arg.nil?
|
|
167
|
+
option.default_value
|
|
168
|
+
else
|
|
169
|
+
arg
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
if option.block
|
|
173
|
+
instance_exec(*arg,*captures,&option.block)
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|