dry-cli 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 448f01b536f8cc664a86d2b4e558e8db6062c6ac31256c32d507828f1d3b7519
4
- data.tar.gz: 254448f2e0b031cfc0077021ca3d0876b81b5eb9c7b1a7e51afce0d9524c95cc
3
+ metadata.gz: acfd9b78000e6f3ecef16d4eee260eee84bb4661251966e367e4f9a2001d3dac
4
+ data.tar.gz: df37074af2d1ed387d24ab90ed37920247cc40dc4c508c1325f08e9cb395c277
5
5
  SHA512:
6
- metadata.gz: b114fa6217a59fdca38df56819e016a47337843ad357a52cd0f006bac2048dc2ee9253439a0353721412edac8e3a4d1f3c9601e7b3ccb729c86f5899d53fc2d6
7
- data.tar.gz: 1edf50dce27e4d1cc9e9cc868c14d18e9399e62b0edcebf5a3166559bc8ef66a7fa79a04d0ac0c2ef5c6ffa1384aecb80ca967c16136f9dceb3721123e9c53a4
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
- - [Ivan Shamatov] Ability to pass command along with registry (for a singular command case)
7
- - [Nikita Shilnikov] [Internal] Backported ability to run gem's CI against ruby 2.3
8
- - [Ivan Shamatov] Inline syntax for commands
9
- - [Ivan Shamatov] Introduced stderr to any diagnostic output
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
- - [Ivan Shamatov] Fix banner, when option is a type of Array
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
- - [Ivan Shamatov] Anonymous Registry sintax
25
- - [Ivan Shamatov] [Internal] Specs refactored, more unit specs added
26
- - [Luca Guidi] [Internal] removed `dry-inflector` as runtime dependency
27
- - [Ivan Shamatov] [Internal] Refactored Command class (command_name property removed)
28
- - [Piotr Solnica, Luca Guidi, Nikita Shilnikov & Christian Georgii] [Internal] Adapt gem to dry-rb style
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
- - [Piotr Solnica] Added missing 'set' require
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
- - [Ivan Shamatov, Piotr Solnica, Luca Guidi] [Internal] removed runtime and development dependency against `hanami-utils`
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
- - [Ivan Shamatov, Piotr Solnica, Luca Guidi] `hanami-cli` => `dry-cli`
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
- - [Luca Guidi] Official support for Ruby: MRI 2.6
63
- - [Luca Guidi] Support `bundler` 2.0+
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
- - [Anton Davydov & Alfonso Uceda] Introduce array type for arguments (`foo exec test spec/bookshelf/entities spec/bookshelf/repositories`)
80
- - [Anton Davydov & Alfonso Uceda] Introduce array type for options (`foo generate config --apps=web,api`)
81
- - [Alfonso Uceda] Introduce variadic arguments (`foo run ruby:latest -- ruby -v`)
82
- - [Luca Guidi] Official support for JRuby 9.2.0.0
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
- - [Anton Davydov] Print informative message when unknown or wrong option is passed (`"test" was called with arguments "--framework=unknown"`)
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
- - [Anton Davydov & Luca Guidi] Support objects as callbacks
143
+ - Support objects as callbacks (@jodosha, @davydovanton)
115
144
 
116
145
  ### Fixed
117
146
 
118
- - [Anton Davydov & Luca Guidi] Ensure callbacks' context of execution (aka `self`) to be the command that is being executed
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
- - [Anton Davydov] Register `before`/`after` callbacks for commands
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
- - [Luca Guidi] Official support for Ruby: MRI 2.5
167
+ - Official support for Ruby: MRI 2.5 (@jodosha)
139
168
 
140
169
  ### Fixed
141
170
 
142
- - [Alfonso Uceda] Ensure default values for arguments to be sent to commands
143
- - [Alfonso Uceda] Ensure to fail when a missing required argument isn't provider, but an option is provided instead
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
- -  [Alfonso Uceda] Allow default value for arguments
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
- -  [Alfonso Uceda, Luca Guidi] Commands banner and usage
182
- -  [Alfonso Uceda] Added support for subcommands
183
- - [Alfonso Uceda] Validations for arguments and options
184
- - [Alfonso Uceda] Commands arguments and options
185
- - [Alfonso Uceda] Commands description
186
- - [Alfonso Uceda, Oana Sipos] Commands aliases
187
- - [Luca Guidi] Exit on unknown command
188
- - [Luca Guidi, Alfonso Uceda, Oana Sipos] Command lookup
189
- - [Luca Guidi, Tim Riley] Trie based registry to register commands and allow third-parties to override/add commands
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
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015-2020 dry-rb team
3
+ Copyright (c) 2015-2021 dry-rb 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
@@ -21,7 +21,7 @@
21
21
 
22
22
  This library officially supports the following Ruby versions:
23
23
 
24
- * MRI >= `2.4`
24
+ * MRI >= `2.5`
25
25
  * jruby >= `9.2`
26
26
 
27
27
  ## License
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.3.0"
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 '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'
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
- return perform_command(arguments) if kommand
66
-
67
- perform_registry(arguments)
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
- if result.found?
111
- command, args = parse(result.command, result.arguments, result.names)
113
+ command, args = parse(result.command, result.arguments, result.names)
112
114
 
113
- result.before_callbacks.run(command, args)
114
- command.call(**args)
115
- result.after_callbacks.run(command, args)
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
- result = Parser.call(command, arguments, names)
133
+ prog_name = ProgramName.call(names)
135
134
 
136
- if result.help?
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.error?
142
- err.puts(result.error)
143
- exit(1)
144
- end
137
+ return help(command, prog_name) if result.help?
138
+
139
+ return error(result) if result.error?
145
140
 
146
- [command.new, result.arguments]
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
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/cli/program_name'
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, names)
20
- full_command_name = full_command_name(names)
19
+ def self.call(command, name)
21
20
  [
22
- command_name(full_command_name),
23
- command_name_and_arguments(command, full_command_name),
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, full_command_name)
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")}" # rubocop:disable Metrics/LineLength
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(' ') if required_arguments.any? # rubocop:disable Metrics/LineLength
86
- optional = optional_arguments.map { |arg| "[#{arg.name.upcase}]" }.join(' ') if optional_arguments.any? # rubocop:disable Metrics/LineLength
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(' ')}" unless result.empty?
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(20)}\t# #{'REQUIRED ' if argument.required?}#{argument.desc}" # rubocop:disable Metrics/LineLength
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(', ')}" if option.aliases.any?
117
+ name = "#{name}, #{option.alias_names.join(", ")}" if option.aliases.any?
114
118
  name = " --#{name.ljust(30)}"
115
- name = "#{name}\t# #{option.desc}"
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 << " --#{'help, -h'.ljust(30)}\t# Print this help"
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