dry-cli 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +27 -1
- data/dry-cli.gemspec +3 -1
- data/lib/dry/cli.rb +72 -31
- data/lib/dry/cli/banner.rb +4 -4
- data/lib/dry/cli/command_registry.rb +1 -2
- data/lib/dry/cli/inline.rb +75 -0
- data/lib/dry/cli/usage.rb +5 -5
- data/lib/dry/cli/utils/files.rb +1 -0
- data/lib/dry/cli/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 448f01b536f8cc664a86d2b4e558e8db6062c6ac31256c32d507828f1d3b7519
|
4
|
+
data.tar.gz: 254448f2e0b031cfc0077021ca3d0876b81b5eb9c7b1a7e51afce0d9524c95cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b114fa6217a59fdca38df56819e016a47337843ad357a52cd0f006bac2048dc2ee9253439a0353721412edac8e3a4d1f3c9601e7b3ccb729c86f5899d53fc2d6
|
7
|
+
data.tar.gz: 1edf50dce27e4d1cc9e9cc868c14d18e9399e62b0edcebf5a3166559bc8ef66a7fa79a04d0ac0c2ef5c6ffa1384aecb80ca967c16136f9dceb3721123e9c53a4
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,35 @@
|
|
1
|
+
## 0.6.0 2020-03-06
|
2
|
+
|
3
|
+
|
4
|
+
### Added
|
5
|
+
|
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
|
10
|
+
|
11
|
+
### Fixed
|
12
|
+
|
13
|
+
- [John Ledbetter & Luca Guidi] Fix ruby 2.7 warnings
|
14
|
+
- [Ivan Shamatov] Fix banner, when option is a type of Array
|
15
|
+
|
16
|
+
|
17
|
+
[Compare v0.5.1...v0.6.0](https://github.com/dry-rb/dry-cli/compare/v0.5.1...v0.6.0)
|
18
|
+
|
1
19
|
## 0.5.1 2020-01-23
|
2
20
|
|
3
21
|
|
22
|
+
### Added
|
23
|
+
|
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
|
29
|
+
|
4
30
|
### Fixed
|
5
31
|
|
6
|
-
- Added missing 'set' require
|
32
|
+
- [Piotr Solnica] Added missing 'set' require
|
7
33
|
|
8
34
|
|
9
35
|
[Compare v0.5.0...v0.5.1](https://github.com/dry-rb/dry-cli/compare/v0.5.0...v0.5.1)
|
data/dry-cli.gemspec
CHANGED
@@ -16,6 +16,8 @@ Gem::Specification.new do |spec|
|
|
16
16
|
spec.description = spec.summary
|
17
17
|
spec.homepage = 'https://dry-rb.org/gems/dry-cli'
|
18
18
|
spec.files = Dir["CHANGELOG.md", "LICENSE", "README.md", "dry-cli.gemspec", "lib/**/*"]
|
19
|
+
spec.bindir = 'bin'
|
20
|
+
spec.executables = []
|
19
21
|
spec.require_paths = ['lib']
|
20
22
|
|
21
23
|
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
@@ -23,7 +25,7 @@ Gem::Specification.new do |spec|
|
|
23
25
|
spec.metadata['source_code_uri'] = 'https://github.com/dry-rb/dry-cli'
|
24
26
|
spec.metadata['bug_tracker_uri'] = 'https://github.com/dry-rb/dry-cli/issues'
|
25
27
|
|
26
|
-
spec.required_ruby_version =
|
28
|
+
spec.required_ruby_version = ">= 2.3.0"
|
27
29
|
|
28
30
|
# to update dependencies edit project.yml
|
29
31
|
spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
|
data/lib/dry/cli.rb
CHANGED
@@ -36,16 +36,20 @@ module Dry
|
|
36
36
|
|
37
37
|
# Create a new instance
|
38
38
|
#
|
39
|
-
# @param
|
39
|
+
# @param command_or_registry [Dry::CLI::Registry, Dry::CLI::Command]
|
40
|
+
# a registry or singular command
|
41
|
+
# @param &block [Block] a configuration block for registry
|
40
42
|
#
|
41
43
|
# @return [Dry::CLI] the new instance
|
42
|
-
# @since 0.
|
43
|
-
def initialize(
|
44
|
-
@
|
44
|
+
# @since 0.1.0
|
45
|
+
def initialize(command_or_registry = nil, &block)
|
46
|
+
@kommand = command_or_registry if command?(command_or_registry)
|
47
|
+
|
48
|
+
@registry =
|
45
49
|
if block_given?
|
46
50
|
anonymous_registry(&block)
|
47
51
|
else
|
48
|
-
|
52
|
+
command_or_registry
|
49
53
|
end
|
50
54
|
end
|
51
55
|
|
@@ -53,28 +57,67 @@ module Dry
|
|
53
57
|
#
|
54
58
|
# @param arguments [Array<string>] the command line arguments (defaults to `ARGV`)
|
55
59
|
# @param out [IO] the standard output (defaults to `$stdout`)
|
60
|
+
# @param err [IO] the error output (defaults to `$stderr`)
|
56
61
|
#
|
57
62
|
# @since 0.1.0
|
58
|
-
def call(arguments: ARGV, out: $stdout)
|
59
|
-
|
63
|
+
def call(arguments: ARGV, out: $stdout, err: $stderr)
|
64
|
+
@out, @err = out, err
|
65
|
+
return perform_command(arguments) if kommand
|
66
|
+
|
67
|
+
perform_registry(arguments)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
# @since 0.6.0
|
73
|
+
# @api private
|
74
|
+
attr_reader :registry
|
75
|
+
|
76
|
+
# @since 0.6.0
|
77
|
+
# @api private
|
78
|
+
attr_reader :kommand
|
79
|
+
|
80
|
+
# @since 0.6.0
|
81
|
+
# @api private
|
82
|
+
attr_reader :out
|
83
|
+
|
84
|
+
# @since 0.6.0
|
85
|
+
# @api private
|
86
|
+
attr_reader :err
|
87
|
+
|
88
|
+
# Invoke the CLI if singular command passed
|
89
|
+
#
|
90
|
+
# @param arguments [Array<string>] the command line arguments
|
91
|
+
# @param out [IO] the standard output (defaults to `$stdout`)
|
92
|
+
#
|
93
|
+
# @since 0.6.0
|
94
|
+
# @api private
|
95
|
+
def perform_command(arguments)
|
96
|
+
command, args = parse(kommand, arguments, [])
|
97
|
+
command.call(**args)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Invoke the CLI if registry passed
|
101
|
+
#
|
102
|
+
# @param arguments [Array<string>] the command line arguments
|
103
|
+
# @param out [IO] the standard output (defaults to `$stdout`)
|
104
|
+
#
|
105
|
+
# @since 0.6.0
|
106
|
+
# @api private
|
107
|
+
def perform_registry(arguments)
|
108
|
+
result = registry.get(arguments)
|
60
109
|
|
61
110
|
if result.found?
|
62
|
-
command, args = parse(result,
|
111
|
+
command, args = parse(result.command, result.arguments, result.names)
|
63
112
|
|
64
113
|
result.before_callbacks.run(command, args)
|
65
|
-
command.call(args)
|
114
|
+
command.call(**args)
|
66
115
|
result.after_callbacks.run(command, args)
|
67
116
|
else
|
68
|
-
usage(result
|
117
|
+
usage(result)
|
69
118
|
end
|
70
119
|
end
|
71
120
|
|
72
|
-
private
|
73
|
-
|
74
|
-
# @since 0.1.0
|
75
|
-
# @api private
|
76
|
-
attr_reader :commands
|
77
|
-
|
78
121
|
# Parse arguments for a command.
|
79
122
|
#
|
80
123
|
# It may exit in case of error, or in case of help.
|
@@ -85,26 +128,22 @@ module Dry
|
|
85
128
|
# @return [Array<Dry:CLI::Command, Array>] returns an array where the
|
86
129
|
# first element is a command and the second one is the list of arguments
|
87
130
|
#
|
88
|
-
# @since 0.
|
131
|
+
# @since 0.6.0
|
89
132
|
# @api private
|
90
|
-
def parse(
|
91
|
-
|
92
|
-
names = result.names
|
93
|
-
return [command, result.arguments] unless command?(command)
|
94
|
-
|
95
|
-
result = Parser.call(command, result.arguments, result.names)
|
133
|
+
def parse(command, arguments, names)
|
134
|
+
result = Parser.call(command, arguments, names)
|
96
135
|
|
97
136
|
if result.help?
|
98
|
-
Banner.call(command,
|
137
|
+
out.puts Banner.call(command, names)
|
99
138
|
exit(0)
|
100
139
|
end
|
101
140
|
|
102
141
|
if result.error?
|
103
|
-
|
142
|
+
err.puts(result.error)
|
104
143
|
exit(1)
|
105
144
|
end
|
106
145
|
|
107
|
-
[command, result.arguments]
|
146
|
+
[command.new, result.arguments]
|
108
147
|
end
|
109
148
|
|
110
149
|
# Prints the command usage and exit.
|
@@ -114,8 +153,8 @@ module Dry
|
|
114
153
|
#
|
115
154
|
# @since 0.1.0
|
116
155
|
# @api private
|
117
|
-
def usage(result
|
118
|
-
Usage.call(result
|
156
|
+
def usage(result)
|
157
|
+
err.puts Usage.call(result)
|
119
158
|
exit(1)
|
120
159
|
end
|
121
160
|
|
@@ -154,11 +193,13 @@ module Dry
|
|
154
193
|
|
155
194
|
# Create a new instance
|
156
195
|
#
|
157
|
-
# @param
|
196
|
+
# @param registry_or_command [Dry::CLI::Registry, Dry::CLI::Command]
|
197
|
+
# a registry or singular command
|
198
|
+
# @param &block [Block] a configuration block for registry
|
158
199
|
#
|
159
200
|
# @return [Dry::CLI] the new instance
|
160
201
|
# @since 0.4.0
|
161
|
-
def self.CLI(
|
162
|
-
CLI.new(
|
202
|
+
def self.CLI(registry_or_command = nil, &block)
|
203
|
+
CLI.new(registry_or_command, &block)
|
163
204
|
end
|
164
205
|
end
|
data/lib/dry/cli/banner.rb
CHANGED
@@ -16,9 +16,9 @@ module Dry
|
|
16
16
|
#
|
17
17
|
# @since 0.1.0
|
18
18
|
# @api private
|
19
|
-
def self.call(command,
|
19
|
+
def self.call(command, names)
|
20
20
|
full_command_name = full_command_name(names)
|
21
|
-
|
21
|
+
[
|
22
22
|
command_name(full_command_name),
|
23
23
|
command_name_and_arguments(command, full_command_name),
|
24
24
|
command_description(command),
|
@@ -26,8 +26,6 @@ module Dry
|
|
26
26
|
command_options(command),
|
27
27
|
command_examples(command, full_command_name)
|
28
28
|
].compact.join("\n")
|
29
|
-
|
30
|
-
out.puts output
|
31
29
|
end
|
32
30
|
|
33
31
|
# @since 0.1.0
|
@@ -107,6 +105,8 @@ module Dry
|
|
107
105
|
name = Inflector.dasherize(option.name)
|
108
106
|
name = if option.boolean?
|
109
107
|
"[no-]#{name}"
|
108
|
+
elsif option.array?
|
109
|
+
"#{name}=VALUE1,VALUE2,.."
|
110
110
|
else
|
111
111
|
"#{name}=VALUE"
|
112
112
|
end
|
@@ -20,13 +20,12 @@ module Dry
|
|
20
20
|
# @api private
|
21
21
|
def set(name, command, aliases)
|
22
22
|
node = @root
|
23
|
-
command = command.new if command
|
24
23
|
name.split(/[[:space:]]/).each do |token|
|
25
24
|
node = node.put(node, token)
|
26
25
|
end
|
27
26
|
|
28
27
|
node.aliases!(aliases)
|
29
|
-
node.leaf!(command)
|
28
|
+
node.leaf!(command) if command
|
30
29
|
|
31
30
|
nil
|
32
31
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'backports/2.5.0/module/define_method' if RUBY_VERSION < '2.5'
|
4
|
+
|
5
|
+
module Dry
|
6
|
+
class CLI
|
7
|
+
require 'dry/cli'
|
8
|
+
# Inline Syntax (aka DSL) to implement one-file applications
|
9
|
+
#
|
10
|
+
# `dry/cli/inline` is not required by default
|
11
|
+
# and explicit requirement of this file means that
|
12
|
+
# it is expected of abusing global namespace with
|
13
|
+
# methods below
|
14
|
+
#
|
15
|
+
# DSL consists of 5 methods:
|
16
|
+
# `desc`, `example`, `argument`, `option`
|
17
|
+
# — are similar to methods from Command class
|
18
|
+
#
|
19
|
+
# `run` accepts a block to execute
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# require 'bundler/inline'
|
23
|
+
# gemfile { gem 'dry/cli', require: 'dry/cli/inline' }
|
24
|
+
#
|
25
|
+
# desc 'List files in a directory'
|
26
|
+
# argument :path, required: false, desc: '[DIR]'
|
27
|
+
# option :all, aliases: ['a'], type: :boolean
|
28
|
+
#
|
29
|
+
# run do |path: '.', **options|
|
30
|
+
# puts options.key?(:all) ? Dir.entries(path) : Dir.children(path)
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# # $ ls -a
|
34
|
+
# # $ ls somepath
|
35
|
+
# # $ ls somepath --all
|
36
|
+
# @since 0.6.0
|
37
|
+
module Inline
|
38
|
+
extend Forwardable
|
39
|
+
|
40
|
+
# AnonymousCommand
|
41
|
+
#
|
42
|
+
# @since 0.6.0
|
43
|
+
AnonymousCommand = Class.new(Dry::CLI::Command)
|
44
|
+
|
45
|
+
# @since 0.6.0
|
46
|
+
delegate %i[desc example argument option] => AnonymousCommand
|
47
|
+
|
48
|
+
# The rule of thumb for implementation of run block
|
49
|
+
# is that for every argument from your CLI
|
50
|
+
# you need to specify that as an mandatory argument for a block.
|
51
|
+
# Optional arguments have to have default value as ruby syntax expect them
|
52
|
+
#
|
53
|
+
# @example
|
54
|
+
# argument :one
|
55
|
+
# argument :two, required: false
|
56
|
+
# option :three
|
57
|
+
#
|
58
|
+
# run do |one:, two: 'default', **options|
|
59
|
+
# puts one, two, options.inspect
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# @since 0.6.0
|
63
|
+
def run(arguments: ARGV, out: $stdout)
|
64
|
+
command = AnonymousCommand
|
65
|
+
command.define_method(:call) do |*args|
|
66
|
+
yield(*args)
|
67
|
+
end
|
68
|
+
|
69
|
+
Dry.CLI(command).call(arguments: arguments, out: out)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
include Dry::CLI::Inline # rubocop:disable Style/MixinUsage
|
data/lib/dry/cli/usage.rb
CHANGED
@@ -15,14 +15,14 @@ module Dry
|
|
15
15
|
|
16
16
|
# @since 0.1.0
|
17
17
|
# @api private
|
18
|
-
def self.call(result
|
19
|
-
|
18
|
+
def self.call(result)
|
19
|
+
header = 'Commands:'
|
20
20
|
max_length, commands = commands_and_arguments(result)
|
21
21
|
|
22
|
-
commands.
|
22
|
+
commands.map do |banner, node|
|
23
23
|
usage = description(node.command) if node.leaf?
|
24
|
-
|
25
|
-
end
|
24
|
+
"#{justify(banner, max_length, usage)}#{usage}"
|
25
|
+
end.unshift(header).join("\n")
|
26
26
|
end
|
27
27
|
|
28
28
|
# @since 0.1.0
|
data/lib/dry/cli/utils/files.rb
CHANGED
data/lib/dry/cli/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dry-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luca Guidi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-03-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -103,6 +103,7 @@ files:
|
|
103
103
|
- lib/dry/cli/command_registry.rb
|
104
104
|
- lib/dry/cli/errors.rb
|
105
105
|
- lib/dry/cli/inflector.rb
|
106
|
+
- lib/dry/cli/inline.rb
|
106
107
|
- lib/dry/cli/option.rb
|
107
108
|
- lib/dry/cli/parser.rb
|
108
109
|
- lib/dry/cli/program_name.rb
|
@@ -126,7 +127,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
126
127
|
requirements:
|
127
128
|
- - ">="
|
128
129
|
- !ruby/object:Gem::Version
|
129
|
-
version: 2.
|
130
|
+
version: 2.3.0
|
130
131
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
132
|
requirements:
|
132
133
|
- - ">="
|