dry-cli 1.3.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: 8ab3b2530b7f867fee473bfb808d816bcfefd9732f49e158d32d5d914873516c
4
- data.tar.gz: 897275b361168f15eb760ced1d5a6db6ec1229361a9b323e06a3204bfe89cd8d
3
+ metadata.gz: 92920db180b09c97eece82f48b921162625b30cd41e5ac5c1f86fb623012a939
4
+ data.tar.gz: 3dc7e165cc9164546106cd52311f5db44b7e620a0acb2eaceb1a572bbfde1ee8
5
5
  SHA512:
6
- metadata.gz: c12f142b52bb3114425d7be016416603a951cc88b5252593a77f3cd48bbe73d0b7e453dca3519fd5025af9832b875f563208914cb5657d6d0b5eef19782d6412
7
- data.tar.gz: 2749e9f49dcf611171bdcdb2f9dbc51106cf78d7658155b2229a6e391610c18f288235ebe2abac654b6dfa8a0461e54e325cd2d315aa9303b2a06e1ddc1119fa
6
+ metadata.gz: '092186ca495d29592e2f24b1cbbecf981f1b3fb50065d61d0250055dce0fb2f419674daeb99d5771539721583417715b639f2c896c1135fa56fa7b420430fcdb'
7
+ data.tar.gz: 77e603998b0a56a3d19ee97c939ad00333b7262568c29d97463b39c3f442b60e5f85d3484fc7dd713e4fd96076a24d55ef8f37ffde0cfad164dd0b1fafaade6d
data/CHANGELOG.md CHANGED
@@ -1,7 +1,45 @@
1
- <!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
1
+ # Changelog
2
2
 
3
- ## 1.3.0 2025-07-29
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]
9
+
10
+ ### Added
11
+
12
+ ### Changed
13
+
14
+ ### Deprecated
15
+
16
+ ### Removed
17
+
18
+ ### Fixed
19
+
20
+ ### Security
21
+
22
+ [Unreleased]: https://github.com/dry-rb/dry-cli/compare/v1.4.0...main
23
+
24
+ ## [1.4.0] - 2026-01-09
25
+
26
+ ### Added
27
+
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
5
43
 
6
44
  ### Added
7
45
 
@@ -31,40 +69,34 @@
31
69
 
32
70
  - Set minimum Ruby version to 3.1. (@timriley)
33
71
 
34
- [Compare v1.2.0...v1.3.0](https://github.com/dry-rb/dry-cli/compare/v1.2.0...v1.3.0)
35
-
36
- ## 1.2.0 2024-10-15
72
+ [1.3.0]: https://github.com/dry-rb/dry-cli/compare/v1.2.0...v1.3.0
37
73
 
74
+ ## [1.2.0] - 2024-10-15
38
75
 
39
76
  ### Added
40
77
 
41
78
  - Added `:hidden` option to register commands that should not be shown in the help output. (@benoittgt in #137)
42
79
  - Provide suggestions when there is a typo in a command name. (@benoittgt in #138)
43
80
 
81
+ [1.2.0]: https://github.com/dry-rb/dry-cli/compare/v1.1.0...v1.2.0
44
82
 
45
- [Compare v1.1.0...v1.2.0](https://github.com/dry-rb/dry-cli/compare/v1.1.0...v1.2.0)
46
-
47
- ## 1.1.0 2024-07-14
48
-
83
+ ## [1.1.0] - 2024-07-14
49
84
 
50
85
  ### Added
51
86
 
52
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)
53
88
 
89
+ [1.1.0]: https://github.com/dry-rb/dry-cli/compare/v1.0.0...v1.1.0
54
90
 
55
- [Compare v1.0.0...v1.1.0](https://github.com/dry-rb/dry-cli/compare/v1.0.0...v1.1.0)
56
-
57
- ## 1.0.0 2022-11-05
58
-
91
+ ## [1.0.0] - 2022-11-05
59
92
 
60
93
  ### Changed
61
94
 
62
95
  - Version bumped to 1.0.0 (@solnic)
63
96
 
64
- [Compare v0.7.0...v1.0.0](https://github.com/dry-rb/dry-cli/compare/v0.7.0...v1.0.0)
65
-
66
- ## 0.7.0 2020-05-08
97
+ [1.0.0]: https://github.com/dry-rb/dry-cli/compare/v0.7.0...v1.0.0
67
98
 
99
+ ## [0.7.0] - 2020-05-08
68
100
 
69
101
  ### Added
70
102
 
@@ -88,10 +120,9 @@
88
120
  - Remove concurrent-ruby as runtime dependency (@jodosha)
89
121
  - [Internal] Banner and Parses refactoring (@IvanShamatov)
90
122
 
91
- [Compare v0.6.0...v0.7.0](https://github.com/dry-rb/dry-cli/compare/v0.6.0...v0.7.0)
92
-
93
- ## 0.6.0 2020-03-06
123
+ [0.7.0]: https://github.com/dry-rb/dry-cli/compare/v0.6.0...v0.7.0
94
124
 
125
+ ## [0.6.0] - 2020-03-06
95
126
 
96
127
  ### Added
97
128
 
@@ -105,11 +136,9 @@
105
136
  - [John Ledbetter & Luca Guidi] Fix ruby 2.7 warnings (@jodosha)
106
137
  - Fix banner, when option is a type of Array (@IvanShamatov)
107
138
 
139
+ [0.6.0]: https://github.com/dry-rb/dry-cli/compare/v0.5.1...v0.6.0
108
140
 
109
- [Compare v0.5.1...v0.6.0](https://github.com/dry-rb/dry-cli/compare/v0.5.1...v0.6.0)
110
-
111
- ## 0.5.1 2020-01-23
112
-
141
+ ## [0.5.1] - 2020-01-23
113
142
 
114
143
  ### Added
115
144
 
@@ -123,48 +152,38 @@
123
152
 
124
153
  - Added missing 'set' require (@solnic)
125
154
 
155
+ [0.5.1]: https://github.com/dry-rb/dry-cli/compare/v0.5.0...v0.5.1
126
156
 
127
- [Compare v0.5.0...v0.5.1](https://github.com/dry-rb/dry-cli/compare/v0.5.0...v0.5.1)
128
-
129
- ## 0.5.0 2019-12-21
130
-
157
+ ## [0.5.0] - 2019-12-21
131
158
 
132
159
  ### Added
133
160
 
134
161
  - [Internal] removed runtime and development dependency against `hanami-utils` (@jodosha, @IvanShamatov, @solnic)
135
162
 
163
+ [0.5.0]: https://github.com/dry-rb/dry-cli/compare/v0.4.0...v0.5.0
136
164
 
137
- [Compare v0.4.0...v0.5.0](https://github.com/dry-rb/dry-cli/compare/v0.4.0...v0.5.0)
138
-
139
- ## 0.4.0 2019-12-10
140
-
165
+ ## [0.4.0] - 2019-12-10
141
166
 
142
167
  ### Added
143
168
 
144
169
  - `hanami-cli` => `dry-cli` (@jodosha, @IvanShamatov, @solnic)
145
170
 
171
+ [0.4.0]: https://github.com/dry-rb/dry-cli/compare/v0.3.1...v0.4.0
146
172
 
147
- [Compare v0.3.1...v0.4.0](https://github.com/dry-rb/dry-cli/compare/v0.3.1...v0.4.0)
148
-
149
- ## 0.3.1 2019-01-18
150
-
173
+ ## [0.3.1] - 2019-01-18
151
174
 
152
175
  ### Added
153
176
 
154
177
  - Official support for Ruby: MRI 2.6 (@jodosha)
155
178
  - Support `bundler` 2.0+ (@jodosha)
156
179
 
180
+ [0.3.1]: https://github.com/dry-rb/dry-cli/compare/v0.3.0...v0.3.1
157
181
 
158
- [Compare v0.3.0...v0.3.1](https://github.com/dry-rb/dry-cli/compare/v0.3.0...v0.3.1)
159
-
160
- ## 0.3.0 2018-10-24
161
-
182
+ ## [0.3.0] - 2018-10-24
162
183
 
184
+ [0.3.0]: https://github.com/dry-rb/dry-cli/compare/v0.3.0.beta1...v0.3.0
163
185
 
164
- [Compare v0.3.0.beta1...v0.3.0](https://github.com/dry-rb/dry-cli/compare/v0.3.0.beta1...v0.3.0)
165
-
166
- ## 0.3.0.beta1 2018-08-08
167
-
186
+ ## [0.3.0.beta1] - 2018-08-08
168
187
 
169
188
  ### Added
170
189
 
@@ -177,29 +196,21 @@
177
196
 
178
197
  - Print informative message when unknown or wrong option is passed (`"test" was called with arguments "--framework=unknown"`) (@davydovanton)
179
198
 
199
+ [0.3.0.beta1]: https://github.com/dry-rb/dry-cli/compare/v0.2.0...v0.3.0.beta1
180
200
 
181
- [Compare v0.2.0...v0.3.0.beta1](https://github.com/dry-rb/dry-cli/compare/v0.2.0...v0.3.0.beta1)
182
-
183
- ## 0.2.0 2018-04-11
184
-
185
-
186
-
187
- [Compare v0.2.0.rc2...v0.2.0](https://github.com/dry-rb/dry-cli/compare/v0.2.0.rc2...v0.2.0)
188
-
189
- ## 0.2.0.rc2 2018-04-06
190
-
201
+ ## [0.2.0] - 2018-04-11
191
202
 
203
+ [0.2.0]: https://github.com/dry-rb/dry-cli/compare/v0.2.0.rc2...v0.2.0
192
204
 
193
- [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)
205
+ ## [0.2.0.rc2] - 2018-04-06
194
206
 
195
- ## 0.2.0.rc1 2018-03-30
207
+ [0.2.0.rc2]: https://github.com/dry-rb/dry-cli/compare/v0.2.0.rc1...v0.2.0.rc2
196
208
 
209
+ ## [0.2.0.rc1] - 2018-03-30
197
210
 
211
+ [0.2.0.rc1]: https://github.com/dry-rb/dry-cli/compare/v0.2.0.beta2...v0.2.0.rc1
198
212
 
199
- [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)
200
-
201
- ## 0.2.0.beta2 2018-03-23
202
-
213
+ ## [0.2.0.beta2] - 2018-03-23
203
214
 
204
215
  ### Added
205
216
 
@@ -209,21 +220,17 @@
209
220
 
210
221
  - Ensure callbacks' context of execution (aka `self`) to be the command that is being executed (@jodosha, @davydovanton)
211
222
 
223
+ [0.2.0.beta2]: https://github.com/dry-rb/dry-cli/compare/v0.2.0.beta1...v0.2.0.beta2
212
224
 
213
- [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)
214
-
215
- ## 0.2.0.beta1 2018-02-28
216
-
225
+ ## [0.2.0.beta1] - 2018-02-28
217
226
 
218
227
  ### Added
219
228
 
220
229
  - Register `before`/`after` callbacks for commands (@davydovanton)
221
230
 
231
+ [0.2.0.beta1]: https://github.com/dry-rb/dry-cli/compare/v0.1.1...v0.2.0.beta1
222
232
 
223
- [Compare v0.1.1...v0.2.0.beta1](https://github.com/dry-rb/dry-cli/compare/v0.1.1...v0.2.0.beta1)
224
-
225
- ## 0.1.1 2018-02-27
226
-
233
+ ## [0.1.1] - 2018-02-27
227
234
 
228
235
  ### Added
229
236
 
@@ -234,39 +241,29 @@
234
241
  - Ensure default values for arguments to be sent to commands (@AlfonsoUceda)
235
242
  - Ensure to fail when a missing required argument isn't provider, but an option is provided instead (@AlfonsoUceda)
236
243
 
244
+ [0.1.1]: https://github.com/dry-rb/dry-cli/compare/v0.1.0...v0.1.1
237
245
 
238
- [Compare v0.1.0...v0.1.1](https://github.com/dry-rb/dry-cli/compare/v0.1.0...v0.1.1)
239
-
240
- ## 0.1.0 2017-10-25
241
-
246
+ ## [0.1.0] - 2017-10-25
242
247
 
248
+ [0.1.0]: https://github.com/dry-rb/dry-cli/compare/v0.1.0.rc1...v0.1.0
243
249
 
244
- [Compare v0.1.0.rc1...v0.1.0](https://github.com/dry-rb/dry-cli/compare/v0.1.0.rc1...v0.1.0)
250
+ ## [0.1.0.rc1] - 2017-10-16
245
251
 
246
- ## 0.1.0.rc1 2017-10-16
252
+ [0.1.0.rc1]: https://github.com/dry-rb/dry-cli/compare/v0.1.0.beta3...v0.1.0.rc1
247
253
 
254
+ ## [0.1.0.beta3] - 2017-10-04
248
255
 
256
+ [0.1.0.beta3]: https://github.com/dry-rb/dry-cli/compare/v0.1.0.beta2...v0.1.0.beta3
249
257
 
250
- [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)
251
-
252
- ## 0.1.0.beta3 2017-10-04
253
-
254
-
255
-
256
- [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)
257
-
258
- ## 0.1.0.beta2 2017-10-03
259
-
258
+ ## [0.1.0.beta2] - 2017-10-03
260
259
 
261
260
  ### Added
262
261
 
263
262
  - Allow default value for arguments (@AlfonsoUceda)
264
263
 
264
+ [0.1.0.beta2]: https://github.com/dry-rb/dry-cli/compare/v0.1.0.beta1...v0.1.0.beta2
265
265
 
266
- [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)
267
-
268
- ## 0.1.0.beta1 2017-08-11
269
-
266
+ ## [0.1.0.beta1] - 2017-08-11
270
267
 
271
268
  ### Added
272
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 `>= 3.1.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,17 +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 = ">= 3.1"
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 "simplecov", "~> 0.17.1"
34
+ spec.add_development_dependency "bundler"
35
+ spec.add_development_dependency "rake"
36
+ spec.add_development_dependency "rspec"
37
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
 
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.3.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.3.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: 2025-07-29 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,68 +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: simplecov
63
- requirement: !ruby/object:Gem::Requirement
64
- requirements:
65
- - - "~>"
44
+ - - ">="
66
45
  - !ruby/object:Gem::Version
67
- version: 0.17.1
46
+ version: '0'
68
47
  type: :development
69
48
  prerelease: false
70
49
  version_requirements: !ruby/object:Gem::Requirement
71
50
  requirements:
72
- - - "~>"
51
+ - - ">="
73
52
  - !ruby/object:Gem::Version
74
- version: 0.17.1
53
+ version: '0'
75
54
  description: Common framework to build command line interfaces with Ruby
76
55
  email:
77
- - me@lucaguidi.com
56
+ - info@hanakai.org
78
57
  executables: []
79
58
  extensions: []
80
- extra_rdoc_files: []
59
+ extra_rdoc_files:
60
+ - CHANGELOG.md
61
+ - LICENSE
62
+ - README.md
81
63
  files:
82
64
  - CHANGELOG.md
83
65
  - LICENSE
@@ -105,7 +87,7 @@ metadata:
105
87
  changelog_uri: https://github.com/dry-rb/dry-cli/blob/main/CHANGELOG.md
106
88
  source_code_uri: https://github.com/dry-rb/dry-cli
107
89
  bug_tracker_uri: https://github.com/dry-rb/dry-cli/issues
108
- post_install_message:
90
+ funding_uri: https://github.com/sponsors/hanami
109
91
  rdoc_options: []
110
92
  require_paths:
111
93
  - lib
@@ -113,15 +95,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
113
95
  requirements:
114
96
  - - ">="
115
97
  - !ruby/object:Gem::Version
116
- version: '3.1'
98
+ version: '3.2'
117
99
  required_rubygems_version: !ruby/object:Gem::Requirement
118
100
  requirements:
119
101
  - - ">="
120
102
  - !ruby/object:Gem::Version
121
103
  version: '0'
122
104
  requirements: []
123
- rubygems_version: 3.3.27
124
- signing_key:
105
+ rubygems_version: 3.6.9
125
106
  specification_version: 4
126
107
  summary: Common framework to build command line interfaces with Ruby
127
108
  test_files: []