hanami-cli 1.0.0.alpha1 → 2.0.0.alpha2

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 (101) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +42 -0
  3. data/.gitignore +4 -2
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +24 -0
  6. data/CHANGELOG.md +14 -1
  7. data/CODE_OF_CONDUCT.md +84 -0
  8. data/Gemfile +8 -2
  9. data/LICENSE.txt +21 -0
  10. data/README.md +12 -605
  11. data/Rakefile +5 -10
  12. data/exe/hanami +10 -0
  13. data/hanami-cli.gemspec +21 -17
  14. data/lib/hanami/cli.rb +9 -122
  15. data/lib/hanami/cli/bundler.rb +73 -0
  16. data/lib/hanami/cli/command.rb +14 -386
  17. data/lib/hanami/cli/command_line.rb +17 -0
  18. data/lib/hanami/cli/commands.rb +26 -0
  19. data/lib/hanami/cli/commands/application.rb +63 -0
  20. data/lib/hanami/cli/commands/db/utils/database.rb +122 -0
  21. data/lib/hanami/cli/commands/db/utils/database_config.rb +48 -0
  22. data/lib/hanami/cli/commands/db/utils/mysql.rb +27 -0
  23. data/lib/hanami/cli/commands/db/utils/postgres.rb +49 -0
  24. data/lib/hanami/cli/commands/db/utils/sqlite.rb +37 -0
  25. data/lib/hanami/cli/commands/gem.rb +21 -0
  26. data/lib/hanami/cli/commands/gem/new.rb +77 -0
  27. data/lib/hanami/cli/commands/gem/version.rb +18 -0
  28. data/lib/hanami/cli/commands/monolith.rb +55 -0
  29. data/lib/hanami/cli/commands/monolith/console.rb +50 -0
  30. data/lib/hanami/cli/commands/monolith/db/create.rb +25 -0
  31. data/lib/hanami/cli/commands/monolith/db/create_migration.rb +29 -0
  32. data/lib/hanami/cli/commands/monolith/db/drop.rb +25 -0
  33. data/lib/hanami/cli/commands/monolith/db/migrate.rb +40 -0
  34. data/lib/hanami/cli/commands/monolith/db/reset.rb +26 -0
  35. data/lib/hanami/cli/commands/monolith/db/rollback.rb +55 -0
  36. data/lib/hanami/cli/commands/monolith/db/sample_data.rb +40 -0
  37. data/lib/hanami/cli/commands/monolith/db/seed.rb +40 -0
  38. data/lib/hanami/cli/commands/monolith/db/setup.rb +24 -0
  39. data/lib/hanami/cli/commands/monolith/db/structure/dump.rb +25 -0
  40. data/lib/hanami/cli/commands/monolith/db/version.rb +26 -0
  41. data/lib/hanami/cli/commands/monolith/generate.rb +14 -0
  42. data/lib/hanami/cli/commands/monolith/generate/action.rb +62 -0
  43. data/lib/hanami/cli/commands/monolith/generate/slice.rb +62 -0
  44. data/lib/hanami/cli/commands/monolith/install.rb +16 -0
  45. data/lib/hanami/cli/commands/monolith/version.rb +18 -0
  46. data/lib/hanami/cli/error.rb +8 -0
  47. data/lib/hanami/cli/generators/context.rb +38 -0
  48. data/lib/hanami/cli/generators/gem/application.rb +21 -0
  49. data/lib/hanami/cli/generators/gem/application/monolith.rb +83 -0
  50. data/lib/hanami/cli/generators/gem/application/monolith/action.erb +21 -0
  51. data/lib/hanami/cli/generators/gem/application/monolith/application.erb +8 -0
  52. data/lib/hanami/cli/generators/gem/application/monolith/config_ru.erb +5 -0
  53. data/lib/hanami/cli/generators/gem/application/monolith/entities.erb +9 -0
  54. data/lib/hanami/cli/generators/gem/application/monolith/env.erb +0 -0
  55. data/lib/hanami/cli/generators/gem/application/monolith/functions.erb +13 -0
  56. data/lib/hanami/cli/generators/gem/application/monolith/gemfile.erb +19 -0
  57. data/lib/hanami/cli/generators/gem/application/monolith/keep.erb +0 -0
  58. data/lib/hanami/cli/generators/gem/application/monolith/operation.erb +18 -0
  59. data/lib/hanami/cli/generators/gem/application/monolith/rakefile.erb +3 -0
  60. data/lib/hanami/cli/generators/gem/application/monolith/readme.erb +1 -0
  61. data/lib/hanami/cli/generators/gem/application/monolith/repository.erb +13 -0
  62. data/lib/hanami/cli/generators/gem/application/monolith/routes.erb +4 -0
  63. data/lib/hanami/cli/generators/gem/application/monolith/settings.erb +6 -0
  64. data/lib/hanami/cli/generators/gem/application/monolith/types.erb +10 -0
  65. data/lib/hanami/cli/generators/gem/application/monolith/validation_contract.erb +14 -0
  66. data/lib/hanami/cli/generators/gem/application/monolith/view_context.erb +15 -0
  67. data/lib/hanami/cli/generators/monolith/action.rb +123 -0
  68. data/lib/hanami/cli/generators/monolith/action/action.erb +13 -0
  69. data/lib/hanami/cli/generators/monolith/action/template.erb +0 -0
  70. data/lib/hanami/cli/generators/monolith/action/template.html.erb +2 -0
  71. data/lib/hanami/cli/generators/monolith/action/view.erb +13 -0
  72. data/lib/hanami/cli/generators/monolith/action_context.rb +76 -0
  73. data/lib/hanami/cli/generators/monolith/slice.rb +56 -0
  74. data/lib/hanami/cli/generators/monolith/slice/action.erb +9 -0
  75. data/lib/hanami/cli/generators/monolith/slice/entities.erb +9 -0
  76. data/lib/hanami/cli/generators/monolith/slice/keep.erb +0 -0
  77. data/lib/hanami/cli/generators/monolith/slice/repository.erb +10 -0
  78. data/lib/hanami/cli/generators/monolith/slice/routes.erb +2 -0
  79. data/lib/hanami/cli/generators/monolith/slice/view.erb +9 -0
  80. data/lib/hanami/cli/generators/monolith/slice_context.rb +33 -0
  81. data/lib/hanami/cli/repl/core.rb +55 -0
  82. data/lib/hanami/cli/repl/irb.rb +41 -0
  83. data/lib/hanami/cli/repl/pry.rb +29 -0
  84. data/lib/hanami/cli/system_call.rb +51 -0
  85. data/lib/hanami/cli/url.rb +34 -0
  86. data/lib/hanami/cli/version.rb +2 -3
  87. data/lib/hanami/console/context.rb +39 -0
  88. data/lib/hanami/console/plugins/slice_readers.rb +42 -0
  89. data/lib/hanami/rake_tasks.rb +52 -0
  90. metadata +134 -43
  91. data/.circleci/config.yml +0 -63
  92. data/.travis.yml +0 -22
  93. data/lib/hanami/cli/banner.rb +0 -129
  94. data/lib/hanami/cli/command_registry.rb +0 -215
  95. data/lib/hanami/cli/errors.rb +0 -46
  96. data/lib/hanami/cli/option.rb +0 -134
  97. data/lib/hanami/cli/parser.rb +0 -144
  98. data/lib/hanami/cli/program_name.rb +0 -21
  99. data/lib/hanami/cli/registry.rb +0 -330
  100. data/lib/hanami/cli/usage.rb +0 -91
  101. data/script/ci +0 -61
@@ -1,134 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "hanami/utils/string"
4
-
5
- module Hanami
6
- class CLI
7
- # Command line option
8
- #
9
- # @since 0.1.0
10
- # @api private
11
- class Option
12
- # @since 0.1.0
13
- # @api private
14
- attr_reader :name
15
-
16
- # @since 0.1.0
17
- # @api private
18
- attr_reader :options
19
-
20
- # @since 0.1.0
21
- # @api private
22
- def initialize(name, options = {})
23
- @name = name
24
- @options = options
25
- end
26
-
27
- # @since 0.1.0
28
- # @api private
29
- def aliases
30
- options[:aliases] || []
31
- end
32
-
33
- # @since 0.1.0
34
- # @api private
35
- def desc
36
- desc = options[:desc]
37
- values ? "#{desc}: (#{values.join('/')})" : desc
38
- end
39
-
40
- # @since 0.1.0
41
- # @api private
42
- def required?
43
- options[:required]
44
- end
45
-
46
- # @since 0.1.0
47
- # @api private
48
- def type
49
- options[:type]
50
- end
51
-
52
- # @since 0.1.0
53
- # @api private
54
- def values
55
- options[:values]
56
- end
57
-
58
- # @since 0.1.0
59
- # @api private
60
- def boolean?
61
- type == :boolean
62
- end
63
-
64
- # @since 0.3.0
65
- # @api private
66
- def array?
67
- type == :array
68
- end
69
-
70
- # @since 0.1.0
71
- # @api private
72
- def default
73
- options[:default]
74
- end
75
-
76
- # @since 0.1.0
77
- # @api private
78
- def description_name
79
- options[:label] || name.upcase
80
- end
81
-
82
- # @since 0.1.0
83
- # @api private
84
- def argument?
85
- false
86
- end
87
-
88
- # @since 0.1.0
89
- # @api private
90
- #
91
- # rubocop:disable Metrics/AbcSize
92
- # rubocop:disable Metrics/MethodLength
93
- def parser_options
94
- dasherized_name = Hanami::Utils::String.dasherize(name)
95
- parser_options = []
96
-
97
- if boolean?
98
- parser_options << "--[no-]#{dasherized_name}"
99
- else
100
- parser_options << "--#{dasherized_name}=#{name}"
101
- parser_options << "--#{dasherized_name} #{name}"
102
- end
103
-
104
- parser_options << Array if array?
105
- parser_options << values if values
106
- parser_options.unshift(alias_name) unless alias_name.nil?
107
- parser_options << desc if desc
108
- parser_options
109
- end
110
- # rubocop:enable Metrics/MethodLength
111
- # rubocop:enable Metrics/AbcSize
112
-
113
- private
114
-
115
- # @since 0.1.0
116
- # @api private
117
- def alias_name
118
- aliases.join(" ") if aliases.any?
119
- end
120
- end
121
-
122
- # Command line argument
123
- #
124
- # @since 0.1.0
125
- # @api private
126
- class Argument < Option
127
- # @since 0.1.0
128
- # @api private
129
- def argument?
130
- true
131
- end
132
- end
133
- end
134
- end
@@ -1,144 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "optparse"
4
- require "hanami/cli/program_name"
5
-
6
- module Hanami
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
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
17
- def self.call(command, arguments, names)
18
- original_arguments = arguments.dup
19
- parsed_options = {}
20
-
21
- OptionParser.new do |opts|
22
- command.options.each do |option|
23
- opts.on(*option.parser_options) do |value|
24
- parsed_options[option.name.to_sym] = value
25
- end
26
- end
27
-
28
- opts.on_tail("-h", "--help") do
29
- return Result.help
30
- end
31
- end.parse!(arguments)
32
-
33
- parsed_options = command.default_params.merge(parsed_options)
34
- parse_required_params(command, arguments, names, parsed_options)
35
- rescue ::OptionParser::ParseError
36
- Result.failure("Error: \"#{command.command_name}\" was called with arguments \"#{original_arguments.join(' ')}\"")
37
- end
38
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
39
-
40
- # @since 0.1.0
41
- # @api private
42
- def self.full_command_name(names)
43
- ProgramName.call(names)
44
- end
45
-
46
- # @since 0.1.0
47
- # @api private
48
- #
49
- # rubocop:disable Metrics/AbcSize
50
- # rubocop:disable Metrics/MethodLength
51
- def self.parse_required_params(command, arguments, names, parsed_options)
52
- parsed_params = match_arguments(command.arguments, arguments)
53
- parsed_required_params = match_arguments(command.required_arguments, arguments)
54
- all_required_params_satisfied = command.required_arguments.all? { |param| !parsed_required_params[param.name].nil? }
55
-
56
- unused_arguments = arguments.drop(command.required_arguments.length)
57
-
58
- unless all_required_params_satisfied
59
- parsed_required_params_values = parsed_required_params.values.compact
60
-
61
- usage = "\nUsage: \"#{full_command_name(names)} #{command.required_arguments.map(&:description_name).join(' ')}\""
62
-
63
- if parsed_required_params_values.empty? # rubocop:disable Style/GuardClause
64
- return Result.failure("ERROR: \"#{full_command_name(names)}\" was called with no arguments#{usage}")
65
- else
66
- return Result.failure("ERROR: \"#{full_command_name(names)}\" was called with arguments #{parsed_required_params_values}#{usage}")
67
- end
68
- end
69
-
70
- parsed_params.reject! { |_key, value| value.nil? }
71
- parsed_options = parsed_options.merge(parsed_params)
72
- parsed_options = parsed_options.merge(args: unused_arguments) if unused_arguments.any?
73
- Result.success(parsed_options)
74
- end
75
- # rubocop:enable Metrics/MethodLength
76
- # rubocop:enable Metrics/AbcSize
77
-
78
- def self.match_arguments(command_arguments, arguments)
79
- result = {}
80
-
81
- command_arguments.each_with_index do |cmd_arg, index|
82
- if cmd_arg.array?
83
- result[cmd_arg.name] = arguments[index..-1]
84
- break
85
- else
86
- result[cmd_arg.name] = arguments.at(index)
87
- end
88
- end
89
-
90
- result
91
- end
92
-
93
- # @since 0.1.0
94
- # @api private
95
- class Result
96
- # @since 0.1.0
97
- # @api private
98
- def self.help
99
- new(help: true)
100
- end
101
-
102
- # @since 0.1.0
103
- # @api private
104
- def self.success(arguments = {})
105
- new(arguments: arguments)
106
- end
107
-
108
- # @since 0.1.0
109
- # @api private
110
- def self.failure(error = "Error: Invalid param provided")
111
- new(error: error)
112
- end
113
-
114
- # @since 0.1.0
115
- # @api private
116
- attr_reader :arguments
117
-
118
- # @since 0.1.0
119
- # @api private
120
- attr_reader :error
121
-
122
- # @since 0.1.0
123
- # @api private
124
- def initialize(arguments: {}, error: nil, help: false)
125
- @arguments = arguments
126
- @error = error
127
- @help = help
128
- end
129
-
130
- # @since 0.1.0
131
- # @api private
132
- def error?
133
- !error.nil?
134
- end
135
-
136
- # @since 0.1.0
137
- # @api private
138
- def help?
139
- @help
140
- end
141
- end
142
- end
143
- end
144
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Hanami
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
@@ -1,330 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "hanami/cli/command_registry"
4
-
5
- module Hanami
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
- @commands = CommandRegistry.new
16
- end
17
- end
18
-
19
- # Register a command
20
- #
21
- # @param name [String] the command name
22
- # @param command [NilClass,Hanami::CLI::Command] the optional command
23
- # @param aliases [Array<String>] an optional list of aliases
24
- # @param options [Hash] a set of options
25
- #
26
- # @since 0.1.0
27
- #
28
- # @example Register a command
29
- # require "hanami/cli"
30
- #
31
- # module Foo
32
- # module Commands
33
- # extend Hanami::CLI::Registry
34
- #
35
- # class Hello < Hanami::CLI::Command
36
- # end
37
- #
38
- # register "hi", Hello
39
- # end
40
- # end
41
- #
42
- # @example Register a command with aliases
43
- # require "hanami/cli"
44
- #
45
- # module Foo
46
- # module Commands
47
- # extend Hanami::CLI::Registry
48
- #
49
- # class Hello < Hanami::CLI::Command
50
- # end
51
- #
52
- # register "hello", Hello, aliases: ["hi", "ciao"]
53
- # end
54
- # end
55
- #
56
- # @example Register a group of commands
57
- # require "hanami/cli"
58
- #
59
- # module Foo
60
- # module Commands
61
- # extend Hanami::CLI::Registry
62
- #
63
- # module Generate
64
- # class App < Hanami::CLI::Command
65
- # end
66
- #
67
- # class Action < Hanami::CLI::Command
68
- # end
69
- # end
70
- #
71
- # register "generate", aliases: ["g"] do |prefix|
72
- # prefix.register "app", Generate::App
73
- # prefix.register "action", Generate::Action
74
- # end
75
- # end
76
- # end
77
- def register(name, command = nil, aliases: [], **options)
78
- if block_given?
79
- yield Prefix.new(@commands, name, aliases)
80
- else
81
- @commands.set(name, command, aliases, **options)
82
- end
83
- end
84
-
85
- # Register a before callback.
86
- #
87
- # @param command_name [String] the name used for command registration
88
- # @param callback [Class, #call] the callback object. If a class is given,
89
- # it MUST respond to `#call`.
90
- # @param blk [Proc] the callback espressed as a block
91
- #
92
- # @raise [Hanami::CLI::UnknownCommandError] if the command isn't registered
93
- # @raise [Hanami::CLI::InvalidCallbackError] if the given callback doesn't
94
- # implement the required interface
95
- #
96
- # @since 0.2.0
97
- #
98
- # @example
99
- # require "hanami/cli"
100
- #
101
- # module Foo
102
- # module Commands
103
- # extend Hanami::CLI::Registry
104
- #
105
- # class Hello < Hanami::CLI::Command
106
- # def call(*)
107
- # puts "hello"
108
- # end
109
- # end
110
- #
111
- # register "hello", Hello
112
- # before "hello", -> { puts "I'm about to say.." }
113
- # end
114
- # end
115
- #
116
- # @example Register an object as callback
117
- # require "hanami/cli"
118
- #
119
- # module Callbacks
120
- # class Hello
121
- # def call(*)
122
- # puts "world"
123
- # end
124
- # end
125
- # end
126
- #
127
- # module Foo
128
- # module Commands
129
- # extend Hanami::CLI::Registry
130
- #
131
- # class Hello < Hanami::CLI::Command
132
- # def call(*)
133
- # puts "I'm about to say.."
134
- # end
135
- # end
136
- #
137
- # register "hello", Hello
138
- # before "hello", Callbacks::Hello.new
139
- # end
140
- # end
141
- #
142
- # @example Register a class as callback
143
- # require "hanami/cli"
144
- #
145
- # module Callbacks
146
- # class Hello
147
- # def call(*)
148
- # puts "world"
149
- # end
150
- # end
151
- # end
152
- #
153
- # module Foo
154
- # module Commands
155
- # extend Hanami::CLI::Registry
156
- #
157
- # class Hello < Hanami::CLI::Command
158
- # def call(*)
159
- # puts "I'm about to say.."
160
- # end
161
- # end
162
- #
163
- # register "hello", Hello
164
- # before "hello", Callbacks::Hello
165
- # end
166
- # end
167
- def before(command_name, callback = nil, &blk)
168
- command(command_name).before_callbacks.append(&_callback(callback, blk))
169
- end
170
-
171
- # Register an after callback.
172
- #
173
- # @param command_name [String] the name used for command registration
174
- # @param callback [Class, #call] the callback object. If a class is given,
175
- # it MUST respond to `#call`.
176
- # @param blk [Proc] the callback espressed as a block
177
- #
178
- # @raise [Hanami::CLI::UnknownCommandError] if the command isn't registered
179
- # @raise [Hanami::CLI::InvalidCallbackError] if the given callback doesn't
180
- # implement the required interface
181
- #
182
- # @since 0.2.0
183
- #
184
- # @example
185
- # require "hanami/cli"
186
- #
187
- # module Foo
188
- # module Commands
189
- # extend Hanami::CLI::Registry
190
- #
191
- # class Hello < Hanami::CLI::Command
192
- # def call(*)
193
- # puts "hello"
194
- # end
195
- # end
196
- #
197
- # register "hello", Hello
198
- # after "hello", -> { puts "world" }
199
- # end
200
- # end
201
- #
202
- # @example Register an object as callback
203
- # require "hanami/cli"
204
- #
205
- # module Callbacks
206
- # class World
207
- # def call(*)
208
- # puts "world"
209
- # end
210
- # end
211
- # end
212
- #
213
- # module Foo
214
- # module Commands
215
- # extend Hanami::CLI::Registry
216
- #
217
- # class Hello < Hanami::CLI::Command
218
- # def call(*)
219
- # puts "hello"
220
- # end
221
- # end
222
- #
223
- # register "hello", Hello
224
- # after "hello", Callbacks::World.new
225
- # end
226
- # end
227
- #
228
- # @example Register a class as callback
229
- # require "hanami/cli"
230
- #
231
- # module Callbacks
232
- # class World
233
- # def call(*)
234
- # puts "world"
235
- # end
236
- # end
237
- # end
238
- #
239
- # module Foo
240
- # module Commands
241
- # extend Hanami::CLI::Registry
242
- #
243
- # class Hello < Hanami::CLI::Command
244
- # def call(*)
245
- # puts "hello"
246
- # end
247
- # end
248
- #
249
- # register "hello", Hello
250
- # after "hello", Callbacks::World
251
- # end
252
- # end
253
- def after(command_name, callback = nil, &blk)
254
- command(command_name).after_callbacks.append(&_callback(callback, blk))
255
- end
256
-
257
- # @since 0.1.0
258
- # @api private
259
- def get(arguments)
260
- @commands.get(arguments)
261
- end
262
-
263
- private
264
-
265
- COMMAND_NAME_SEPARATOR = " "
266
-
267
- # @since 0.2.0
268
- # @api private
269
- def command(command_name)
270
- get(command_name.split(COMMAND_NAME_SEPARATOR)).tap do |result|
271
- raise UnknownCommandError.new(command_name) unless result.found?
272
- end
273
- end
274
-
275
- # @since 0.2.0
276
- # @api private
277
- #
278
- # rubocop:disable Metrics/MethodLength
279
- def _callback(callback, blk)
280
- return blk if blk.respond_to?(:to_proc)
281
-
282
- case callback
283
- when ->(c) { c.respond_to?(:call) }
284
- callback.method(:call)
285
- when Class
286
- begin
287
- _callback(callback.new, blk)
288
- rescue ArgumentError
289
- raise InvalidCallbackError.new(callback)
290
- end
291
- else
292
- raise InvalidCallbackError.new(callback)
293
- end
294
- end
295
- # rubocop:enable Metrics/MethodLength
296
-
297
- # Command name prefix
298
- #
299
- # @since 0.1.0
300
- class Prefix
301
- # @since 0.1.0
302
- # @api private
303
- def initialize(registry, prefix, aliases)
304
- @registry = registry
305
- @prefix = prefix
306
-
307
- registry.set(prefix, nil, aliases)
308
- end
309
-
310
- # @since 0.1.0
311
- #
312
- # @see Hanami::CLI::Registry#register
313
- def register(name, command, aliases: [], **options)
314
- command_name = "#{prefix} #{name}"
315
- registry.set(command_name, command, aliases, **options)
316
- end
317
-
318
- private
319
-
320
- # @since 0.1.0
321
- # @api private
322
- attr_reader :registry
323
-
324
- # @since 0.1.0
325
- # @api private
326
- attr_reader :prefix
327
- end
328
- end
329
- end
330
- end