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.
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 +61 -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 +114 -164
  41. data/lib/rfix/types.rb +52 -0
  42. data/lib/rfix/version.rb +1 -1
  43. data/rfix.gemspec +28 -38
  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 +274 -188
  139. data/.github/workflows/main.yml +0 -26
  140. data/.gitignore +0 -43
  141. data/.rspec +0 -2
  142. data/.rubocop.yml +0 -87
  143. data/.travis.yml +0 -35
  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 -85
  151. data/Rakefile +0 -31
  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