dry-cli 0.5.1 → 0.6.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: '0976875bf08ad159133d9c103dccf46df45551875fe368d24aca74bc11263b6e'
4
- data.tar.gz: 68d06b56349cc86c74812b1226d221cf11ad97c132ab836ea2161add4e8867d5
3
+ metadata.gz: 448f01b536f8cc664a86d2b4e558e8db6062c6ac31256c32d507828f1d3b7519
4
+ data.tar.gz: 254448f2e0b031cfc0077021ca3d0876b81b5eb9c7b1a7e51afce0d9524c95cc
5
5
  SHA512:
6
- metadata.gz: 9577fd903c55e544fe062aac19cf9226d3474a298299a8f30ce2ed58be60a9833e6b7d7ca56acfc33ec31b9899275a6ccaafa4aa732187987d0a72f3df0ab6f6
7
- data.tar.gz: e3842ccf475c1a82fb53fb71dfa9deb96a28d23ca20ff25860f49a3db07fcaf1f2d0cd5cd0454afb41ca3b924475f190c091c1bc8e4182eb9981a24449f425ed
6
+ metadata.gz: b114fa6217a59fdca38df56819e016a47337843ad357a52cd0f006bac2048dc2ee9253439a0353721412edac8e3a4d1f3c9601e7b3ccb729c86f5899d53fc2d6
7
+ data.tar.gz: 1edf50dce27e4d1cc9e9cc868c14d18e9399e62b0edcebf5a3166559bc8ef66a7fa79a04d0ac0c2ef5c6ffa1384aecb80ca967c16136f9dceb3721123e9c53a4
@@ -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 (@solnic)
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)
@@ -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 = '>= 2.4.0'
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"
@@ -36,16 +36,20 @@ module Dry
36
36
 
37
37
  # Create a new instance
38
38
  #
39
- # @param registry [Dry::CLI::Registry, Block] a registry or a configuration block
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.4.0
43
- def initialize(registry = nil, &block)
44
- @commands =
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
- registry
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
- result = commands.get(arguments)
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, out)
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, out)
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.1.0
131
+ # @since 0.6.0
89
132
  # @api private
90
- def parse(result, out)
91
- command = result.command
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, out, names)
137
+ out.puts Banner.call(command, names)
99
138
  exit(0)
100
139
  end
101
140
 
102
141
  if result.error?
103
- out.puts(result.error)
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, out)
118
- Usage.call(result, out)
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 registry [Dry::CLI::Registry, Block] a registry or a configuration block
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(registry = nil, &block)
162
- CLI.new(registry, &block)
202
+ def self.CLI(registry_or_command = nil, &block)
203
+ CLI.new(registry_or_command, &block)
163
204
  end
164
205
  end
@@ -16,9 +16,9 @@ module Dry
16
16
  #
17
17
  # @since 0.1.0
18
18
  # @api private
19
- def self.call(command, out, names)
19
+ def self.call(command, names)
20
20
  full_command_name = full_command_name(names)
21
- output = [
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) unless command.nil?
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
@@ -15,14 +15,14 @@ module Dry
15
15
 
16
16
  # @since 0.1.0
17
17
  # @api private
18
- def self.call(result, out)
19
- out.puts 'Commands:'
18
+ def self.call(result)
19
+ header = 'Commands:'
20
20
  max_length, commands = commands_and_arguments(result)
21
21
 
22
- commands.each do |banner, node|
22
+ commands.map do |banner, node|
23
23
  usage = description(node.command) if node.leaf?
24
- out.puts "#{justify(banner, max_length, usage)}#{usage}"
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
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'pathname'
4
4
  require 'fileutils'
5
+ require 'backports/2.4.0/string/match' if RUBY_VERSION < '2.4'
5
6
 
6
7
  module Dry
7
8
  class CLI
@@ -3,6 +3,6 @@
3
3
  module Dry
4
4
  class CLI
5
5
  # @since 0.1.0
6
- VERSION = '0.5.1'
6
+ VERSION = '0.6.0'
7
7
  end
8
8
  end
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.5.1
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-01-23 00:00:00.000000000 Z
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.4.0
130
+ version: 2.3.0
130
131
  required_rubygems_version: !ruby/object:Gem::Requirement
131
132
  requirements:
132
133
  - - ">="