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 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
  - - ">="