rfix 1.4.1 → 2.0.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 +4 -4
- data/exe/rfix +78 -34
- data/lib/rfix.rb +17 -28
- data/lib/rfix/branch.rb +3 -25
- data/lib/rfix/branch/base.rb +27 -0
- data/lib/rfix/branch/head.rb +15 -0
- data/lib/rfix/branch/main.rb +33 -0
- data/lib/rfix/branch/name.rb +21 -0
- data/lib/rfix/branch/reference.rb +15 -0
- data/lib/rfix/branch/upstream.rb +17 -0
- data/lib/rfix/cli/command.rb +19 -0
- data/lib/rfix/cli/command/base.rb +61 -0
- data/lib/rfix/cli/command/branch.rb +13 -0
- data/lib/rfix/cli/command/config.rb +22 -0
- data/lib/rfix/cli/command/extension.rb +25 -0
- data/lib/rfix/cli/command/help.rb +11 -0
- data/lib/rfix/cli/command/info.rb +11 -0
- data/lib/rfix/cli/command/lint.rb +17 -0
- data/lib/rfix/cli/command/local.rb +11 -0
- data/lib/rfix/cli/command/origin.rb +11 -0
- data/lib/rfix/cli/command/setup.rb +11 -0
- data/lib/rfix/error.rb +5 -1
- data/lib/rfix/extension/offense.rb +79 -0
- data/lib/rfix/extension/pastel.rb +11 -0
- data/lib/rfix/extension/string.rb +12 -0
- data/lib/rfix/extension/strings.rb +9 -0
- data/lib/rfix/file.rb +6 -41
- data/lib/rfix/file/base.rb +73 -0
- data/lib/rfix/file/deleted.rb +17 -0
- data/lib/rfix/file/ignored.rb +17 -0
- data/lib/rfix/file/tracked.rb +42 -0
- data/lib/rfix/file/untracked.rb +20 -0
- data/lib/rfix/formatter.rb +125 -86
- data/lib/rfix/highlighter.rb +118 -0
- data/lib/rfix/indicator.rb +19 -0
- data/lib/rfix/log.rb +12 -121
- data/lib/rfix/rake/gemfile.rb +111 -0
- data/lib/rfix/rake/paths.rb +25 -23
- data/lib/rfix/rake/support.rb +72 -57
- data/lib/rfix/repository.rb +114 -164
- data/lib/rfix/types.rb +52 -0
- data/lib/rfix/version.rb +1 -1
- data/rfix.gemspec +28 -38
- data/vendor/dry-cli/CHANGELOG.md +191 -0
- data/vendor/dry-cli/CODEOWNERS +1 -0
- data/vendor/dry-cli/CODE_OF_CONDUCT.md +13 -0
- data/vendor/dry-cli/CONTRIBUTING.md +29 -0
- data/vendor/dry-cli/Gemfile +14 -0
- data/vendor/dry-cli/Gemfile.devtools +18 -0
- data/vendor/dry-cli/LICENSE +20 -0
- data/vendor/dry-cli/README.md +29 -0
- data/vendor/dry-cli/Rakefile +13 -0
- data/vendor/dry-cli/bin/console +15 -0
- data/vendor/dry-cli/bin/setup +8 -0
- data/vendor/dry-cli/changelog.yml +97 -0
- data/vendor/dry-cli/docsite/source/arguments.html.md +57 -0
- data/vendor/dry-cli/docsite/source/callbacks.html.md +51 -0
- data/vendor/dry-cli/docsite/source/commands-with-subcommands-and-params.md +86 -0
- data/vendor/dry-cli/docsite/source/commands.html.md +41 -0
- data/vendor/dry-cli/docsite/source/index.html.md +302 -0
- data/vendor/dry-cli/docsite/source/options.html.md +51 -0
- data/vendor/dry-cli/docsite/source/subcommands.html.md +38 -0
- data/vendor/dry-cli/docsite/source/variadic-arguments.html.md +45 -0
- data/vendor/dry-cli/dry-cli.gemspec +36 -0
- data/vendor/dry-cli/lib/dry/cli.rb +224 -0
- data/vendor/dry-cli/lib/dry/cli/banner.rb +135 -0
- data/vendor/dry-cli/lib/dry/cli/command.rb +387 -0
- data/vendor/dry-cli/lib/dry/cli/command_registry.rb +253 -0
- data/vendor/dry-cli/lib/dry/cli/errors.rb +37 -0
- data/vendor/dry-cli/lib/dry/cli/inflector.rb +17 -0
- data/vendor/dry-cli/lib/dry/cli/inline.rb +75 -0
- data/vendor/dry-cli/lib/dry/cli/option.rb +131 -0
- data/vendor/dry-cli/lib/dry/cli/parser.rb +138 -0
- data/vendor/dry-cli/lib/dry/cli/program_name.rb +21 -0
- data/vendor/dry-cli/lib/dry/cli/registry.rb +338 -0
- data/vendor/dry-cli/lib/dry/cli/usage.rb +94 -0
- data/vendor/dry-cli/lib/dry/cli/version.rb +8 -0
- data/vendor/dry-cli/project.yml +13 -0
- data/vendor/dry-cli/spec/integration/commands_spec.rb +14 -0
- data/vendor/dry-cli/spec/integration/inherited_commands_spec.rb +24 -0
- data/vendor/dry-cli/spec/integration/inline_spec.rb +43 -0
- data/vendor/dry-cli/spec/integration/processes_errors_spec.rb +29 -0
- data/vendor/dry-cli/spec/integration/rendering_spec.rb +31 -0
- data/vendor/dry-cli/spec/integration/single_command_spec.rb +81 -0
- data/vendor/dry-cli/spec/integration/subcommands_spec.rb +60 -0
- data/vendor/dry-cli/spec/integration/third_party_gems_spec.rb +18 -0
- data/vendor/dry-cli/spec/spec_helper.rb +15 -0
- data/vendor/dry-cli/spec/support/coverage.rb +15 -0
- data/vendor/dry-cli/spec/support/files.rb +13 -0
- data/vendor/dry-cli/spec/support/fixtures/based +65 -0
- data/vendor/dry-cli/spec/support/fixtures/baz +9 -0
- data/vendor/dry-cli/spec/support/fixtures/baz_command.rb +19 -0
- data/vendor/dry-cli/spec/support/fixtures/foo +588 -0
- data/vendor/dry-cli/spec/support/fixtures/infinites +31 -0
- data/vendor/dry-cli/spec/support/fixtures/inline +20 -0
- data/vendor/dry-cli/spec/support/fixtures/registry.rb +15 -0
- data/vendor/dry-cli/spec/support/fixtures/shared_commands.rb +596 -0
- data/vendor/dry-cli/spec/support/fixtures/with_block.rb +86 -0
- data/vendor/dry-cli/spec/support/fixtures/with_registry.rb +90 -0
- data/vendor/dry-cli/spec/support/fixtures/with_zero_arity_block.rb +87 -0
- data/vendor/dry-cli/spec/support/helpers.rb +37 -0
- data/vendor/dry-cli/spec/support/path.rb +24 -0
- data/vendor/dry-cli/spec/support/rspec.rb +26 -0
- data/vendor/dry-cli/spec/support/rspec_options.rb +16 -0
- data/vendor/dry-cli/spec/support/shared_examples/commands.rb +300 -0
- data/vendor/dry-cli/spec/support/shared_examples/inherited_commands.rb +197 -0
- data/vendor/dry-cli/spec/support/shared_examples/rendering.rb +181 -0
- data/vendor/dry-cli/spec/support/shared_examples/subcommands.rb +226 -0
- data/vendor/dry-cli/spec/support/shared_examples/third_party_gems.rb +49 -0
- data/vendor/dry-cli/spec/support/warnings.rb +10 -0
- data/vendor/dry-cli/spec/unit/dry/cli/cli_spec.rb +123 -0
- data/vendor/dry-cli/spec/unit/dry/cli/inflector_spec.rb +26 -0
- data/vendor/dry-cli/spec/unit/dry/cli/registry_spec.rb +78 -0
- data/vendor/dry-cli/spec/unit/dry/cli/version_spec.rb +7 -0
- data/vendor/strings-ansi/CHANGELOG.md +24 -0
- data/vendor/strings-ansi/CODE_OF_CONDUCT.md +74 -0
- data/vendor/strings-ansi/Gemfile +11 -0
- data/{LICENSE.txt → vendor/strings-ansi/LICENSE.txt} +1 -1
- data/vendor/strings-ansi/README.md +155 -0
- data/vendor/strings-ansi/Rakefile +8 -0
- data/vendor/strings-ansi/appveyor.yml +32 -0
- data/vendor/strings-ansi/bin/console +14 -0
- data/vendor/strings-ansi/bin/setup +8 -0
- data/vendor/strings-ansi/lib/strings-ansi.rb +1 -0
- data/vendor/strings-ansi/lib/strings/ansi.rb +84 -0
- data/vendor/strings-ansi/lib/strings/ansi/extensions.rb +23 -0
- data/vendor/strings-ansi/lib/strings/ansi/version.rb +7 -0
- data/vendor/strings-ansi/spec/fixtures/ansi_codes.yaml +194 -0
- data/vendor/strings-ansi/spec/spec_helper.rb +51 -0
- data/vendor/strings-ansi/spec/unit/ansi_spec.rb +15 -0
- data/vendor/strings-ansi/spec/unit/extensions_spec.rb +19 -0
- data/vendor/strings-ansi/spec/unit/only_ansi_spec.rb +36 -0
- data/vendor/strings-ansi/spec/unit/sanitize_spec.rb +53 -0
- data/vendor/strings-ansi/strings-ansi.gemspec +34 -0
- data/vendor/strings-ansi/tasks/console.rake +11 -0
- data/vendor/strings-ansi/tasks/coverage.rake +11 -0
- data/vendor/strings-ansi/tasks/spec.rake +29 -0
- metadata +274 -188
- data/.github/workflows/main.yml +0 -26
- data/.gitignore +0 -43
- data/.rspec +0 -2
- data/.rubocop.yml +0 -87
- data/.travis.yml +0 -35
- data/Gemfile +0 -2
- data/Gemfile.base +0 -14
- data/Gemfile.base.lock +0 -172
- data/Gemfile.lock +0 -188
- data/Guardfile +0 -16
- data/Makefile +0 -12
- data/README.md +0 -85
- data/Rakefile +0 -31
- data/bin/bundle +0 -114
- data/bin/console +0 -29
- data/bin/guard +0 -29
- data/bin/rake +0 -29
- data/bin/rfix +0 -29
- data/bin/rspec +0 -29
- data/bin/setup +0 -29
- data/ci/Gemfile.rubocop-0.80 +0 -2
- data/ci/Gemfile.rubocop-0.80.lock +0 -170
- data/ci/Gemfile.rubocop-0.81 +0 -2
- data/ci/Gemfile.rubocop-0.81.lock +0 -170
- data/ci/Gemfile.rubocop-0.82 +0 -2
- data/ci/Gemfile.rubocop-0.82.lock +0 -170
- data/ci/Gemfile.rubocop-0.83 +0 -2
- data/ci/Gemfile.rubocop-0.83.lock +0 -168
- data/ci/Gemfile.rubocop-0.84 +0 -2
- data/ci/Gemfile.rubocop-0.84.lock +0 -171
- data/ci/Gemfile.rubocop-0.85 +0 -2
- data/ci/Gemfile.rubocop-0.85.1 +0 -2
- data/ci/Gemfile.rubocop-0.85.1.lock +0 -173
- data/ci/Gemfile.rubocop-0.85.lock +0 -173
- data/lib/rfix/box.rb +0 -112
- data/lib/rfix/branches/base.rb +0 -15
- data/lib/rfix/branches/head.rb +0 -13
- data/lib/rfix/branches/main.rb +0 -28
- data/lib/rfix/branches/name.rb +0 -23
- data/lib/rfix/branches/reference.rb +0 -21
- data/lib/rfix/branches/upstream.rb +0 -13
- data/lib/rfix/cmd.rb +0 -39
- data/lib/rfix/commands/branch.rb +0 -15
- data/lib/rfix/commands/extensions/options.rb +0 -8
- data/lib/rfix/commands/help.rb +0 -7
- data/lib/rfix/commands/helper/args.rb +0 -141
- data/lib/rfix/commands/helper/help.rb +0 -6
- data/lib/rfix/commands/helper/loader.rb +0 -6
- data/lib/rfix/commands/helper/option.rb +0 -0
- data/lib/rfix/commands/helper/params.rb +0 -0
- data/lib/rfix/commands/helper/rubocop.rb +0 -17
- data/lib/rfix/commands/info.rb +0 -30
- data/lib/rfix/commands/lint.rb +0 -22
- data/lib/rfix/commands/local.rb +0 -12
- data/lib/rfix/commands/origin.rb +0 -19
- data/lib/rfix/commands/setup.rb +0 -29
- data/lib/rfix/commands/welcome.rb +0 -24
- data/lib/rfix/deleted.rb +0 -13
- data/lib/rfix/extensions/extensions.rb +0 -18
- data/lib/rfix/extensions/offense.rb +0 -78
- data/lib/rfix/extensions/string.rb +0 -8
- data/lib/rfix/file_cache.rb +0 -59
- data/lib/rfix/git_helper.rb +0 -59
- data/lib/rfix/indentation.rb +0 -39
- data/lib/rfix/loader/bundler.rb +0 -37
- data/lib/rfix/loader/env.rb +0 -33
- data/lib/rfix/loader/spec.rb +0 -41
- data/lib/rfix/no_file.rb +0 -13
- data/lib/rfix/rfix.rb +0 -34
- data/lib/rfix/tracked.rb +0 -72
- data/lib/rfix/tracked_file.rb +0 -16
- data/lib/rfix/untracked.rb +0 -13
- data/resources/ps.png +0 -0
- data/tasks/bump.rake +0 -11
- data/tasks/bundle.rake +0 -17
- data/tasks/complex.rake +0 -54
- data/tasks/execute.rake +0 -38
- data/tasks/libgit2.rake +0 -33
- data/tasks/simple.rake +0 -62
- data/tasks/travis.rake +0 -74
- data/tasks/vendor.rake +0 -34
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "forwardable"
|
|
4
|
+
require "dry/cli/option"
|
|
5
|
+
|
|
6
|
+
module Dry
|
|
7
|
+
class CLI
|
|
8
|
+
# Base class for commands
|
|
9
|
+
#
|
|
10
|
+
# @since 0.1.0
|
|
11
|
+
class Command
|
|
12
|
+
# @since 0.1.0
|
|
13
|
+
# @api private
|
|
14
|
+
def self.inherited(base)
|
|
15
|
+
super
|
|
16
|
+
base.class_eval do
|
|
17
|
+
@_mutex = Mutex.new
|
|
18
|
+
@description = nil
|
|
19
|
+
@examples = []
|
|
20
|
+
@subcommands = []
|
|
21
|
+
@arguments = base.superclass_arguments || []
|
|
22
|
+
@options = base.superclass_options || []
|
|
23
|
+
end
|
|
24
|
+
base.extend ClassMethods
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @since 0.1.0
|
|
28
|
+
# @api private
|
|
29
|
+
module ClassMethods
|
|
30
|
+
# @since 0.1.0
|
|
31
|
+
# @api private
|
|
32
|
+
attr_reader :description
|
|
33
|
+
|
|
34
|
+
# @since 0.1.0
|
|
35
|
+
# @api private
|
|
36
|
+
attr_reader :examples
|
|
37
|
+
|
|
38
|
+
# @since 0.1.0
|
|
39
|
+
# @api private
|
|
40
|
+
attr_reader :arguments
|
|
41
|
+
|
|
42
|
+
# @since 0.1.0
|
|
43
|
+
# @api private
|
|
44
|
+
attr_reader :options
|
|
45
|
+
|
|
46
|
+
# @since x.x.x
|
|
47
|
+
# @api private
|
|
48
|
+
attr_accessor :subcommands
|
|
49
|
+
|
|
50
|
+
# @since x.x.x
|
|
51
|
+
# @api private
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Set the description of the command
|
|
55
|
+
#
|
|
56
|
+
# @param description [String] the description
|
|
57
|
+
#
|
|
58
|
+
# @since 0.1.0
|
|
59
|
+
#
|
|
60
|
+
# @example
|
|
61
|
+
# require "dry/cli"
|
|
62
|
+
#
|
|
63
|
+
# class Echo < Dry::CLI::Command
|
|
64
|
+
# desc "Prints given input"
|
|
65
|
+
#
|
|
66
|
+
# def call(*)
|
|
67
|
+
# # ...
|
|
68
|
+
# end
|
|
69
|
+
# end
|
|
70
|
+
def self.desc(description)
|
|
71
|
+
@description = description
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Describe the usage of the command
|
|
75
|
+
#
|
|
76
|
+
# @param examples [Array<String>] one or more examples
|
|
77
|
+
#
|
|
78
|
+
# @since 0.1.0
|
|
79
|
+
#
|
|
80
|
+
# @example
|
|
81
|
+
# require "dry/cli"
|
|
82
|
+
#
|
|
83
|
+
# class Server < Dry::CLI::Command
|
|
84
|
+
# example [
|
|
85
|
+
# " # Basic usage (it uses the bundled server engine)",
|
|
86
|
+
# "--server=webrick # Force `webrick` server engine",
|
|
87
|
+
# "--host=0.0.0.0 # Bind to a host",
|
|
88
|
+
# "--port=2306 # Bind to a port",
|
|
89
|
+
# "--no-code-reloading # Disable code reloading"
|
|
90
|
+
# ]
|
|
91
|
+
#
|
|
92
|
+
# def call(*)
|
|
93
|
+
# # ...
|
|
94
|
+
# end
|
|
95
|
+
# end
|
|
96
|
+
#
|
|
97
|
+
# # $ foo server --help
|
|
98
|
+
# # # ...
|
|
99
|
+
# #
|
|
100
|
+
# # Examples:
|
|
101
|
+
# # foo server # Basic usage (it uses the bundled server engine)
|
|
102
|
+
# # foo server --server=webrick # Force `webrick` server engine
|
|
103
|
+
# # foo server --host=0.0.0.0 # Bind to a host
|
|
104
|
+
# # foo server --port=2306 # Bind to a port
|
|
105
|
+
# # foo server --no-code-reloading # Disable code reloading
|
|
106
|
+
def self.example(*examples)
|
|
107
|
+
@examples += examples.flatten(1)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Specify an argument
|
|
111
|
+
#
|
|
112
|
+
# @param name [Symbol] the argument name
|
|
113
|
+
# @param options [Hash] a set of options
|
|
114
|
+
#
|
|
115
|
+
# @since 0.1.0
|
|
116
|
+
#
|
|
117
|
+
# @example Optional argument
|
|
118
|
+
# require "dry/cli"
|
|
119
|
+
#
|
|
120
|
+
# class Hello < Dry::CLI::Command
|
|
121
|
+
# argument :name
|
|
122
|
+
#
|
|
123
|
+
# def call(name: nil, **)
|
|
124
|
+
# if name.nil?
|
|
125
|
+
# puts "Hello, stranger"
|
|
126
|
+
# else
|
|
127
|
+
# puts "Hello, #{name}"
|
|
128
|
+
# end
|
|
129
|
+
# end
|
|
130
|
+
# end
|
|
131
|
+
#
|
|
132
|
+
# # $ foo hello
|
|
133
|
+
# # Hello, stranger
|
|
134
|
+
#
|
|
135
|
+
# # $ foo hello Luca
|
|
136
|
+
# # Hello, Luca
|
|
137
|
+
#
|
|
138
|
+
# @example Required argument
|
|
139
|
+
# require "dry/cli"
|
|
140
|
+
#
|
|
141
|
+
# class Hello < Dry::CLI::Command
|
|
142
|
+
# argument :name, required: true
|
|
143
|
+
#
|
|
144
|
+
# def call(name:, **)
|
|
145
|
+
# puts "Hello, #{name}"
|
|
146
|
+
# end
|
|
147
|
+
# end
|
|
148
|
+
#
|
|
149
|
+
# # $ foo hello Luca
|
|
150
|
+
# # Hello, Luca
|
|
151
|
+
#
|
|
152
|
+
# # $ foo hello
|
|
153
|
+
# # ERROR: "foo hello" was called with no arguments
|
|
154
|
+
# # Usage: "foo hello NAME"
|
|
155
|
+
#
|
|
156
|
+
# @example Multiple arguments
|
|
157
|
+
# require "dry/cli"
|
|
158
|
+
#
|
|
159
|
+
# module Generate
|
|
160
|
+
# class Action < Dry::CLI::Command
|
|
161
|
+
# argument :app, required: true
|
|
162
|
+
# argument :action, required: true
|
|
163
|
+
#
|
|
164
|
+
# def call(app:, action:, **)
|
|
165
|
+
# puts "Generating action: #{action} for app: #{app}"
|
|
166
|
+
# end
|
|
167
|
+
# end
|
|
168
|
+
# end
|
|
169
|
+
#
|
|
170
|
+
# # $ foo generate action web home
|
|
171
|
+
# # Generating action: home for app: web
|
|
172
|
+
#
|
|
173
|
+
# # $ foo generate action
|
|
174
|
+
# # ERROR: "foo generate action" was called with no arguments
|
|
175
|
+
# # Usage: "foo generate action APP ACTION"
|
|
176
|
+
#
|
|
177
|
+
# @example Description
|
|
178
|
+
# require "dry/cli"
|
|
179
|
+
#
|
|
180
|
+
# class Hello < Dry::CLI::Command
|
|
181
|
+
# argument :name, desc: "The name of the person to greet"
|
|
182
|
+
#
|
|
183
|
+
# def call(name: nil, **)
|
|
184
|
+
# # ...
|
|
185
|
+
# end
|
|
186
|
+
# end
|
|
187
|
+
#
|
|
188
|
+
# # $ foo hello --help
|
|
189
|
+
# # Command:
|
|
190
|
+
# # foo hello
|
|
191
|
+
# #
|
|
192
|
+
# # Usage:
|
|
193
|
+
# # foo hello [NAME]
|
|
194
|
+
# #
|
|
195
|
+
# # Arguments:
|
|
196
|
+
# # NAME # The name of the person to greet
|
|
197
|
+
# #
|
|
198
|
+
# # Options:
|
|
199
|
+
# # --help, -h # Print this help
|
|
200
|
+
def self.argument(name, options = {})
|
|
201
|
+
@arguments << Argument.new(name, options)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# Command line option (aka optional argument)
|
|
205
|
+
#
|
|
206
|
+
# @param name [Symbol] the param name
|
|
207
|
+
# @param options [Hash] a set of options
|
|
208
|
+
#
|
|
209
|
+
# @since 0.1.0
|
|
210
|
+
#
|
|
211
|
+
# @example Basic usage
|
|
212
|
+
# require "dry/cli"
|
|
213
|
+
#
|
|
214
|
+
# class Console < Dry::CLI::Command
|
|
215
|
+
# param :engine
|
|
216
|
+
#
|
|
217
|
+
# def call(engine: nil, **)
|
|
218
|
+
# puts "starting console (engine: #{engine || :irb})"
|
|
219
|
+
# end
|
|
220
|
+
# end
|
|
221
|
+
#
|
|
222
|
+
# # $ foo console
|
|
223
|
+
# # starting console (engine: irb)
|
|
224
|
+
#
|
|
225
|
+
# # $ foo console --engine=pry
|
|
226
|
+
# # starting console (engine: pry)
|
|
227
|
+
#
|
|
228
|
+
# @example List values
|
|
229
|
+
# require "dry/cli"
|
|
230
|
+
#
|
|
231
|
+
# class Console < Dry::CLI::Command
|
|
232
|
+
# param :engine, values: %w(irb pry ripl)
|
|
233
|
+
#
|
|
234
|
+
# def call(engine: nil, **)
|
|
235
|
+
# puts "starting console (engine: #{engine || :irb})"
|
|
236
|
+
# end
|
|
237
|
+
# end
|
|
238
|
+
#
|
|
239
|
+
# # $ foo console
|
|
240
|
+
# # starting console (engine: irb)
|
|
241
|
+
#
|
|
242
|
+
# # $ foo console --engine=pry
|
|
243
|
+
# # starting console (engine: pry)
|
|
244
|
+
#
|
|
245
|
+
# # $ foo console --engine=foo
|
|
246
|
+
# # ERROR: Invalid param provided
|
|
247
|
+
#
|
|
248
|
+
# @example Description
|
|
249
|
+
# require "dry/cli"
|
|
250
|
+
#
|
|
251
|
+
# class Console < Dry::CLI::Command
|
|
252
|
+
# param :engine, desc: "Force a console engine"
|
|
253
|
+
#
|
|
254
|
+
# def call(engine: nil, **)
|
|
255
|
+
# # ...
|
|
256
|
+
# end
|
|
257
|
+
# end
|
|
258
|
+
#
|
|
259
|
+
# # $ foo console --help
|
|
260
|
+
# # # ...
|
|
261
|
+
# #
|
|
262
|
+
# # Options:
|
|
263
|
+
# # --engine=VALUE # Force a console engine: (irb/pry/ripl)
|
|
264
|
+
# # --help, -h # Print this help
|
|
265
|
+
#
|
|
266
|
+
# @example Boolean
|
|
267
|
+
# require "dry/cli"
|
|
268
|
+
#
|
|
269
|
+
# class Server < Dry::CLI::Command
|
|
270
|
+
# param :code_reloading, type: :boolean, default: true
|
|
271
|
+
#
|
|
272
|
+
# def call(code_reloading:, **)
|
|
273
|
+
# puts "staring server (code reloading: #{code_reloading})"
|
|
274
|
+
# end
|
|
275
|
+
# end
|
|
276
|
+
#
|
|
277
|
+
# # $ foo server
|
|
278
|
+
# # starting server (code reloading: true)
|
|
279
|
+
#
|
|
280
|
+
# # $ foo server --no-code-reloading
|
|
281
|
+
# # starting server (code reloading: false)
|
|
282
|
+
#
|
|
283
|
+
# # $ foo server --help
|
|
284
|
+
# # # ...
|
|
285
|
+
# #
|
|
286
|
+
# # Options:
|
|
287
|
+
# # --[no]-code-reloading
|
|
288
|
+
#
|
|
289
|
+
# @example Aliases
|
|
290
|
+
# require "dry/cli"
|
|
291
|
+
#
|
|
292
|
+
# class Server < Dry::CLI::Command
|
|
293
|
+
# param :port, aliases: ["-p"]
|
|
294
|
+
#
|
|
295
|
+
# def call(options)
|
|
296
|
+
# puts "staring server (port: #{options.fetch(:port, 2300)})"
|
|
297
|
+
# end
|
|
298
|
+
# end
|
|
299
|
+
#
|
|
300
|
+
# # $ foo server
|
|
301
|
+
# # starting server (port: 2300)
|
|
302
|
+
#
|
|
303
|
+
# # $ foo server --port=2306
|
|
304
|
+
# # starting server (port: 2306)
|
|
305
|
+
#
|
|
306
|
+
# # $ foo server -p 2306
|
|
307
|
+
# # starting server (port: 2306)
|
|
308
|
+
#
|
|
309
|
+
# # $ foo server --help
|
|
310
|
+
# # # ...
|
|
311
|
+
# #
|
|
312
|
+
# # Options:
|
|
313
|
+
# # --port=VALUE, -p VALUE
|
|
314
|
+
def self.option(name, options = {})
|
|
315
|
+
@options << Option.new(name, options)
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
# @since 0.1.0
|
|
319
|
+
# @api private
|
|
320
|
+
def self.params
|
|
321
|
+
@_mutex.synchronize do
|
|
322
|
+
(@arguments + @options).uniq
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
# @since 0.1.0
|
|
327
|
+
# @api private
|
|
328
|
+
def self.default_params
|
|
329
|
+
params.each_with_object({}) do |param, result|
|
|
330
|
+
result[param.name] = param.default unless param.default.nil?
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
# @since 0.1.0
|
|
335
|
+
# @api private
|
|
336
|
+
def self.required_arguments
|
|
337
|
+
arguments.select(&:required?)
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
# @since 0.1.0
|
|
341
|
+
# @api private
|
|
342
|
+
def self.optional_arguments
|
|
343
|
+
arguments.reject(&:required?)
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
# @since x.x.x
|
|
347
|
+
# @api private
|
|
348
|
+
def self.subcommands
|
|
349
|
+
subcommands
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
# @since 0.7.0
|
|
353
|
+
# @api private
|
|
354
|
+
def self.superclass_variable_dup(var)
|
|
355
|
+
if superclass.instance_variable_defined?(var)
|
|
356
|
+
superclass.instance_variable_get(var).dup
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
# @since 0.7.0
|
|
361
|
+
# @api private
|
|
362
|
+
def self.superclass_arguments
|
|
363
|
+
superclass_variable_dup(:@arguments)
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
# @since 0.7.0
|
|
367
|
+
# @api private
|
|
368
|
+
def self.superclass_options
|
|
369
|
+
superclass_variable_dup(:@options)
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
extend Forwardable
|
|
373
|
+
|
|
374
|
+
delegate %i[
|
|
375
|
+
description
|
|
376
|
+
examples
|
|
377
|
+
arguments
|
|
378
|
+
options
|
|
379
|
+
params
|
|
380
|
+
default_params
|
|
381
|
+
required_arguments
|
|
382
|
+
optional_arguments
|
|
383
|
+
subcommands
|
|
384
|
+
] => "self.class"
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
end
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "set"
|
|
4
|
+
|
|
5
|
+
module Dry
|
|
6
|
+
class CLI
|
|
7
|
+
# Command registry
|
|
8
|
+
#
|
|
9
|
+
# @since 0.1.0
|
|
10
|
+
# @api private
|
|
11
|
+
class CommandRegistry
|
|
12
|
+
# @since 0.1.0
|
|
13
|
+
# @api private
|
|
14
|
+
def initialize
|
|
15
|
+
@_mutex = Mutex.new
|
|
16
|
+
@root = Node.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @since 0.1.0
|
|
20
|
+
# @api private
|
|
21
|
+
def set(name, command, aliases)
|
|
22
|
+
@_mutex.synchronize do
|
|
23
|
+
node = @root
|
|
24
|
+
name.split(/[[:space:]]/).each do |token|
|
|
25
|
+
node = node.put(node, token)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
node.aliases!(aliases)
|
|
29
|
+
if command
|
|
30
|
+
node.leaf!(command)
|
|
31
|
+
node.subcommands!(command)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
nil
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @since 0.1.0
|
|
39
|
+
# @api private
|
|
40
|
+
#
|
|
41
|
+
def get(arguments)
|
|
42
|
+
@_mutex.synchronize do
|
|
43
|
+
node = @root
|
|
44
|
+
args = []
|
|
45
|
+
names = []
|
|
46
|
+
valid_leaf = nil
|
|
47
|
+
result = LookupResult.new(node, args, names, node.leaf?)
|
|
48
|
+
|
|
49
|
+
arguments.each_with_index do |token, i|
|
|
50
|
+
tmp = node.lookup(token)
|
|
51
|
+
|
|
52
|
+
if tmp.nil? && valid_leaf
|
|
53
|
+
result = valid_leaf
|
|
54
|
+
break
|
|
55
|
+
elsif tmp.nil?
|
|
56
|
+
result = LookupResult.new(node, args, names, false)
|
|
57
|
+
break
|
|
58
|
+
elsif tmp.leaf?
|
|
59
|
+
args = arguments[i + 1..-1]
|
|
60
|
+
names = arguments[0..i]
|
|
61
|
+
node = tmp
|
|
62
|
+
result = LookupResult.new(node, args, names, true)
|
|
63
|
+
valid_leaf = result
|
|
64
|
+
break unless tmp.children?
|
|
65
|
+
else
|
|
66
|
+
names = arguments[0..i]
|
|
67
|
+
node = tmp
|
|
68
|
+
result = LookupResult.new(node, args, names, node.leaf?)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
result
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Node of the registry
|
|
77
|
+
#
|
|
78
|
+
# @since 0.1.0
|
|
79
|
+
# @api private
|
|
80
|
+
class Node
|
|
81
|
+
# @since 0.1.0
|
|
82
|
+
# @api private
|
|
83
|
+
attr_reader :parent
|
|
84
|
+
|
|
85
|
+
# @since 0.1.0
|
|
86
|
+
# @api private
|
|
87
|
+
attr_reader :children
|
|
88
|
+
|
|
89
|
+
# @since 0.1.0
|
|
90
|
+
# @api private
|
|
91
|
+
attr_reader :aliases
|
|
92
|
+
|
|
93
|
+
# @since 0.1.0
|
|
94
|
+
# @api private
|
|
95
|
+
attr_reader :command
|
|
96
|
+
|
|
97
|
+
# @since 0.1.0
|
|
98
|
+
# @api private
|
|
99
|
+
attr_reader :before_callbacks
|
|
100
|
+
|
|
101
|
+
# @since 0.1.0
|
|
102
|
+
# @api private
|
|
103
|
+
attr_reader :after_callbacks
|
|
104
|
+
|
|
105
|
+
# @since 0.1.0
|
|
106
|
+
# @api private
|
|
107
|
+
def initialize(parent = nil)
|
|
108
|
+
@parent = parent
|
|
109
|
+
@children = {}
|
|
110
|
+
@aliases = {}
|
|
111
|
+
@command = nil
|
|
112
|
+
|
|
113
|
+
@before_callbacks = Chain.new
|
|
114
|
+
@after_callbacks = Chain.new
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# @since 0.1.0
|
|
118
|
+
# @api private
|
|
119
|
+
def put(parent, key)
|
|
120
|
+
children[key] ||= self.class.new(parent)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# @since 0.1.0
|
|
124
|
+
# @api private
|
|
125
|
+
def lookup(token)
|
|
126
|
+
children[token] || aliases[token]
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# @since 0.1.0
|
|
130
|
+
# @api private
|
|
131
|
+
def leaf!(command)
|
|
132
|
+
@command = command
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# @since x.x.x
|
|
136
|
+
# @api private
|
|
137
|
+
def subcommands!(command)
|
|
138
|
+
command_class = command.is_a?(Class) ? command : command.class
|
|
139
|
+
command_class.subcommands = children
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# @since 0.1.0
|
|
143
|
+
# @api private
|
|
144
|
+
def alias!(key, child)
|
|
145
|
+
@aliases[key] = child
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# @since 0.1.0
|
|
149
|
+
# @api private
|
|
150
|
+
def aliases!(aliases)
|
|
151
|
+
aliases.each do |a|
|
|
152
|
+
parent.alias!(a, self)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# @since 0.1.0
|
|
157
|
+
# @api private
|
|
158
|
+
def leaf?
|
|
159
|
+
!command.nil?
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# @since x.x.x
|
|
163
|
+
# @api private
|
|
164
|
+
def children?
|
|
165
|
+
children.any?
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Result of a registry lookup
|
|
170
|
+
#
|
|
171
|
+
# @since 0.1.0
|
|
172
|
+
# @api private
|
|
173
|
+
class LookupResult
|
|
174
|
+
# @since 0.1.0
|
|
175
|
+
# @api private
|
|
176
|
+
attr_reader :names
|
|
177
|
+
|
|
178
|
+
# @since 0.1.0
|
|
179
|
+
# @api private
|
|
180
|
+
attr_reader :arguments
|
|
181
|
+
|
|
182
|
+
# @since 0.1.0
|
|
183
|
+
# @api private
|
|
184
|
+
def initialize(node, arguments, names, found)
|
|
185
|
+
@node = node
|
|
186
|
+
@arguments = arguments
|
|
187
|
+
@names = names
|
|
188
|
+
@found = found
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# @since 0.1.0
|
|
192
|
+
# @api private
|
|
193
|
+
def found?
|
|
194
|
+
@found
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# @since 0.1.0
|
|
198
|
+
# @api private
|
|
199
|
+
def children
|
|
200
|
+
@node.children
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# @since 0.1.0
|
|
204
|
+
# @api private
|
|
205
|
+
def command
|
|
206
|
+
@node.command
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# @since 0.2.0
|
|
210
|
+
# @api private
|
|
211
|
+
def before_callbacks
|
|
212
|
+
@node.before_callbacks
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# @since 0.2.0
|
|
216
|
+
# @api private
|
|
217
|
+
def after_callbacks
|
|
218
|
+
@node.after_callbacks
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Callbacks chain
|
|
223
|
+
#
|
|
224
|
+
# @since 0.4.0
|
|
225
|
+
# @api private
|
|
226
|
+
class Chain
|
|
227
|
+
# @since 0.4.0
|
|
228
|
+
# @api private
|
|
229
|
+
attr_reader :chain
|
|
230
|
+
|
|
231
|
+
# @since 0.4.0
|
|
232
|
+
# @api private
|
|
233
|
+
def initialize
|
|
234
|
+
@chain = Set.new
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# @since 0.4.0
|
|
238
|
+
# @api private
|
|
239
|
+
def append(&callback)
|
|
240
|
+
chain.add(callback)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# @since 0.4.0
|
|
244
|
+
# @api private
|
|
245
|
+
def run(context, *args)
|
|
246
|
+
chain.each do |callback|
|
|
247
|
+
context.instance_exec(*args, &callback)
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
end
|