hanami-cli 1.0.0.alpha1 → 2.0.0.alpha2

Sign up to get free protection for your applications and to get access to all the features.
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