dry-cli 0.6.0 → 0.7.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.md +66 -37
- data/LICENSE +1 -1
- data/README.md +1 -1
- data/dry-cli.gemspec +2 -3
- data/lib/dry/cli.rb +53 -34
- data/lib/dry/cli/banner.rb +31 -21
- data/lib/dry/cli/command.rb +51 -20
- data/lib/dry/cli/command_registry.rb +59 -34
- data/lib/dry/cli/inflector.rb +1 -1
- data/lib/dry/cli/inline.rb +4 -4
- data/lib/dry/cli/option.rb +2 -2
- data/lib/dry/cli/parser.rb +16 -18
- data/lib/dry/cli/program_name.rb +1 -1
- data/lib/dry/cli/registry.rb +11 -6
- data/lib/dry/cli/usage.rb +11 -8
- data/lib/dry/cli/version.rb +1 -1
- metadata +18 -19
- data/lib/dry/cli/utils/files.rb +0 -444
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: acfd9b78000e6f3ecef16d4eee260eee84bb4661251966e367e4f9a2001d3dac
|
4
|
+
data.tar.gz: df37074af2d1ed387d24ab90ed37920247cc40dc4c508c1325f08e9cb395c277
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c2b0035c9df7cbe7cf01fabd69a0207aaab945a13debf8b4a1441d764853343ac2a2dd1264c395aeda3296957870fcdcd87fa44041f6948d490afde897f2d837
|
7
|
+
data.tar.gz: c74d981d7c23200a652f75013977a9ea3b720c1264e184fd93af83fcb33995ec00c6284021a7e29b3ea215e9ac5c51aaccbf2ff03c821f215aa52d433bf1fd62
|
data/CHANGELOG.md
CHANGED
@@ -1,17 +1,46 @@
|
|
1
|
+
<!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
|
2
|
+
|
3
|
+
## 0.7.0 2020-05-08
|
4
|
+
|
5
|
+
|
6
|
+
### Added
|
7
|
+
|
8
|
+
- Inheritable attributes for subclasses of commands (@IvanShamatov)
|
9
|
+
- Ability to register instances, not only classes as Commands (@IvanShamatov)
|
10
|
+
- Add support for subcommands with a parent command (@unrooty)
|
11
|
+
|
12
|
+
### Fixed
|
13
|
+
|
14
|
+
- Safely rescue pipe exception, when you CLI app is producing output for piped CLI app (IvanShamatov)
|
15
|
+
- Safely rescue keyboard interrupts (@IvanShamatov)
|
16
|
+
- [Internal] Don't run specs twice (@jodosha)
|
17
|
+
- Update inline call with keyward arguments (@flash-gordon)
|
18
|
+
|
19
|
+
### Changed
|
20
|
+
|
21
|
+
- Extracted Dry::CLI::Utils::Files into dry-files (@jodosha)
|
22
|
+
- Drop 2.3 ruby support (@IvanShamatov)
|
23
|
+
- [Internal] Changelog, issue templates (@solnic)
|
24
|
+
- Documentation updates (@davydovanton)
|
25
|
+
- Remove concurrent-ruby as runtime dependency (@jodosha)
|
26
|
+
- [Internal] Banner and Parses refactoring (@IvanShamatov)
|
27
|
+
|
28
|
+
[Compare v0.6.0...v0.7.0](https://github.com/dry-rb/dry-cli/compare/v0.6.0...v0.7.0)
|
29
|
+
|
1
30
|
## 0.6.0 2020-03-06
|
2
31
|
|
3
32
|
|
4
33
|
### Added
|
5
34
|
|
6
|
-
-
|
7
|
-
- [
|
8
|
-
-
|
9
|
-
-
|
35
|
+
- Ability to pass command along with registry (for a singular command case) (@IvanShamatov)
|
36
|
+
- [Internal] Backported ability to run gem's CI against ruby 2.3 (@flash-gordon)
|
37
|
+
- Inline syntax for commands (@IvanShamatov)
|
38
|
+
- Introduced stderr to any diagnostic output (@IvanShamatov)
|
10
39
|
|
11
40
|
### Fixed
|
12
41
|
|
13
|
-
- [John Ledbetter & Luca Guidi] Fix ruby 2.7 warnings
|
14
|
-
-
|
42
|
+
- [John Ledbetter & Luca Guidi] Fix ruby 2.7 warnings (@jodosha)
|
43
|
+
- Fix banner, when option is a type of Array (@IvanShamatov)
|
15
44
|
|
16
45
|
|
17
46
|
[Compare v0.5.1...v0.6.0](https://github.com/dry-rb/dry-cli/compare/v0.5.1...v0.6.0)
|
@@ -21,15 +50,15 @@
|
|
21
50
|
|
22
51
|
### Added
|
23
52
|
|
24
|
-
-
|
25
|
-
- [
|
26
|
-
- [
|
27
|
-
- [
|
28
|
-
- [
|
53
|
+
- Anonymous Registry sintax (@IvanShamatov)
|
54
|
+
- [Internal] Specs refactored, more unit specs added (@IvanShamatov)
|
55
|
+
- [Internal] removed `dry-inflector` as runtime dependency (@jodosha)
|
56
|
+
- [Internal] Refactored Command class (command_name property removed) (@IvanShamatov)
|
57
|
+
- [Internal] Adapt gem to dry-rb style (@jodosha, @flash-gordon, @solnic, @cgeorgii)
|
29
58
|
|
30
59
|
### Fixed
|
31
60
|
|
32
|
-
-
|
61
|
+
- Added missing 'set' require (@solnic)
|
33
62
|
|
34
63
|
|
35
64
|
[Compare v0.5.0...v0.5.1](https://github.com/dry-rb/dry-cli/compare/v0.5.0...v0.5.1)
|
@@ -39,7 +68,7 @@
|
|
39
68
|
|
40
69
|
### Added
|
41
70
|
|
42
|
-
- [
|
71
|
+
- [Internal] removed runtime and development dependency against `hanami-utils` (@jodosha, @IvanShamatov, @solnic)
|
43
72
|
|
44
73
|
|
45
74
|
[Compare v0.4.0...v0.5.0](https://github.com/dry-rb/dry-cli/compare/v0.4.0...v0.5.0)
|
@@ -49,7 +78,7 @@
|
|
49
78
|
|
50
79
|
### Added
|
51
80
|
|
52
|
-
-
|
81
|
+
- `hanami-cli` => `dry-cli` (@jodosha, @IvanShamatov, @solnic)
|
53
82
|
|
54
83
|
|
55
84
|
[Compare v0.3.1...v0.4.0](https://github.com/dry-rb/dry-cli/compare/v0.3.1...v0.4.0)
|
@@ -59,8 +88,8 @@
|
|
59
88
|
|
60
89
|
### Added
|
61
90
|
|
62
|
-
-
|
63
|
-
-
|
91
|
+
- Official support for Ruby: MRI 2.6 (@jodosha)
|
92
|
+
- Support `bundler` 2.0+ (@jodosha)
|
64
93
|
|
65
94
|
|
66
95
|
[Compare v0.3.0...v0.3.1](https://github.com/dry-rb/dry-cli/compare/v0.3.0...v0.3.1)
|
@@ -76,14 +105,14 @@
|
|
76
105
|
|
77
106
|
### Added
|
78
107
|
|
79
|
-
-
|
80
|
-
-
|
81
|
-
-
|
82
|
-
-
|
108
|
+
- Introduce array type for arguments (`foo exec test spec/bookshelf/entities spec/bookshelf/repositories`) (@davydovanton, @AlfonsoUceda)
|
109
|
+
- Introduce array type for options (`foo generate config --apps=web,api`) (@davydovanton, @AlfonsoUceda)
|
110
|
+
- Introduce variadic arguments (`foo run ruby:latest -- ruby -v`)
|
111
|
+
- Official support for JRuby 9.2.0.0 (@jodosha, @AlfonsoUceda)
|
83
112
|
|
84
113
|
### Fixed
|
85
114
|
|
86
|
-
-
|
115
|
+
- Print informative message when unknown or wrong option is passed (`"test" was called with arguments "--framework=unknown"`) (@davydovanton)
|
87
116
|
|
88
117
|
|
89
118
|
[Compare v0.2.0...v0.3.0.beta1](https://github.com/dry-rb/dry-cli/compare/v0.2.0...v0.3.0.beta1)
|
@@ -111,11 +140,11 @@
|
|
111
140
|
|
112
141
|
### Added
|
113
142
|
|
114
|
-
-
|
143
|
+
- Support objects as callbacks (@jodosha, @davydovanton)
|
115
144
|
|
116
145
|
### Fixed
|
117
146
|
|
118
|
-
-
|
147
|
+
- Ensure callbacks' context of execution (aka `self`) to be the command that is being executed (@jodosha, @davydovanton)
|
119
148
|
|
120
149
|
|
121
150
|
[Compare v0.2.0.beta1...v0.2.0.beta2](https://github.com/dry-rb/dry-cli/compare/v0.2.0.beta1...v0.2.0.beta2)
|
@@ -125,7 +154,7 @@
|
|
125
154
|
|
126
155
|
### Added
|
127
156
|
|
128
|
-
-
|
157
|
+
- Register `before`/`after` callbacks for commands (@davydovanton)
|
129
158
|
|
130
159
|
|
131
160
|
[Compare v0.1.1...v0.2.0.beta1](https://github.com/dry-rb/dry-cli/compare/v0.1.1...v0.2.0.beta1)
|
@@ -135,12 +164,12 @@
|
|
135
164
|
|
136
165
|
### Added
|
137
166
|
|
138
|
-
-
|
167
|
+
- Official support for Ruby: MRI 2.5 (@jodosha)
|
139
168
|
|
140
169
|
### Fixed
|
141
170
|
|
142
|
-
-
|
143
|
-
-
|
171
|
+
- Ensure default values for arguments to be sent to commands (@AlfonsoUceda)
|
172
|
+
- Ensure to fail when a missing required argument isn't provider, but an option is provided instead (@AlfonsoUceda)
|
144
173
|
|
145
174
|
|
146
175
|
[Compare v0.1.0...v0.1.1](https://github.com/dry-rb/dry-cli/compare/v0.1.0...v0.1.1)
|
@@ -168,7 +197,7 @@
|
|
168
197
|
|
169
198
|
### Added
|
170
199
|
|
171
|
-
-
|
200
|
+
- Allow default value for arguments (@AlfonsoUceda)
|
172
201
|
|
173
202
|
|
174
203
|
[Compare v0.1.0.beta1...v0.1.0.beta2](https://github.com/dry-rb/dry-cli/compare/v0.1.0.beta1...v0.1.0.beta2)
|
@@ -178,12 +207,12 @@
|
|
178
207
|
|
179
208
|
### Added
|
180
209
|
|
181
|
-
-
|
182
|
-
-
|
183
|
-
-
|
184
|
-
-
|
185
|
-
-
|
186
|
-
-
|
187
|
-
-
|
188
|
-
-
|
189
|
-
-
|
210
|
+
- Commands banner and usage (@jodosha, @AlfonsoUceda)
|
211
|
+
- Added support for subcommands (@AlfonsoUceda)
|
212
|
+
- Validations for arguments and options (@AlfonsoUceda)
|
213
|
+
- Commands arguments and options (@AlfonsoUceda)
|
214
|
+
- Commands description (@AlfonsoUceda)
|
215
|
+
- Commands aliases (@AlfonsoUceda, @oana-sipos)
|
216
|
+
- Exit on unknown command (@jodosha)
|
217
|
+
- Command lookup (@AlfonsoUceda, @oana-sipos)
|
218
|
+
- Trie based registry to register commands and allow third-parties to override/add commands (@jodosha, @timriley)
|
data/LICENSE
CHANGED
data/README.md
CHANGED
data/dry-cli.gemspec
CHANGED
@@ -25,13 +25,12 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.metadata['source_code_uri'] = 'https://github.com/dry-rb/dry-cli'
|
26
26
|
spec.metadata['bug_tracker_uri'] = 'https://github.com/dry-rb/dry-cli/issues'
|
27
27
|
|
28
|
-
spec.required_ruby_version = ">= 2.
|
28
|
+
spec.required_ruby_version = ">= 2.4.0"
|
29
29
|
|
30
30
|
# to update dependencies edit project.yml
|
31
|
-
spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
|
32
|
-
|
33
31
|
spec.add_development_dependency "bundler", ">= 1.6", "< 3"
|
34
32
|
spec.add_development_dependency "rake", "~> 13.0"
|
35
33
|
spec.add_development_dependency "rspec", "~> 3.7"
|
34
|
+
spec.add_development_dependency "rubocop", "~> 0.82"
|
36
35
|
spec.add_development_dependency "simplecov", "~> 0.17.1"
|
37
36
|
end
|
data/lib/dry/cli.rb
CHANGED
@@ -8,14 +8,14 @@ module Dry
|
|
8
8
|
#
|
9
9
|
# @since 0.1.0
|
10
10
|
class CLI
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
14
|
-
require
|
15
|
-
require
|
16
|
-
require
|
17
|
-
require
|
18
|
-
require
|
11
|
+
require "dry/cli/version"
|
12
|
+
require "dry/cli/errors"
|
13
|
+
require "dry/cli/command"
|
14
|
+
require "dry/cli/registry"
|
15
|
+
require "dry/cli/parser"
|
16
|
+
require "dry/cli/usage"
|
17
|
+
require "dry/cli/banner"
|
18
|
+
require "dry/cli/inflector"
|
19
19
|
|
20
20
|
# Check if command
|
21
21
|
#
|
@@ -62,9 +62,11 @@ module Dry
|
|
62
62
|
# @since 0.1.0
|
63
63
|
def call(arguments: ARGV, out: $stdout, err: $stderr)
|
64
64
|
@out, @err = out, err
|
65
|
-
|
66
|
-
|
67
|
-
|
65
|
+
kommand ? perform_command(arguments) : perform_registry(arguments)
|
66
|
+
rescue SignalException => e
|
67
|
+
signal_exception(e)
|
68
|
+
rescue Errno::EPIPE
|
69
|
+
# no op
|
68
70
|
end
|
69
71
|
|
70
72
|
private
|
@@ -106,16 +108,13 @@ module Dry
|
|
106
108
|
# @api private
|
107
109
|
def perform_registry(arguments)
|
108
110
|
result = registry.get(arguments)
|
111
|
+
return usage(result) unless result.found?
|
109
112
|
|
110
|
-
|
111
|
-
command, args = parse(result.command, result.arguments, result.names)
|
113
|
+
command, args = parse(result.command, result.arguments, result.names)
|
112
114
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
else
|
117
|
-
usage(result)
|
118
|
-
end
|
115
|
+
result.before_callbacks.run(command, args)
|
116
|
+
command.call(**args)
|
117
|
+
result.after_callbacks.run(command, args)
|
119
118
|
end
|
120
119
|
|
121
120
|
# Parse arguments for a command.
|
@@ -131,26 +130,37 @@ module Dry
|
|
131
130
|
# @since 0.6.0
|
132
131
|
# @api private
|
133
132
|
def parse(command, arguments, names)
|
134
|
-
|
133
|
+
prog_name = ProgramName.call(names)
|
135
134
|
|
136
|
-
|
137
|
-
out.puts Banner.call(command, names)
|
138
|
-
exit(0)
|
139
|
-
end
|
135
|
+
result = Parser.call(command, arguments, prog_name)
|
140
136
|
|
141
|
-
if result.
|
142
|
-
|
143
|
-
|
144
|
-
end
|
137
|
+
return help(command, prog_name) if result.help?
|
138
|
+
|
139
|
+
return error(result) if result.error?
|
145
140
|
|
146
|
-
[command
|
141
|
+
[build_command(command), result.arguments]
|
142
|
+
end
|
143
|
+
|
144
|
+
# @since 0.6.0
|
145
|
+
# @api private
|
146
|
+
def build_command(command)
|
147
|
+
command.is_a?(Class) ? command.new : command
|
148
|
+
end
|
149
|
+
|
150
|
+
# @since 0.6.0
|
151
|
+
# @api private
|
152
|
+
def help(command, prog_name)
|
153
|
+
out.puts Banner.call(command, prog_name)
|
154
|
+
exit(0) # Successful exit
|
155
|
+
end
|
156
|
+
|
157
|
+
# @since 0.6.0
|
158
|
+
# @api private
|
159
|
+
def error(result)
|
160
|
+
err.puts(result.error)
|
161
|
+
exit(1)
|
147
162
|
end
|
148
163
|
|
149
|
-
# Prints the command usage and exit.
|
150
|
-
#
|
151
|
-
# @param result [Dry::CLI::CommandRegistry::LookupResult]
|
152
|
-
# @param out [IO] sta output
|
153
|
-
#
|
154
164
|
# @since 0.1.0
|
155
165
|
# @api private
|
156
166
|
def usage(result)
|
@@ -158,6 +168,15 @@ module Dry
|
|
158
168
|
exit(1)
|
159
169
|
end
|
160
170
|
|
171
|
+
# Handles Exit codes for signals
|
172
|
+
# Fatal error signal "n". Say 130 = 128 + 2 (SIGINT) or 137 = 128 + 9 (SIGKILL)
|
173
|
+
#
|
174
|
+
# @since 0.7.0
|
175
|
+
# @api private
|
176
|
+
def signal_exception(exception)
|
177
|
+
exit(128 + exception.signo)
|
178
|
+
end
|
179
|
+
|
161
180
|
# Check if command
|
162
181
|
#
|
163
182
|
# @param command [Object] the command to check
|
data/lib/dry/cli/banner.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "dry/cli/program_name"
|
4
4
|
|
5
5
|
module Dry
|
6
6
|
class CLI
|
@@ -16,15 +16,15 @@ module Dry
|
|
16
16
|
#
|
17
17
|
# @since 0.1.0
|
18
18
|
# @api private
|
19
|
-
def self.call(command,
|
20
|
-
full_command_name = full_command_name(names)
|
19
|
+
def self.call(command, name)
|
21
20
|
[
|
22
|
-
command_name(
|
23
|
-
command_name_and_arguments(command,
|
21
|
+
command_name(name),
|
22
|
+
command_name_and_arguments(command, name),
|
24
23
|
command_description(command),
|
24
|
+
command_subcommands(command),
|
25
25
|
command_arguments(command),
|
26
26
|
command_options(command),
|
27
|
-
command_examples(command,
|
27
|
+
command_examples(command, name)
|
28
28
|
].compact.join("\n")
|
29
29
|
end
|
30
30
|
|
@@ -37,7 +37,11 @@ module Dry
|
|
37
37
|
# @since 0.1.0
|
38
38
|
# @api private
|
39
39
|
def self.command_name_and_arguments(command, name)
|
40
|
-
"\nUsage:\n #{name}#{arguments(command)}"
|
40
|
+
usage = "\nUsage:\n #{name}#{arguments(command)}"
|
41
|
+
|
42
|
+
return usage + " | #{name} SUBCOMMAND" if command.subcommands.any?
|
43
|
+
|
44
|
+
usage
|
41
45
|
end
|
42
46
|
|
43
47
|
# @since 0.1.0
|
@@ -45,7 +49,7 @@ module Dry
|
|
45
49
|
def self.command_examples(command, name)
|
46
50
|
return if command.examples.empty?
|
47
51
|
|
48
|
-
"\nExamples:\n#{command.examples.map { |example| " #{name} #{example}" }.join("\n")}"
|
52
|
+
"\nExamples:\n#{command.examples.map { |example| " #{name} #{example}" }.join("\n")}"
|
49
53
|
end
|
50
54
|
|
51
55
|
# @since 0.1.0
|
@@ -56,6 +60,12 @@ module Dry
|
|
56
60
|
"\nDescription:\n #{command.description}"
|
57
61
|
end
|
58
62
|
|
63
|
+
def self.command_subcommands(command)
|
64
|
+
return if command.subcommands.empty?
|
65
|
+
|
66
|
+
"\nSubcommands:\n#{build_subcommands_list(command.subcommands)}"
|
67
|
+
end
|
68
|
+
|
59
69
|
# @since 0.1.0
|
60
70
|
# @api private
|
61
71
|
def self.command_arguments(command)
|
@@ -70,30 +80,24 @@ module Dry
|
|
70
80
|
"\nOptions:\n#{extended_command_options(command)}"
|
71
81
|
end
|
72
82
|
|
73
|
-
# @since 0.1.0
|
74
|
-
# @api private
|
75
|
-
def self.full_command_name(names)
|
76
|
-
ProgramName.call(names)
|
77
|
-
end
|
78
|
-
|
79
83
|
# @since 0.1.0
|
80
84
|
# @api private
|
81
85
|
def self.arguments(command)
|
82
86
|
required_arguments = command.required_arguments
|
83
87
|
optional_arguments = command.optional_arguments
|
84
88
|
|
85
|
-
required = required_arguments.map { |arg| arg.name.upcase }.join(
|
86
|
-
optional = optional_arguments.map { |arg| "[#{arg.name.upcase}]" }.join(
|
89
|
+
required = required_arguments.map { |arg| arg.name.upcase }.join(" ") if required_arguments.any? # rubocop:disable Metrics/LineLength
|
90
|
+
optional = optional_arguments.map { |arg| "[#{arg.name.upcase}]" }.join(" ") if optional_arguments.any? # rubocop:disable Metrics/LineLength
|
87
91
|
result = [required, optional].compact
|
88
92
|
|
89
|
-
" #{result.join(
|
93
|
+
" #{result.join(" ")}" unless result.empty?
|
90
94
|
end
|
91
95
|
|
92
96
|
# @since 0.1.0
|
93
97
|
# @api private
|
94
98
|
def self.extended_command_arguments(command)
|
95
99
|
command.arguments.map do |argument|
|
96
|
-
" #{argument.name.to_s.upcase.ljust(
|
100
|
+
" #{argument.name.to_s.upcase.ljust(32)} # #{"REQUIRED " if argument.required?}#{argument.desc}" # rubocop:disable Metrics/LineLength
|
97
101
|
end.join("\n")
|
98
102
|
end
|
99
103
|
|
@@ -110,16 +114,22 @@ module Dry
|
|
110
114
|
else
|
111
115
|
"#{name}=VALUE"
|
112
116
|
end
|
113
|
-
name = "#{name}, #{option.alias_names.join(
|
117
|
+
name = "#{name}, #{option.alias_names.join(", ")}" if option.aliases.any?
|
114
118
|
name = " --#{name.ljust(30)}"
|
115
|
-
name = "#{name}
|
119
|
+
name = "#{name} # #{option.desc}"
|
116
120
|
name = "#{name}, default: #{option.default.inspect}" unless option.default.nil?
|
117
121
|
name
|
118
122
|
end
|
119
123
|
|
120
|
-
result << " --#{
|
124
|
+
result << " --#{"help, -h".ljust(30)} # Print this help"
|
121
125
|
result.join("\n")
|
122
126
|
end
|
127
|
+
|
128
|
+
def self.build_subcommands_list(subcommands)
|
129
|
+
subcommands.map do |subcommand_name, subcommand|
|
130
|
+
" #{subcommand_name.ljust(32)} # #{subcommand.command.description}"
|
131
|
+
end.join("\n")
|
132
|
+
end
|
123
133
|
end
|
124
134
|
end
|
125
135
|
end
|