rfix 1.4.0.pre.201 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (219) hide show
  1. checksums.yaml +4 -4
  2. data/exe/rfix +78 -34
  3. data/lib/rfix.rb +17 -28
  4. data/lib/rfix/branch.rb +3 -25
  5. data/lib/rfix/branch/base.rb +27 -0
  6. data/lib/rfix/branch/head.rb +15 -0
  7. data/lib/rfix/branch/main.rb +33 -0
  8. data/lib/rfix/branch/name.rb +21 -0
  9. data/lib/rfix/branch/reference.rb +15 -0
  10. data/lib/rfix/branch/upstream.rb +17 -0
  11. data/lib/rfix/cli/command.rb +19 -0
  12. data/lib/rfix/cli/command/base.rb +67 -0
  13. data/lib/rfix/cli/command/branch.rb +13 -0
  14. data/lib/rfix/cli/command/config.rb +22 -0
  15. data/lib/rfix/cli/command/extension.rb +25 -0
  16. data/lib/rfix/cli/command/help.rb +11 -0
  17. data/lib/rfix/cli/command/info.rb +11 -0
  18. data/lib/rfix/cli/command/lint.rb +17 -0
  19. data/lib/rfix/cli/command/local.rb +11 -0
  20. data/lib/rfix/cli/command/origin.rb +11 -0
  21. data/lib/rfix/cli/command/setup.rb +11 -0
  22. data/lib/rfix/error.rb +5 -1
  23. data/lib/rfix/extension/offense.rb +79 -0
  24. data/lib/rfix/extension/pastel.rb +11 -0
  25. data/lib/rfix/extension/string.rb +12 -0
  26. data/lib/rfix/extension/strings.rb +9 -0
  27. data/lib/rfix/file.rb +6 -41
  28. data/lib/rfix/file/base.rb +73 -0
  29. data/lib/rfix/file/deleted.rb +17 -0
  30. data/lib/rfix/file/ignored.rb +17 -0
  31. data/lib/rfix/file/tracked.rb +42 -0
  32. data/lib/rfix/file/untracked.rb +20 -0
  33. data/lib/rfix/formatter.rb +125 -86
  34. data/lib/rfix/highlighter.rb +118 -0
  35. data/lib/rfix/indicator.rb +19 -0
  36. data/lib/rfix/log.rb +12 -121
  37. data/lib/rfix/rake/gemfile.rb +111 -0
  38. data/lib/rfix/rake/paths.rb +25 -23
  39. data/lib/rfix/rake/support.rb +72 -57
  40. data/lib/rfix/repository.rb +117 -163
  41. data/lib/rfix/types.rb +52 -0
  42. data/lib/rfix/version.rb +1 -1
  43. data/rfix.gemspec +28 -49
  44. data/vendor/dry-cli/CHANGELOG.md +191 -0
  45. data/vendor/dry-cli/CODEOWNERS +1 -0
  46. data/vendor/dry-cli/CODE_OF_CONDUCT.md +13 -0
  47. data/vendor/dry-cli/CONTRIBUTING.md +29 -0
  48. data/vendor/dry-cli/Gemfile +14 -0
  49. data/vendor/dry-cli/Gemfile.devtools +18 -0
  50. data/vendor/dry-cli/LICENSE +20 -0
  51. data/vendor/dry-cli/README.md +29 -0
  52. data/vendor/dry-cli/Rakefile +13 -0
  53. data/vendor/dry-cli/bin/console +15 -0
  54. data/vendor/dry-cli/bin/setup +8 -0
  55. data/vendor/dry-cli/changelog.yml +97 -0
  56. data/vendor/dry-cli/docsite/source/arguments.html.md +57 -0
  57. data/vendor/dry-cli/docsite/source/callbacks.html.md +51 -0
  58. data/vendor/dry-cli/docsite/source/commands-with-subcommands-and-params.md +86 -0
  59. data/vendor/dry-cli/docsite/source/commands.html.md +41 -0
  60. data/vendor/dry-cli/docsite/source/index.html.md +302 -0
  61. data/vendor/dry-cli/docsite/source/options.html.md +51 -0
  62. data/vendor/dry-cli/docsite/source/subcommands.html.md +38 -0
  63. data/vendor/dry-cli/docsite/source/variadic-arguments.html.md +45 -0
  64. data/vendor/dry-cli/dry-cli.gemspec +36 -0
  65. data/vendor/dry-cli/lib/dry/cli.rb +224 -0
  66. data/vendor/dry-cli/lib/dry/cli/banner.rb +135 -0
  67. data/vendor/dry-cli/lib/dry/cli/command.rb +387 -0
  68. data/vendor/dry-cli/lib/dry/cli/command_registry.rb +253 -0
  69. data/vendor/dry-cli/lib/dry/cli/errors.rb +37 -0
  70. data/vendor/dry-cli/lib/dry/cli/inflector.rb +17 -0
  71. data/vendor/dry-cli/lib/dry/cli/inline.rb +75 -0
  72. data/vendor/dry-cli/lib/dry/cli/option.rb +131 -0
  73. data/vendor/dry-cli/lib/dry/cli/parser.rb +138 -0
  74. data/vendor/dry-cli/lib/dry/cli/program_name.rb +21 -0
  75. data/vendor/dry-cli/lib/dry/cli/registry.rb +338 -0
  76. data/vendor/dry-cli/lib/dry/cli/usage.rb +94 -0
  77. data/vendor/dry-cli/lib/dry/cli/version.rb +8 -0
  78. data/vendor/dry-cli/project.yml +13 -0
  79. data/vendor/dry-cli/spec/integration/commands_spec.rb +14 -0
  80. data/vendor/dry-cli/spec/integration/inherited_commands_spec.rb +24 -0
  81. data/vendor/dry-cli/spec/integration/inline_spec.rb +43 -0
  82. data/vendor/dry-cli/spec/integration/processes_errors_spec.rb +29 -0
  83. data/vendor/dry-cli/spec/integration/rendering_spec.rb +31 -0
  84. data/vendor/dry-cli/spec/integration/single_command_spec.rb +81 -0
  85. data/vendor/dry-cli/spec/integration/subcommands_spec.rb +60 -0
  86. data/vendor/dry-cli/spec/integration/third_party_gems_spec.rb +18 -0
  87. data/vendor/dry-cli/spec/spec_helper.rb +15 -0
  88. data/vendor/dry-cli/spec/support/coverage.rb +15 -0
  89. data/vendor/dry-cli/spec/support/files.rb +13 -0
  90. data/vendor/dry-cli/spec/support/fixtures/based +65 -0
  91. data/vendor/dry-cli/spec/support/fixtures/baz +9 -0
  92. data/vendor/dry-cli/spec/support/fixtures/baz_command.rb +19 -0
  93. data/vendor/dry-cli/spec/support/fixtures/foo +588 -0
  94. data/vendor/dry-cli/spec/support/fixtures/infinites +31 -0
  95. data/vendor/dry-cli/spec/support/fixtures/inline +20 -0
  96. data/vendor/dry-cli/spec/support/fixtures/registry.rb +15 -0
  97. data/vendor/dry-cli/spec/support/fixtures/shared_commands.rb +596 -0
  98. data/vendor/dry-cli/spec/support/fixtures/with_block.rb +86 -0
  99. data/vendor/dry-cli/spec/support/fixtures/with_registry.rb +90 -0
  100. data/vendor/dry-cli/spec/support/fixtures/with_zero_arity_block.rb +87 -0
  101. data/vendor/dry-cli/spec/support/helpers.rb +37 -0
  102. data/vendor/dry-cli/spec/support/path.rb +24 -0
  103. data/vendor/dry-cli/spec/support/rspec.rb +26 -0
  104. data/vendor/dry-cli/spec/support/rspec_options.rb +16 -0
  105. data/vendor/dry-cli/spec/support/shared_examples/commands.rb +300 -0
  106. data/vendor/dry-cli/spec/support/shared_examples/inherited_commands.rb +197 -0
  107. data/vendor/dry-cli/spec/support/shared_examples/rendering.rb +181 -0
  108. data/vendor/dry-cli/spec/support/shared_examples/subcommands.rb +226 -0
  109. data/vendor/dry-cli/spec/support/shared_examples/third_party_gems.rb +49 -0
  110. data/vendor/dry-cli/spec/support/warnings.rb +10 -0
  111. data/vendor/dry-cli/spec/unit/dry/cli/cli_spec.rb +123 -0
  112. data/vendor/dry-cli/spec/unit/dry/cli/inflector_spec.rb +26 -0
  113. data/vendor/dry-cli/spec/unit/dry/cli/registry_spec.rb +78 -0
  114. data/vendor/dry-cli/spec/unit/dry/cli/version_spec.rb +7 -0
  115. data/vendor/strings-ansi/CHANGELOG.md +24 -0
  116. data/vendor/strings-ansi/CODE_OF_CONDUCT.md +74 -0
  117. data/vendor/strings-ansi/Gemfile +11 -0
  118. data/{LICENSE.txt → vendor/strings-ansi/LICENSE.txt} +1 -1
  119. data/vendor/strings-ansi/README.md +155 -0
  120. data/vendor/strings-ansi/Rakefile +8 -0
  121. data/vendor/strings-ansi/appveyor.yml +32 -0
  122. data/vendor/strings-ansi/bin/console +14 -0
  123. data/vendor/strings-ansi/bin/setup +8 -0
  124. data/vendor/strings-ansi/lib/strings-ansi.rb +1 -0
  125. data/vendor/strings-ansi/lib/strings/ansi.rb +84 -0
  126. data/vendor/strings-ansi/lib/strings/ansi/extensions.rb +23 -0
  127. data/vendor/strings-ansi/lib/strings/ansi/version.rb +7 -0
  128. data/vendor/strings-ansi/spec/fixtures/ansi_codes.yaml +194 -0
  129. data/vendor/strings-ansi/spec/spec_helper.rb +51 -0
  130. data/vendor/strings-ansi/spec/unit/ansi_spec.rb +15 -0
  131. data/vendor/strings-ansi/spec/unit/extensions_spec.rb +19 -0
  132. data/vendor/strings-ansi/spec/unit/only_ansi_spec.rb +36 -0
  133. data/vendor/strings-ansi/spec/unit/sanitize_spec.rb +53 -0
  134. data/vendor/strings-ansi/strings-ansi.gemspec +34 -0
  135. data/vendor/strings-ansi/tasks/console.rake +11 -0
  136. data/vendor/strings-ansi/tasks/coverage.rake +11 -0
  137. data/vendor/strings-ansi/tasks/spec.rake +29 -0
  138. metadata +276 -190
  139. data/.github/workflows/main.yml +0 -24
  140. data/.gitignore +0 -43
  141. data/.rspec +0 -2
  142. data/.rubocop.yml +0 -87
  143. data/.travis.yml +0 -34
  144. data/Gemfile +0 -2
  145. data/Gemfile.base +0 -14
  146. data/Gemfile.base.lock +0 -172
  147. data/Gemfile.lock +0 -188
  148. data/Guardfile +0 -16
  149. data/Makefile +0 -12
  150. data/README.md +0 -92
  151. data/Rakefile +0 -27
  152. data/bin/bundle +0 -114
  153. data/bin/console +0 -29
  154. data/bin/guard +0 -29
  155. data/bin/rake +0 -29
  156. data/bin/rfix +0 -29
  157. data/bin/rspec +0 -29
  158. data/bin/setup +0 -29
  159. data/ci/Gemfile.rubocop-0.80 +0 -2
  160. data/ci/Gemfile.rubocop-0.80.lock +0 -170
  161. data/ci/Gemfile.rubocop-0.81 +0 -2
  162. data/ci/Gemfile.rubocop-0.81.lock +0 -170
  163. data/ci/Gemfile.rubocop-0.82 +0 -2
  164. data/ci/Gemfile.rubocop-0.82.lock +0 -170
  165. data/ci/Gemfile.rubocop-0.83 +0 -2
  166. data/ci/Gemfile.rubocop-0.83.lock +0 -168
  167. data/ci/Gemfile.rubocop-0.84 +0 -2
  168. data/ci/Gemfile.rubocop-0.84.lock +0 -171
  169. data/ci/Gemfile.rubocop-0.85 +0 -2
  170. data/ci/Gemfile.rubocop-0.85.1 +0 -2
  171. data/ci/Gemfile.rubocop-0.85.1.lock +0 -173
  172. data/ci/Gemfile.rubocop-0.85.lock +0 -173
  173. data/lib/rfix/box.rb +0 -112
  174. data/lib/rfix/branches/base.rb +0 -15
  175. data/lib/rfix/branches/head.rb +0 -13
  176. data/lib/rfix/branches/main.rb +0 -28
  177. data/lib/rfix/branches/name.rb +0 -23
  178. data/lib/rfix/branches/reference.rb +0 -21
  179. data/lib/rfix/branches/upstream.rb +0 -13
  180. data/lib/rfix/cmd.rb +0 -39
  181. data/lib/rfix/commands/branch.rb +0 -15
  182. data/lib/rfix/commands/extensions/options.rb +0 -8
  183. data/lib/rfix/commands/help.rb +0 -7
  184. data/lib/rfix/commands/helper/args.rb +0 -141
  185. data/lib/rfix/commands/helper/help.rb +0 -6
  186. data/lib/rfix/commands/helper/loader.rb +0 -6
  187. data/lib/rfix/commands/helper/option.rb +0 -0
  188. data/lib/rfix/commands/helper/params.rb +0 -0
  189. data/lib/rfix/commands/helper/rubocop.rb +0 -17
  190. data/lib/rfix/commands/info.rb +0 -30
  191. data/lib/rfix/commands/lint.rb +0 -22
  192. data/lib/rfix/commands/local.rb +0 -12
  193. data/lib/rfix/commands/origin.rb +0 -19
  194. data/lib/rfix/commands/setup.rb +0 -29
  195. data/lib/rfix/commands/welcome.rb +0 -24
  196. data/lib/rfix/deleted.rb +0 -13
  197. data/lib/rfix/extensions/extensions.rb +0 -18
  198. data/lib/rfix/extensions/offense.rb +0 -78
  199. data/lib/rfix/extensions/string.rb +0 -8
  200. data/lib/rfix/file_cache.rb +0 -59
  201. data/lib/rfix/git_helper.rb +0 -59
  202. data/lib/rfix/indentation.rb +0 -39
  203. data/lib/rfix/loader/bundler.rb +0 -37
  204. data/lib/rfix/loader/env.rb +0 -33
  205. data/lib/rfix/loader/spec.rb +0 -41
  206. data/lib/rfix/no_file.rb +0 -13
  207. data/lib/rfix/rfix.rb +0 -34
  208. data/lib/rfix/tracked.rb +0 -72
  209. data/lib/rfix/tracked_file.rb +0 -16
  210. data/lib/rfix/untracked.rb +0 -13
  211. data/resources/ps.png +0 -0
  212. data/tasks/bump.rake +0 -11
  213. data/tasks/bundle.rake +0 -17
  214. data/tasks/complex.rake +0 -54
  215. data/tasks/execute.rake +0 -38
  216. data/tasks/libgit2.rake +0 -33
  217. data/tasks/simple.rake +0 -62
  218. data/tasks/travis.rake +0 -74
  219. data/tasks/vendor.rake +0 -34
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ # General purpose Command Line Interface (CLI) framework for Ruby
5
+ #
6
+ # @since 0.1.0
7
+ class CLI
8
+ # @since 0.2.0
9
+ class Error < StandardError
10
+ end
11
+
12
+ # @since 0.2.1
13
+ class UnknownCommandError < Error
14
+ # @since 0.2.1
15
+ # @api private
16
+ def initialize(command_name)
17
+ super("unknown command: `#{command_name}'")
18
+ end
19
+ end
20
+
21
+ # @since 0.2.0
22
+ class InvalidCallbackError < Error
23
+ # @since 0.2.0
24
+ # @api private
25
+ def initialize(callback)
26
+ message = case callback
27
+ when Class
28
+ "expected `#{callback.inspect}' to respond to `#initialize' with arity 0"
29
+ else
30
+ "expected `#{callback.inspect}' to respond to `#call'"
31
+ end
32
+
33
+ super(message)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ class CLI
5
+ # @api private
6
+ # @since 0.5.0
7
+ module Inflector
8
+ # @api private
9
+ # @since 0.5.0
10
+ def self.dasherize(input)
11
+ return nil unless input
12
+
13
+ input.to_s.downcase.gsub(/[[[:space:]]_]/, "-")
14
+ end
15
+ end
16
+ end
17
+ 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
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ class CLI
5
+ # Command line option
6
+ #
7
+ # @since 0.1.0
8
+ # @api private
9
+ class Option
10
+ # @since 0.1.0
11
+ # @api private
12
+ attr_reader :name
13
+
14
+ # @since 0.1.0
15
+ # @api private
16
+ attr_reader :options
17
+
18
+ # @since 0.1.0
19
+ # @api private
20
+ def initialize(name, options = {})
21
+ @name = name
22
+ @options = options
23
+ end
24
+
25
+ # @since 0.1.0
26
+ # @api private
27
+ def aliases
28
+ options[:aliases] || []
29
+ end
30
+
31
+ # @since 0.1.0
32
+ # @api private
33
+ def desc
34
+ desc = options[:desc]
35
+ values ? "#{desc}: (#{values.join("/")})" : desc
36
+ end
37
+
38
+ # @since 0.1.0
39
+ # @api private
40
+ def required?
41
+ options[:required]
42
+ end
43
+
44
+ # @since 0.1.0
45
+ # @api private
46
+ def type
47
+ options[:type]
48
+ end
49
+
50
+ # @since 0.1.0
51
+ # @api private
52
+ def values
53
+ options[:values]
54
+ end
55
+
56
+ # @since 0.1.0
57
+ # @api private
58
+ def boolean?
59
+ type == :boolean
60
+ end
61
+
62
+ # @since 0.3.0
63
+ # @api private
64
+ def array?
65
+ type == :array
66
+ end
67
+
68
+ # @since 0.1.0
69
+ # @api private
70
+ def default
71
+ options[:default]
72
+ end
73
+
74
+ # @since 0.1.0
75
+ # @api private
76
+ def description_name
77
+ options[:label] || name.upcase
78
+ end
79
+
80
+ # @since 0.1.0
81
+ # @api private
82
+ def argument?
83
+ false
84
+ end
85
+
86
+ # @since 0.1.0
87
+ # @api private
88
+ #
89
+ def parser_options
90
+ dasherized_name = Inflector.dasherize(name)
91
+ parser_options = []
92
+
93
+ if boolean?
94
+ parser_options << "--[no-]#{dasherized_name}"
95
+ else
96
+ parser_options << "--#{dasherized_name}=#{name}"
97
+ parser_options << "--#{dasherized_name} #{name}"
98
+ end
99
+
100
+ parser_options << Array if array?
101
+ parser_options << values if values
102
+ parser_options.unshift(*alias_names) if aliases.any?
103
+ parser_options << desc if desc
104
+ parser_options
105
+ end
106
+
107
+ # @since 0.1.0
108
+ # @api private
109
+ def alias_names
110
+ aliases
111
+ .map { |name| name.gsub(/^-{1,2}/, "") }
112
+ .compact
113
+ .uniq
114
+ .map { |name| name.size == 1 ? "-#{name}" : "--#{name}" }
115
+ .map { |name| boolean? ? name : "#{name} VALUE" }
116
+ end
117
+ end
118
+
119
+ # Command line argument
120
+ #
121
+ # @since 0.1.0
122
+ # @api private
123
+ class Argument < Option
124
+ # @since 0.1.0
125
+ # @api private
126
+ def argument?
127
+ true
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "optparse"
4
+ require "dry/cli/program_name"
5
+
6
+ module Dry
7
+ class CLI
8
+ # Parse command line arguments and options
9
+ #
10
+ # @since 0.1.0
11
+ # @api private
12
+ module Parser
13
+ # @since 0.1.0
14
+ # @api private
15
+ #
16
+ def self.call(command, arguments, prog_name)
17
+ original_arguments = arguments.dup
18
+ parsed_options = {}
19
+
20
+ OptionParser.new do |opts|
21
+ command.options.each do |option|
22
+ opts.on(*option.parser_options) do |value|
23
+ parsed_options[option.name.to_sym] = value
24
+ end
25
+ end
26
+
27
+ opts.on_tail("-h", "--help") do
28
+ return Result.help
29
+ end
30
+ end.parse!(arguments)
31
+
32
+ parsed_options = command.default_params.merge(parsed_options)
33
+ parse_required_params(command, arguments, prog_name, parsed_options)
34
+ rescue ::OptionParser::ParseError
35
+ Result.failure("ERROR: \"#{prog_name}\" was called with arguments \"#{original_arguments.join(" ")}\"") # rubocop:disable Metrics/LineLength
36
+ end
37
+
38
+ # @since 0.1.0
39
+ # @api private
40
+ #
41
+ # rubocop:disable Metrics/AbcSize
42
+ def self.parse_required_params(command, arguments, prog_name, parsed_options)
43
+ parsed_params = match_arguments(command.arguments, arguments)
44
+ parsed_required_params = match_arguments(command.required_arguments, arguments)
45
+ all_required_params_satisfied = command.required_arguments.all? { |param| !parsed_required_params[param.name].nil? } # rubocop:disable Metrics/LineLength
46
+
47
+ unused_arguments = arguments.drop(command.required_arguments.length)
48
+
49
+ unless all_required_params_satisfied
50
+ parsed_required_params_values = parsed_required_params.values.compact
51
+
52
+ usage = "\nUsage: \"#{prog_name} #{command.required_arguments.map(&:description_name).join(" ")}" # rubocop:disable Metrics/LineLength
53
+
54
+ usage += " | #{prog_name} SUBCOMMAND" if command.subcommands.any?
55
+
56
+ usage += '"'
57
+
58
+ if parsed_required_params_values.empty?
59
+ return Result.failure("ERROR: \"#{prog_name}\" was called with no arguments#{usage}")
60
+ else
61
+ return Result.failure("ERROR: \"#{prog_name}\" was called with arguments #{parsed_required_params_values}#{usage}") # rubocop:disable Metrics/LineLength
62
+ end
63
+ end
64
+
65
+ parsed_params.reject! { |_key, value| value.nil? }
66
+ parsed_options = parsed_options.merge(parsed_params)
67
+ parsed_options = parsed_options.merge(args: unused_arguments) if unused_arguments.any?
68
+ Result.success(parsed_options)
69
+ end
70
+ # rubocop:enable Metrics/AbcSize
71
+
72
+ def self.match_arguments(command_arguments, arguments)
73
+ result = {}
74
+
75
+ command_arguments.each_with_index do |cmd_arg, index|
76
+ if cmd_arg.array?
77
+ result[cmd_arg.name] = arguments[index..-1]
78
+ break
79
+ else
80
+ result[cmd_arg.name] = arguments.at(index)
81
+ end
82
+ end
83
+
84
+ result
85
+ end
86
+
87
+ # @since 0.1.0
88
+ # @api private
89
+ class Result
90
+ # @since 0.1.0
91
+ # @api private
92
+ def self.help
93
+ new(help: true)
94
+ end
95
+
96
+ # @since 0.1.0
97
+ # @api private
98
+ def self.success(arguments = {})
99
+ new(arguments: arguments)
100
+ end
101
+
102
+ # @since 0.1.0
103
+ # @api private
104
+ def self.failure(error = "Error: Invalid param provided")
105
+ new(error: error)
106
+ end
107
+
108
+ # @since 0.1.0
109
+ # @api private
110
+ attr_reader :arguments
111
+
112
+ # @since 0.1.0
113
+ # @api private
114
+ attr_reader :error
115
+
116
+ # @since 0.1.0
117
+ # @api private
118
+ def initialize(arguments: {}, error: nil, help: false)
119
+ @arguments = arguments
120
+ @error = error
121
+ @help = help
122
+ end
123
+
124
+ # @since 0.1.0
125
+ # @api private
126
+ def error?
127
+ !error.nil?
128
+ end
129
+
130
+ # @since 0.1.0
131
+ # @api private
132
+ def help?
133
+ @help
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ class CLI
5
+ # Program name
6
+ #
7
+ # @since 0.1.0
8
+ # @api private
9
+ module ProgramName
10
+ # @since 0.1.0
11
+ # @api private
12
+ SEPARATOR = " "
13
+
14
+ # @since 0.1.0
15
+ # @api private
16
+ def self.call(names = [], program_name: $PROGRAM_NAME)
17
+ [File.basename(program_name), names].flatten.join(SEPARATOR)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,338 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/cli/command_registry"
4
+
5
+ module Dry
6
+ class CLI
7
+ # Registry mixin
8
+ #
9
+ # @since 0.1.0
10
+ module Registry
11
+ # @since 0.1.0
12
+ # @api private
13
+ def self.extended(base)
14
+ base.class_eval do
15
+ @_mutex = Mutex.new
16
+ @commands = CommandRegistry.new
17
+ end
18
+ end
19
+
20
+ # Register a command
21
+ #
22
+ # @param name [String] the command name
23
+ # @param command [NilClass,Dry::CLI::Command] the optional command
24
+ # @param aliases [Array<String>] an optional list of aliases
25
+ # @param options [Hash] a set of options
26
+ #
27
+ # @since 0.1.0
28
+ #
29
+ # @example Register a command
30
+ # require "dry/cli"
31
+ #
32
+ # module Foo
33
+ # module Commands
34
+ # extend Dry::CLI::Registry
35
+ #
36
+ # class Hello < Dry::CLI::Command
37
+ # end
38
+ #
39
+ # register "hi", Hello
40
+ # end
41
+ # end
42
+ #
43
+ # @example Register a command with aliases
44
+ # require "dry/cli"
45
+ #
46
+ # module Foo
47
+ # module Commands
48
+ # extend Dry::CLI::Registry
49
+ #
50
+ # class Hello < Dry::CLI::Command
51
+ # end
52
+ #
53
+ # register "hello", Hello, aliases: ["hi", "ciao"]
54
+ # end
55
+ # end
56
+ #
57
+ # @example Register a group of commands
58
+ # require "dry/cli"
59
+ #
60
+ # module Foo
61
+ # module Commands
62
+ # extend Dry::CLI::Registry
63
+ #
64
+ # module Generate
65
+ # class App < Dry::CLI::Command
66
+ # end
67
+ #
68
+ # class Action < Dry::CLI::Command
69
+ # end
70
+ # end
71
+ #
72
+ # register "generate", aliases: ["g"] do |prefix|
73
+ # prefix.register "app", Generate::App
74
+ # prefix.register "action", Generate::Action
75
+ # end
76
+ # end
77
+ # end
78
+ def register(name, command = nil, aliases: [], &block)
79
+ @commands.set(name, command, aliases)
80
+
81
+ if block_given?
82
+ prefix = Prefix.new(@commands, name, aliases)
83
+ if block.arity.zero?
84
+ prefix.instance_eval(&block)
85
+ else
86
+ yield(prefix)
87
+ end
88
+ end
89
+ end
90
+
91
+ # Register a before callback.
92
+ #
93
+ # @param command_name [String] the name used for command registration
94
+ # @param callback [Class, #call] the callback object. If a class is given,
95
+ # it MUST respond to `#call`.
96
+ # @param blk [Proc] the callback espressed as a block
97
+ #
98
+ # @raise [Dry::CLI::UnknownCommandError] if the command isn't registered
99
+ # @raise [Dry::CLI::InvalidCallbackError] if the given callback doesn't
100
+ # implement the required interface
101
+ #
102
+ # @since 0.2.0
103
+ #
104
+ # @example
105
+ # require "dry/cli"
106
+ #
107
+ # module Foo
108
+ # module Commands
109
+ # extend Dry::CLI::Registry
110
+ #
111
+ # class Hello < Dry::CLI::Command
112
+ # def call(*)
113
+ # puts "hello"
114
+ # end
115
+ # end
116
+ #
117
+ # register "hello", Hello
118
+ # before "hello", -> { puts "I'm about to say.." }
119
+ # end
120
+ # end
121
+ #
122
+ # @example Register an object as callback
123
+ # require "dry/cli"
124
+ #
125
+ # module Callbacks
126
+ # class Hello
127
+ # def call(*)
128
+ # puts "world"
129
+ # end
130
+ # end
131
+ # end
132
+ #
133
+ # module Foo
134
+ # module Commands
135
+ # extend Dry::CLI::Registry
136
+ #
137
+ # class Hello < Dry::CLI::Command
138
+ # def call(*)
139
+ # puts "I'm about to say.."
140
+ # end
141
+ # end
142
+ #
143
+ # register "hello", Hello
144
+ # before "hello", Callbacks::Hello.new
145
+ # end
146
+ # end
147
+ #
148
+ # @example Register a class as callback
149
+ # require "dry/cli"
150
+ #
151
+ # module Callbacks
152
+ # class Hello
153
+ # def call(*)
154
+ # puts "world"
155
+ # end
156
+ # end
157
+ # end
158
+ #
159
+ # module Foo
160
+ # module Commands
161
+ # extend Dry::CLI::Registry
162
+ #
163
+ # class Hello < Dry::CLI::Command
164
+ # def call(*)
165
+ # puts "I'm about to say.."
166
+ # end
167
+ # end
168
+ #
169
+ # register "hello", Hello
170
+ # before "hello", Callbacks::Hello
171
+ # end
172
+ # end
173
+ def before(command_name, callback = nil, &blk)
174
+ @_mutex.synchronize do
175
+ command(command_name).before_callbacks.append(&_callback(callback, blk))
176
+ end
177
+ end
178
+
179
+ # Register an after callback.
180
+ #
181
+ # @param command_name [String] the name used for command registration
182
+ # @param callback [Class, #call] the callback object. If a class is given,
183
+ # it MUST respond to `#call`.
184
+ # @param blk [Proc] the callback espressed as a block
185
+ #
186
+ # @raise [Dry::CLI::UnknownCommandError] if the command isn't registered
187
+ # @raise [Dry::CLI::InvalidCallbackError] if the given callback doesn't
188
+ # implement the required interface
189
+ #
190
+ # @since 0.2.0
191
+ #
192
+ # @example
193
+ # require "dry/cli"
194
+ #
195
+ # module Foo
196
+ # module Commands
197
+ # extend Dry::CLI::Registry
198
+ #
199
+ # class Hello < Dry::CLI::Command
200
+ # def call(*)
201
+ # puts "hello"
202
+ # end
203
+ # end
204
+ #
205
+ # register "hello", Hello
206
+ # after "hello", -> { puts "world" }
207
+ # end
208
+ # end
209
+ #
210
+ # @example Register an object as callback
211
+ # require "dry/cli"
212
+ #
213
+ # module Callbacks
214
+ # class World
215
+ # def call(*)
216
+ # puts "world"
217
+ # end
218
+ # end
219
+ # end
220
+ #
221
+ # module Foo
222
+ # module Commands
223
+ # extend Dry::CLI::Registry
224
+ #
225
+ # class Hello < Dry::CLI::Command
226
+ # def call(*)
227
+ # puts "hello"
228
+ # end
229
+ # end
230
+ #
231
+ # register "hello", Hello
232
+ # after "hello", Callbacks::World.new
233
+ # end
234
+ # end
235
+ #
236
+ # @example Register a class as callback
237
+ # require "dry/cli"
238
+ #
239
+ # module Callbacks
240
+ # class World
241
+ # def call(*)
242
+ # puts "world"
243
+ # end
244
+ # end
245
+ # end
246
+ #
247
+ # module Foo
248
+ # module Commands
249
+ # extend Dry::CLI::Registry
250
+ #
251
+ # class Hello < Dry::CLI::Command
252
+ # def call(*)
253
+ # puts "hello"
254
+ # end
255
+ # end
256
+ #
257
+ # register "hello", Hello
258
+ # after "hello", Callbacks::World
259
+ # end
260
+ # end
261
+ def after(command_name, callback = nil, &blk)
262
+ @_mutex.synchronize do
263
+ command(command_name).after_callbacks.append(&_callback(callback, blk))
264
+ end
265
+ end
266
+
267
+ # @since 0.1.0
268
+ # @api private
269
+ def get(arguments)
270
+ @commands.get(arguments)
271
+ end
272
+
273
+ private
274
+
275
+ COMMAND_NAME_SEPARATOR = " "
276
+
277
+ # @since 0.2.0
278
+ # @api private
279
+ def command(command_name)
280
+ get(command_name.split(COMMAND_NAME_SEPARATOR)).tap do |result|
281
+ raise UnknownCommandError, command_name unless result.found?
282
+ end
283
+ end
284
+
285
+ # @since 0.2.0
286
+ # @api private
287
+ #
288
+ def _callback(callback, blk)
289
+ return blk if blk.respond_to?(:to_proc)
290
+
291
+ case callback
292
+ when ->(c) { c.respond_to?(:call) }
293
+ callback.method(:call)
294
+ when Class
295
+ begin
296
+ _callback(callback.new, blk)
297
+ rescue ArgumentError
298
+ raise InvalidCallbackError, callback
299
+ end
300
+ else
301
+ raise InvalidCallbackError, callback
302
+ end
303
+ end
304
+
305
+ # Command name prefix
306
+ #
307
+ # @since 0.1.0
308
+ class Prefix
309
+ # @since 0.1.0
310
+ # @api private
311
+ def initialize(registry, prefix, aliases)
312
+ @registry = registry
313
+ @prefix = prefix
314
+
315
+ registry.set(prefix, nil, aliases)
316
+ end
317
+
318
+ # @since 0.1.0
319
+ #
320
+ # @see Dry::CLI::Registry#register
321
+ def register(name, command, aliases: [])
322
+ command_name = "#{prefix} #{name}"
323
+ registry.set(command_name, command, aliases)
324
+ end
325
+
326
+ private
327
+
328
+ # @since 0.1.0
329
+ # @api private
330
+ attr_reader :registry
331
+
332
+ # @since 0.1.0
333
+ # @api private
334
+ attr_reader :prefix
335
+ end
336
+ end
337
+ end
338
+ end