dry-cli 1.2.0 → 1.4.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: 816b3ffdbf5a84ad4ce91ff6be0bba9424141a7b28b880accb087ba65b63e36d
4
- data.tar.gz: 6ca3a54ff35dcb634acf68ff6472ddc8737cc15f99d6f7f860ac89e491759cd4
3
+ metadata.gz: 92920db180b09c97eece82f48b921162625b30cd41e5ac5c1f86fb623012a939
4
+ data.tar.gz: 3dc7e165cc9164546106cd52311f5db44b7e620a0acb2eaceb1a572bbfde1ee8
5
5
  SHA512:
6
- metadata.gz: e1b289e4571b3b658ff402f1c8dd2fa8c7746fc3a17293f2a3316961622adc1570c76b82dfbcf4c74c6510f1994952928d64eb56e99284acfae797f6adeb8037
7
- data.tar.gz: 4739d57ca298e1c85afcd5d0c499a56ca04db8e802d4c84be905a674e884599d4b2dbedca66927d9ed9a0467a5b1468c063bd57b25109c6a7e1c69068b113b59
6
+ metadata.gz: '092186ca495d29592e2f24b1cbbecf981f1b3fb50065d61d0250055dce0fb2f419674daeb99d5771539721583417715b639f2c896c1135fa56fa7b420430fcdb'
7
+ data.tar.gz: 77e603998b0a56a3d19ee97c939ad00333b7262568c29d97463b39c3f442b60e5f85d3484fc7dd713e4fd96076a24d55ef8f37ffde0cfad164dd0b1fafaade6d
data/CHANGELOG.md CHANGED
@@ -1,37 +1,102 @@
1
- <!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
1
+ # Changelog
2
2
 
3
- ## 1.2.0 2024-10-15
3
+ All notable changes to this project will be documented in this file.
4
4
 
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Break Versioning](https://www.taoensso.com/break-versioning).
7
+
8
+ ## [Unreleased]
5
9
 
6
10
  ### Added
7
11
 
8
- - Added `:hidden` option to register commands that should not be shown in the help output. (@benoittgt in #137)
9
- - Provide suggestions when there is a typo in a command name. (@benoittgt in #138)
12
+ ### Changed
13
+
14
+ ### Deprecated
10
15
 
16
+ ### Removed
11
17
 
12
- [Compare v1.1.0...v1.2.0](https://github.com/dry-rb/dry-cli/compare/v1.1.0...v1.2.0)
18
+ ### Fixed
19
+
20
+ ### Security
13
21
 
14
- ## 1.1.0 2024-07-14
22
+ [Unreleased]: https://github.com/dry-rb/dry-cli/compare/v1.4.0...main
15
23
 
24
+ ## [1.4.0] - 2026-01-09
16
25
 
17
26
  ### Added
18
27
 
19
- - Added `:flag` option type. This acts like a `:boolean` that can only be set to true, so has no `--no-` prefix to disable it. (@Billiam in #117)
28
+ - Provide the CLI’s `out` and `err` streams to command instances (unless `@out` and `@err` ivars already exist in the command). (@aaronmallen in #150)
29
+
30
+ ### Changed
31
+
32
+ - Require Ruby 3.2 or later. (@timriley)
33
+
34
+ ### Fixed
35
+
36
+ - Pass a commands keyword arguments to any related callbacks. (@gustavothecoder in #136)
37
+ - Avoid duplicated option names in `--help` output when a subclass re-defines an option. (@gustavothecoder in #143)
38
+ - Properly raise an error when an invalid value is passed to an option (previously this was working for arguments only, not options). (@gustavothecoder in #142)
39
+
40
+ [1.4.0]: https://github.com/dry-rb/dry-cli/compare/v1.3.0...v1.4.0
41
+
42
+ ## [1.3.0] - 2025-07-29
43
+
44
+ ### Added
45
+
46
+ - Support unlimited nesting when registering commands via `register` with blocks. (@aaronmallen in #149)
20
47
 
48
+ You could previously do this only with fully qualified registrations:
21
49
 
22
- [Compare v1.0.0...v1.1.0](https://github.com/dry-rb/dry-cli/compare/v1.0.0...v1.1.0)
50
+ ```ruby
51
+ Commands.register "nested one", MyFirstNestedCommand
52
+ Commands.register "nested one two", MySecondNestedCommand
53
+ Commands.register "nested one two three", MyThirdNestedCommand
54
+ ```
23
55
 
24
- ## 1.0.0 2022-11-05
56
+ Now you can do the same via blocks:
25
57
 
58
+ ```ruby
59
+ Commands.register "nested" do
60
+ register "one", MyFirstNestedCommand do
61
+ register "two", MySecondNestedCommand do
62
+ register "three", MyThirdNestedCommand
63
+ end
64
+ end
65
+ end
66
+ ```
26
67
 
27
68
  ### Changed
28
69
 
29
- - Version bumped to 1.0.0 (@solnic)
70
+ - Set minimum Ruby version to 3.1. (@timriley)
71
+
72
+ [1.3.0]: https://github.com/dry-rb/dry-cli/compare/v1.2.0...v1.3.0
30
73
 
31
- [Compare v0.7.0...v1.0.0](https://github.com/dry-rb/dry-cli/compare/v0.7.0...v1.0.0)
74
+ ## [1.2.0] - 2024-10-15
32
75
 
33
- ## 0.7.0 2020-05-08
76
+ ### Added
34
77
 
78
+ - Added `:hidden` option to register commands that should not be shown in the help output. (@benoittgt in #137)
79
+ - Provide suggestions when there is a typo in a command name. (@benoittgt in #138)
80
+
81
+ [1.2.0]: https://github.com/dry-rb/dry-cli/compare/v1.1.0...v1.2.0
82
+
83
+ ## [1.1.0] - 2024-07-14
84
+
85
+ ### Added
86
+
87
+ - Added `:flag` option type. This acts like a `:boolean` that can only be set to true, so has no `--no-` prefix to disable it. (@Billiam in #117)
88
+
89
+ [1.1.0]: https://github.com/dry-rb/dry-cli/compare/v1.0.0...v1.1.0
90
+
91
+ ## [1.0.0] - 2022-11-05
92
+
93
+ ### Changed
94
+
95
+ - Version bumped to 1.0.0 (@solnic)
96
+
97
+ [1.0.0]: https://github.com/dry-rb/dry-cli/compare/v0.7.0...v1.0.0
98
+
99
+ ## [0.7.0] - 2020-05-08
35
100
 
36
101
  ### Added
37
102
 
@@ -55,10 +120,9 @@
55
120
  - Remove concurrent-ruby as runtime dependency (@jodosha)
56
121
  - [Internal] Banner and Parses refactoring (@IvanShamatov)
57
122
 
58
- [Compare v0.6.0...v0.7.0](https://github.com/dry-rb/dry-cli/compare/v0.6.0...v0.7.0)
59
-
60
- ## 0.6.0 2020-03-06
123
+ [0.7.0]: https://github.com/dry-rb/dry-cli/compare/v0.6.0...v0.7.0
61
124
 
125
+ ## [0.6.0] - 2020-03-06
62
126
 
63
127
  ### Added
64
128
 
@@ -72,11 +136,9 @@
72
136
  - [John Ledbetter & Luca Guidi] Fix ruby 2.7 warnings (@jodosha)
73
137
  - Fix banner, when option is a type of Array (@IvanShamatov)
74
138
 
139
+ [0.6.0]: https://github.com/dry-rb/dry-cli/compare/v0.5.1...v0.6.0
75
140
 
76
- [Compare v0.5.1...v0.6.0](https://github.com/dry-rb/dry-cli/compare/v0.5.1...v0.6.0)
77
-
78
- ## 0.5.1 2020-01-23
79
-
141
+ ## [0.5.1] - 2020-01-23
80
142
 
81
143
  ### Added
82
144
 
@@ -90,48 +152,38 @@
90
152
 
91
153
  - Added missing 'set' require (@solnic)
92
154
 
155
+ [0.5.1]: https://github.com/dry-rb/dry-cli/compare/v0.5.0...v0.5.1
93
156
 
94
- [Compare v0.5.0...v0.5.1](https://github.com/dry-rb/dry-cli/compare/v0.5.0...v0.5.1)
95
-
96
- ## 0.5.0 2019-12-21
97
-
157
+ ## [0.5.0] - 2019-12-21
98
158
 
99
159
  ### Added
100
160
 
101
161
  - [Internal] removed runtime and development dependency against `hanami-utils` (@jodosha, @IvanShamatov, @solnic)
102
162
 
163
+ [0.5.0]: https://github.com/dry-rb/dry-cli/compare/v0.4.0...v0.5.0
103
164
 
104
- [Compare v0.4.0...v0.5.0](https://github.com/dry-rb/dry-cli/compare/v0.4.0...v0.5.0)
105
-
106
- ## 0.4.0 2019-12-10
107
-
165
+ ## [0.4.0] - 2019-12-10
108
166
 
109
167
  ### Added
110
168
 
111
169
  - `hanami-cli` => `dry-cli` (@jodosha, @IvanShamatov, @solnic)
112
170
 
171
+ [0.4.0]: https://github.com/dry-rb/dry-cli/compare/v0.3.1...v0.4.0
113
172
 
114
- [Compare v0.3.1...v0.4.0](https://github.com/dry-rb/dry-cli/compare/v0.3.1...v0.4.0)
115
-
116
- ## 0.3.1 2019-01-18
117
-
173
+ ## [0.3.1] - 2019-01-18
118
174
 
119
175
  ### Added
120
176
 
121
177
  - Official support for Ruby: MRI 2.6 (@jodosha)
122
178
  - Support `bundler` 2.0+ (@jodosha)
123
179
 
180
+ [0.3.1]: https://github.com/dry-rb/dry-cli/compare/v0.3.0...v0.3.1
124
181
 
125
- [Compare v0.3.0...v0.3.1](https://github.com/dry-rb/dry-cli/compare/v0.3.0...v0.3.1)
126
-
127
- ## 0.3.0 2018-10-24
128
-
129
-
130
-
131
- [Compare v0.3.0.beta1...v0.3.0](https://github.com/dry-rb/dry-cli/compare/v0.3.0.beta1...v0.3.0)
182
+ ## [0.3.0] - 2018-10-24
132
183
 
133
- ## 0.3.0.beta1 2018-08-08
184
+ [0.3.0]: https://github.com/dry-rb/dry-cli/compare/v0.3.0.beta1...v0.3.0
134
185
 
186
+ ## [0.3.0.beta1] - 2018-08-08
135
187
 
136
188
  ### Added
137
189
 
@@ -144,29 +196,21 @@
144
196
 
145
197
  - Print informative message when unknown or wrong option is passed (`"test" was called with arguments "--framework=unknown"`) (@davydovanton)
146
198
 
199
+ [0.3.0.beta1]: https://github.com/dry-rb/dry-cli/compare/v0.2.0...v0.3.0.beta1
147
200
 
148
- [Compare v0.2.0...v0.3.0.beta1](https://github.com/dry-rb/dry-cli/compare/v0.2.0...v0.3.0.beta1)
149
-
150
- ## 0.2.0 2018-04-11
151
-
152
-
153
-
154
- [Compare v0.2.0.rc2...v0.2.0](https://github.com/dry-rb/dry-cli/compare/v0.2.0.rc2...v0.2.0)
201
+ ## [0.2.0] - 2018-04-11
155
202
 
156
- ## 0.2.0.rc2 2018-04-06
203
+ [0.2.0]: https://github.com/dry-rb/dry-cli/compare/v0.2.0.rc2...v0.2.0
157
204
 
205
+ ## [0.2.0.rc2] - 2018-04-06
158
206
 
207
+ [0.2.0.rc2]: https://github.com/dry-rb/dry-cli/compare/v0.2.0.rc1...v0.2.0.rc2
159
208
 
160
- [Compare v0.2.0.rc1...v0.2.0.rc2](https://github.com/dry-rb/dry-cli/compare/v0.2.0.rc1...v0.2.0.rc2)
209
+ ## [0.2.0.rc1] - 2018-03-30
161
210
 
162
- ## 0.2.0.rc1 2018-03-30
163
-
164
-
165
-
166
- [Compare v0.2.0.beta2...v0.2.0.rc1](https://github.com/dry-rb/dry-cli/compare/v0.2.0.beta2...v0.2.0.rc1)
167
-
168
- ## 0.2.0.beta2 2018-03-23
211
+ [0.2.0.rc1]: https://github.com/dry-rb/dry-cli/compare/v0.2.0.beta2...v0.2.0.rc1
169
212
 
213
+ ## [0.2.0.beta2] - 2018-03-23
170
214
 
171
215
  ### Added
172
216
 
@@ -176,21 +220,17 @@
176
220
 
177
221
  - Ensure callbacks' context of execution (aka `self`) to be the command that is being executed (@jodosha, @davydovanton)
178
222
 
223
+ [0.2.0.beta2]: https://github.com/dry-rb/dry-cli/compare/v0.2.0.beta1...v0.2.0.beta2
179
224
 
180
- [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)
181
-
182
- ## 0.2.0.beta1 2018-02-28
183
-
225
+ ## [0.2.0.beta1] - 2018-02-28
184
226
 
185
227
  ### Added
186
228
 
187
229
  - Register `before`/`after` callbacks for commands (@davydovanton)
188
230
 
231
+ [0.2.0.beta1]: https://github.com/dry-rb/dry-cli/compare/v0.1.1...v0.2.0.beta1
189
232
 
190
- [Compare v0.1.1...v0.2.0.beta1](https://github.com/dry-rb/dry-cli/compare/v0.1.1...v0.2.0.beta1)
191
-
192
- ## 0.1.1 2018-02-27
193
-
233
+ ## [0.1.1] - 2018-02-27
194
234
 
195
235
  ### Added
196
236
 
@@ -201,39 +241,29 @@
201
241
  - Ensure default values for arguments to be sent to commands (@AlfonsoUceda)
202
242
  - Ensure to fail when a missing required argument isn't provider, but an option is provided instead (@AlfonsoUceda)
203
243
 
244
+ [0.1.1]: https://github.com/dry-rb/dry-cli/compare/v0.1.0...v0.1.1
204
245
 
205
- [Compare v0.1.0...v0.1.1](https://github.com/dry-rb/dry-cli/compare/v0.1.0...v0.1.1)
206
-
207
- ## 0.1.0 2017-10-25
246
+ ## [0.1.0] - 2017-10-25
208
247
 
248
+ [0.1.0]: https://github.com/dry-rb/dry-cli/compare/v0.1.0.rc1...v0.1.0
209
249
 
250
+ ## [0.1.0.rc1] - 2017-10-16
210
251
 
211
- [Compare v0.1.0.rc1...v0.1.0](https://github.com/dry-rb/dry-cli/compare/v0.1.0.rc1...v0.1.0)
252
+ [0.1.0.rc1]: https://github.com/dry-rb/dry-cli/compare/v0.1.0.beta3...v0.1.0.rc1
212
253
 
213
- ## 0.1.0.rc1 2017-10-16
254
+ ## [0.1.0.beta3] - 2017-10-04
214
255
 
256
+ [0.1.0.beta3]: https://github.com/dry-rb/dry-cli/compare/v0.1.0.beta2...v0.1.0.beta3
215
257
 
216
-
217
- [Compare v0.1.0.beta3...v0.1.0.rc1](https://github.com/dry-rb/dry-cli/compare/v0.1.0.beta3...v0.1.0.rc1)
218
-
219
- ## 0.1.0.beta3 2017-10-04
220
-
221
-
222
-
223
- [Compare v0.1.0.beta2...v0.1.0.beta3](https://github.com/dry-rb/dry-cli/compare/v0.1.0.beta2...v0.1.0.beta3)
224
-
225
- ## 0.1.0.beta2 2017-10-03
226
-
258
+ ## [0.1.0.beta2] - 2017-10-03
227
259
 
228
260
  ### Added
229
261
 
230
262
  - Allow default value for arguments (@AlfonsoUceda)
231
263
 
264
+ [0.1.0.beta2]: https://github.com/dry-rb/dry-cli/compare/v0.1.0.beta1...v0.1.0.beta2
232
265
 
233
- [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)
234
-
235
- ## 0.1.0.beta1 2017-08-11
236
-
266
+ ## [0.1.0.beta1] - 2017-08-11
237
267
 
238
268
  ### Added
239
269
 
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015-2023 dry-rb team
3
+ Copyright (c) 2015-2026 Hanakai team
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
data/README.md CHANGED
@@ -1,22 +1,17 @@
1
- <!--- this file is synced from dry-rb/template-gem project -->
2
- [gem]: https://rubygems.org/gems/dry-cli
1
+ <!--- This file is synced from hanakai-rb/repo-sync -->
2
+
3
+ [rubygem]: https://rubygems.org/gems/dry-cli
3
4
  [actions]: https://github.com/dry-rb/dry-cli/actions
4
5
 
5
- # dry-cli [![Gem Version](https://badge.fury.io/rb/dry-cli.svg)][gem] [![CI Status](https://github.com/dry-rb/dry-cli/workflows/ci/badge.svg)][actions]
6
+ # dry-cli [![Gem Version](https://badge.fury.io/rb/dry-cli.svg)][rubygem] [![CI Status](https://github.com/dry-rb/dry-cli/workflows/CI/badge.svg)][actions]
6
7
 
7
8
  ## Links
8
9
 
9
- * [User documentation](https://dry-rb.org/gems/dry-cli)
10
- * [API documentation](http://rubydoc.info/gems/dry-cli)
11
- * [Forum](https://discourse.dry-rb.org)
12
-
13
- ## Supported Ruby versions
14
-
15
- This library officially supports the following Ruby versions:
16
-
17
- * MRI `>= 2.4.0`
18
- * jruby `>= 9.4` (not tested on CI)
10
+ - [User documentation](https://dry-rb.org/gems/dry-cli)
11
+ - [API documentation](http://rubydoc.info/gems/dry-cli)
12
+ - [Forum](https://discourse.dry-rb.org)
19
13
 
20
14
  ## License
21
15
 
22
16
  See `LICENSE` file.
17
+
data/dry-cli.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # this file is synced from dry-rb/template-gem project
3
+ # This file is synced from hanakai-rb/repo-sync. To update it, edit repo-sync.yml.
4
4
 
5
5
  lib = File.expand_path("lib", __dir__)
6
6
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
@@ -8,8 +8,8 @@ require "dry/cli/version"
8
8
 
9
9
  Gem::Specification.new do |spec|
10
10
  spec.name = "dry-cli"
11
- spec.authors = ["Luca Guidi"]
12
- spec.email = ["me@lucaguidi.com"]
11
+ spec.authors = ["Hanakai team"]
12
+ spec.email = ["info@hanakai.org"]
13
13
  spec.license = "MIT"
14
14
  spec.version = Dry::CLI::VERSION.dup
15
15
 
@@ -21,18 +21,18 @@ Gem::Specification.new do |spec|
21
21
  spec.executables = []
22
22
  spec.require_paths = ["lib"]
23
23
 
24
+ spec.extra_rdoc_files = ["README.md", "CHANGELOG.md", "LICENSE"]
25
+
24
26
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
25
27
  spec.metadata["changelog_uri"] = "https://github.com/dry-rb/dry-cli/blob/main/CHANGELOG.md"
26
28
  spec.metadata["source_code_uri"] = "https://github.com/dry-rb/dry-cli"
27
29
  spec.metadata["bug_tracker_uri"] = "https://github.com/dry-rb/dry-cli/issues"
30
+ spec.metadata["funding_uri"] = "https://github.com/sponsors/hanami"
28
31
 
29
- spec.required_ruby_version = ">= 2.4.0"
30
-
31
- # to update dependencies edit project.yml
32
+ spec.required_ruby_version = ">= 3.2"
32
33
 
33
- spec.add_development_dependency "bundler", ">= 1.6", "< 3"
34
- spec.add_development_dependency "rake", "~> 13.0"
35
- spec.add_development_dependency "rspec", "~> 3.7"
36
- spec.add_development_dependency "rubocop", "~> 0.82"
37
- spec.add_development_dependency "simplecov", "~> 0.17.1"
34
+ spec.add_development_dependency "bundler"
35
+ spec.add_development_dependency "rake"
36
+ spec.add_development_dependency "rspec"
38
37
  end
38
+
@@ -86,8 +86,8 @@ module Dry
86
86
  required_arguments = command.required_arguments
87
87
  optional_arguments = command.optional_arguments
88
88
 
89
- required = required_arguments.map { |arg| arg.name.upcase }.join(" ") if required_arguments.any? # rubocop:disable Layout/LineLength
90
- optional = optional_arguments.map { |arg| "[#{arg.name.upcase}]" }.join(" ") if optional_arguments.any? # rubocop:disable Layout/LineLength
89
+ required = required_arguments.map { |arg| arg.name.upcase }.join(" ") if required_arguments.any?
90
+ optional = optional_arguments.map { |arg| "[#{arg.name.upcase}]" }.join(" ") if optional_arguments.any?
91
91
  result = [required, optional].compact
92
92
 
93
93
  " #{result.join(" ")}" unless result.empty?
@@ -97,7 +97,7 @@ module Dry
97
97
  # @api private
98
98
  def self.extended_command_arguments(command)
99
99
  command.arguments.map do |argument|
100
- " #{argument.name.to_s.upcase.ljust(32)} # #{"REQUIRED " if argument.required?}#{argument.desc}" # rubocop:disable Layout/LineLength
100
+ " #{argument.name.to_s.upcase.ljust(32)} # #{"REQUIRED " if argument.required?}#{argument.desc}"
101
101
  end.join("\n")
102
102
  end
103
103
 
@@ -195,7 +195,12 @@ module Dry
195
195
  # # Options:
196
196
  # # --help, -h # Print this help
197
197
  def self.argument(name, options = {})
198
- @arguments << Argument.new(name, options)
198
+ new_arg = Argument.new(name, options)
199
+
200
+ duplicate_index = @arguments.find_index { _1.name == new_arg.name }
201
+ @arguments.delete_at(duplicate_index) unless duplicate_index.nil?
202
+
203
+ @arguments << new_arg
199
204
  end
200
205
 
201
206
  # Command line option (aka optional argument)
@@ -309,7 +314,12 @@ module Dry
309
314
  # # Options:
310
315
  # # --port=VALUE, -p VALUE
311
316
  def self.option(name, options = {})
312
- @options << Option.new(name, options)
317
+ new_op = Option.new(name, options)
318
+
319
+ duplicate_index = @options.find_index { _1.name == new_op.name }
320
+ @options.delete_at(duplicate_index) unless duplicate_index.nil?
321
+
322
+ @options << new_op
313
323
  end
314
324
 
315
325
  # @since 0.1.0
@@ -379,6 +389,39 @@ module Dry
379
389
  optional_arguments
380
390
  subcommands
381
391
  ] => "self.class"
392
+
393
+ protected
394
+
395
+ # The error output used to print error messaging
396
+ #
397
+ # @example
398
+ # class MyCommand
399
+ # def call
400
+ # out.puts "Hello World!"
401
+ # exit(0)
402
+ # rescue StandardError => e
403
+ # err.puts "Uh oh: #{e.message}"
404
+ # exit(1)
405
+ # end
406
+ # end
407
+ #
408
+ # @since unreleased
409
+ # @return [IO]
410
+ attr_reader :err
411
+
412
+ # The standard output object used to print messaging
413
+ #
414
+ # @example
415
+ # class MyCommand
416
+ # def call
417
+ # out.puts "Hello World!"
418
+ # exit(0)
419
+ # end
420
+ # end
421
+ #
422
+ # @since unreleased
423
+ # @return [IO]
424
+ attr_reader :out
382
425
  end
383
426
  end
384
427
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "set"
4
-
5
3
  module Dry
6
4
  class CLI
7
5
  # Command registry
@@ -255,9 +253,9 @@ module Dry
255
253
 
256
254
  # @since 0.4.0
257
255
  # @api private
258
- def run(context, *args)
256
+ def run(context, **args)
259
257
  chain.each do |callback|
260
- context.instance_exec(*args, &callback)
258
+ context.instance_exec(**args, &callback)
261
259
  end
262
260
  end
263
261
  end
@@ -9,6 +9,10 @@ module Dry
9
9
  class Error < StandardError
10
10
  end
11
11
 
12
+ # @since 1.4.0
13
+ class ValueError < Error
14
+ end
15
+
12
16
  # @since 0.2.1
13
17
  class UnknownCommandError < Error
14
18
  # @since 0.2.1
@@ -13,7 +13,7 @@ module Dry
13
13
  # methods below
14
14
  #
15
15
  # DSL consists of 5 methods:
16
- # `desc`, `example`, `argument`, `option` 
16
+ # `desc`, `example`, `argument`, `option`
17
17
  # — are similar to methods from Command class
18
18
  #
19
19
  # `run` accepts a block to execute
@@ -121,6 +121,18 @@ module Dry
121
121
  .map { |name| name.size == 1 ? "-#{name}" : "--#{name}" }
122
122
  .map { |name| boolean? || flag? ? name : "#{name} VALUE" }
123
123
  end
124
+
125
+ # @api private
126
+ def valid_value?(value)
127
+ available_values = values
128
+ return true if available_values.nil?
129
+
130
+ if array?
131
+ (value - available_values).empty?
132
+ else
133
+ available_values.map(&:to_s).include?(value.to_s)
134
+ end
135
+ end
124
136
  end
125
137
 
126
138
  # Command line argument
@@ -31,25 +31,25 @@ module Dry
31
31
 
32
32
  parsed_options = command.default_params.merge(parsed_options)
33
33
  parse_required_params(command, arguments, prog_name, parsed_options)
34
- rescue ::OptionParser::ParseError
35
- Result.failure("ERROR: \"#{prog_name}\" was called with arguments \"#{original_arguments.join(" ")}\"") # rubocop:disable Layout/LineLength
34
+ rescue ::OptionParser::ParseError, ValueError
35
+ Result.failure("ERROR: \"#{prog_name}\" was called with arguments \"#{original_arguments.join(" ")}\"")
36
36
  end
37
37
 
38
38
  # @since 0.1.0
39
39
  # @api private
40
40
  #
41
- # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
41
+ # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity, Layout/LineLength
42
42
  def self.parse_required_params(command, arguments, prog_name, parsed_options)
43
- parsed_params = match_arguments(command.arguments, arguments)
44
- parsed_required_params = match_arguments(command.required_arguments, arguments)
45
- all_required_params_satisfied = command.required_arguments.all? { |param| !parsed_required_params[param.name].nil? } # rubocop:disable Layout/LineLength
43
+ parsed_params = match_arguments(command.arguments, arguments, parsed_options)
44
+ parsed_required_params = match_arguments(command.required_arguments, arguments, parsed_options)
45
+ all_required_params_satisfied = command.required_arguments.all? { |param| !parsed_required_params[param.name].nil? }
46
46
 
47
47
  unused_arguments = arguments.drop(command.required_arguments.length)
48
48
 
49
49
  unless all_required_params_satisfied
50
50
  parsed_required_params_values = parsed_required_params.values.compact
51
51
 
52
- usage = "\nUsage: \"#{prog_name} #{command.required_arguments.map(&:description_name).join(" ")}" # rubocop:disable Layout/LineLength
52
+ usage = "\nUsage: \"#{prog_name} #{command.required_arguments.map(&:description_name).join(" ")}"
53
53
 
54
54
  usage += " | #{prog_name} SUBCOMMAND" if command.subcommands.any?
55
55
 
@@ -58,7 +58,7 @@ module Dry
58
58
  if parsed_required_params_values.empty?
59
59
  return Result.failure("ERROR: \"#{prog_name}\" was called with no arguments#{usage}")
60
60
  else
61
- return Result.failure("ERROR: \"#{prog_name}\" was called with arguments #{parsed_required_params_values}#{usage}") # rubocop:disable Layout/LineLength
61
+ return Result.failure("ERROR: \"#{prog_name}\" was called with arguments #{parsed_required_params_values}#{usage}")
62
62
  end
63
63
  end
64
64
 
@@ -67,17 +67,24 @@ module Dry
67
67
  parsed_options = parsed_options.merge(args: unused_arguments) if unused_arguments.any?
68
68
  Result.success(parsed_options)
69
69
  end
70
- # rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity
70
+ # rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity, Layout/LineLength
71
71
 
72
- def self.match_arguments(command_arguments, arguments)
72
+ def self.match_arguments(command_arguments, arguments, default_values)
73
73
  result = {}
74
74
 
75
+ arg = nil
75
76
  command_arguments.each_with_index do |cmd_arg, index|
76
77
  if cmd_arg.array?
77
- result[cmd_arg.name] = arguments[index..]
78
+ arg = arguments[index..] || default_values[cmd_arg.name]
79
+ raise ValueError unless cmd_arg.valid_value?(arg)
80
+
81
+ result[cmd_arg.name] = arg
78
82
  break
79
83
  else
80
- result[cmd_arg.name] = arguments.at(index)
84
+ arg = arguments.at(index) || default_values[cmd_arg.name]
85
+ raise ValueError unless cmd_arg.valid_value?(arg)
86
+
87
+ result[cmd_arg.name] = arg
81
88
  end
82
89
  end
83
90
 
@@ -318,9 +318,18 @@ module Dry
318
318
  # @since 0.1.0
319
319
  #
320
320
  # @see Dry::CLI::Registry#register
321
- def register(name, command, aliases: [], hidden: false)
321
+ def register(name, command = nil, aliases: [], hidden: false, &block)
322
322
  command_name = "#{prefix} #{name}"
323
323
  registry.set(command_name, command, aliases, hidden)
324
+
325
+ if block_given?
326
+ prefix = self.class.new(registry, command_name, aliases, hidden)
327
+ if block.arity.zero?
328
+ prefix.instance_eval(&block)
329
+ else
330
+ yield(prefix)
331
+ end
332
+ end
324
333
  end
325
334
 
326
335
  private
data/lib/dry/cli/usage.rb CHANGED
@@ -57,8 +57,8 @@ module Dry
57
57
  required_arguments = command.required_arguments
58
58
  optional_arguments = command.optional_arguments
59
59
 
60
- required = required_arguments.map { |arg| arg.name.upcase }.join(" ") if required_arguments.any? # rubocop:disable Layout/LineLength
61
- optional = optional_arguments.map { |arg| "[#{arg.name.upcase}]" }.join(" ") if optional_arguments.any? # rubocop:disable Layout/LineLength
60
+ required = required_arguments.map { |arg| arg.name.upcase }.join(" ") if required_arguments.any?
61
+ optional = optional_arguments.map { |arg| "[#{arg.name.upcase}]" }.join(" ") if optional_arguments.any?
62
62
  result = [required, optional].compact
63
63
 
64
64
  " #{result.join(" ")}" unless result.empty?
@@ -3,6 +3,6 @@
3
3
  module Dry
4
4
  class CLI
5
5
  # @since 0.1.0
6
- VERSION = "1.2.0"
6
+ VERSION = "1.4.0"
7
7
  end
8
8
  end
data/lib/dry/cli.rb CHANGED
@@ -64,8 +64,8 @@ module Dry
64
64
  def call(arguments: ARGV, out: $stdout, err: $stderr)
65
65
  @out, @err = out, err
66
66
  kommand ? perform_command(arguments) : perform_registry(arguments)
67
- rescue SignalException => e
68
- signal_exception(e)
67
+ rescue SignalException => exception
68
+ signal_exception(exception)
69
69
  rescue Errno::EPIPE
70
70
  # no op
71
71
  end
@@ -97,6 +97,10 @@ module Dry
97
97
  # @api private
98
98
  def perform_command(arguments)
99
99
  command, args = parse(kommand, arguments, [])
100
+
101
+ command.instance_variable_set(:@err, err) unless command.instance_variable_defined?(:@err)
102
+ command.instance_variable_set(:@out, out) unless command.instance_variable_defined?(:@out)
103
+
100
104
  command.call(**args)
101
105
  end
102
106
 
@@ -113,9 +117,12 @@ module Dry
113
117
 
114
118
  command, args = parse(result.command, result.arguments, result.names)
115
119
 
116
- result.before_callbacks.run(command, args)
120
+ command.instance_variable_set(:@err, err) unless command.instance_variable_defined?(:@err)
121
+ command.instance_variable_set(:@out, out) unless command.instance_variable_defined?(:@out)
122
+
123
+ result.before_callbacks.run(command, **args)
117
124
  command.call(**args)
118
- result.after_callbacks.run(command, args)
125
+ result.after_callbacks.run(command, **args)
119
126
  end
120
127
 
121
128
  # Parse arguments for a command.
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dry-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
- - Luca Guidi
8
- autorequire:
7
+ - Hanakai team
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-10-15 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: bundler
@@ -16,82 +15,51 @@ dependencies:
16
15
  requirements:
17
16
  - - ">="
18
17
  - !ruby/object:Gem::Version
19
- version: '1.6'
20
- - - "<"
21
- - !ruby/object:Gem::Version
22
- version: '3'
18
+ version: '0'
23
19
  type: :development
24
20
  prerelease: false
25
21
  version_requirements: !ruby/object:Gem::Requirement
26
22
  requirements:
27
23
  - - ">="
28
24
  - !ruby/object:Gem::Version
29
- version: '1.6'
30
- - - "<"
31
- - !ruby/object:Gem::Version
32
- version: '3'
25
+ version: '0'
33
26
  - !ruby/object:Gem::Dependency
34
27
  name: rake
35
28
  requirement: !ruby/object:Gem::Requirement
36
29
  requirements:
37
- - - "~>"
30
+ - - ">="
38
31
  - !ruby/object:Gem::Version
39
- version: '13.0'
32
+ version: '0'
40
33
  type: :development
41
34
  prerelease: false
42
35
  version_requirements: !ruby/object:Gem::Requirement
43
36
  requirements:
44
- - - "~>"
37
+ - - ">="
45
38
  - !ruby/object:Gem::Version
46
- version: '13.0'
39
+ version: '0'
47
40
  - !ruby/object:Gem::Dependency
48
41
  name: rspec
49
42
  requirement: !ruby/object:Gem::Requirement
50
43
  requirements:
51
- - - "~>"
52
- - !ruby/object:Gem::Version
53
- version: '3.7'
54
- type: :development
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- requirements:
58
- - - "~>"
59
- - !ruby/object:Gem::Version
60
- version: '3.7'
61
- - !ruby/object:Gem::Dependency
62
- name: rubocop
63
- requirement: !ruby/object:Gem::Requirement
64
- requirements:
65
- - - "~>"
66
- - !ruby/object:Gem::Version
67
- version: '0.82'
68
- type: :development
69
- prerelease: false
70
- version_requirements: !ruby/object:Gem::Requirement
71
- requirements:
72
- - - "~>"
73
- - !ruby/object:Gem::Version
74
- version: '0.82'
75
- - !ruby/object:Gem::Dependency
76
- name: simplecov
77
- requirement: !ruby/object:Gem::Requirement
78
- requirements:
79
- - - "~>"
44
+ - - ">="
80
45
  - !ruby/object:Gem::Version
81
- version: 0.17.1
46
+ version: '0'
82
47
  type: :development
83
48
  prerelease: false
84
49
  version_requirements: !ruby/object:Gem::Requirement
85
50
  requirements:
86
- - - "~>"
51
+ - - ">="
87
52
  - !ruby/object:Gem::Version
88
- version: 0.17.1
53
+ version: '0'
89
54
  description: Common framework to build command line interfaces with Ruby
90
55
  email:
91
- - me@lucaguidi.com
56
+ - info@hanakai.org
92
57
  executables: []
93
58
  extensions: []
94
- extra_rdoc_files: []
59
+ extra_rdoc_files:
60
+ - CHANGELOG.md
61
+ - LICENSE
62
+ - README.md
95
63
  files:
96
64
  - CHANGELOG.md
97
65
  - LICENSE
@@ -119,7 +87,7 @@ metadata:
119
87
  changelog_uri: https://github.com/dry-rb/dry-cli/blob/main/CHANGELOG.md
120
88
  source_code_uri: https://github.com/dry-rb/dry-cli
121
89
  bug_tracker_uri: https://github.com/dry-rb/dry-cli/issues
122
- post_install_message:
90
+ funding_uri: https://github.com/sponsors/hanami
123
91
  rdoc_options: []
124
92
  require_paths:
125
93
  - lib
@@ -127,15 +95,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
127
95
  requirements:
128
96
  - - ">="
129
97
  - !ruby/object:Gem::Version
130
- version: 2.4.0
98
+ version: '3.2'
131
99
  required_rubygems_version: !ruby/object:Gem::Requirement
132
100
  requirements:
133
101
  - - ">="
134
102
  - !ruby/object:Gem::Version
135
103
  version: '0'
136
104
  requirements: []
137
- rubygems_version: 3.3.27
138
- signing_key:
105
+ rubygems_version: 3.6.9
139
106
  specification_version: 4
140
107
  summary: Common framework to build command line interfaces with Ruby
141
108
  test_files: []