hanami-cli 2.3.5 → 3.0.0.rc1

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +38 -5
  3. data/README.md +6 -1
  4. data/hanami-cli.gemspec +2 -3
  5. data/lib/hanami/cli/commands/app/db/migrate.rb +4 -4
  6. data/lib/hanami/cli/commands/app/db/utils/postgres.rb +4 -6
  7. data/lib/hanami/cli/commands/app/generate/action.rb +31 -7
  8. data/lib/hanami/cli/commands/app/generate/component.rb +2 -0
  9. data/lib/hanami/cli/commands/app/generate/mailer.rb +52 -0
  10. data/lib/hanami/cli/commands/app/generate/operation.rb +6 -0
  11. data/lib/hanami/cli/commands/app/generate/part.rb +4 -8
  12. data/lib/hanami/cli/commands/app/generate/provider.rb +27 -0
  13. data/lib/hanami/cli/commands/app/generate/relation.rb +7 -3
  14. data/lib/hanami/cli/commands/app/generate/repo.rb +3 -1
  15. data/lib/hanami/cli/commands/app/generate/slice.rb +16 -10
  16. data/lib/hanami/cli/commands/app/generate/struct.rb +2 -0
  17. data/lib/hanami/cli/commands/app/generate/view.rb +24 -1
  18. data/lib/hanami/cli/commands/app/middleware.rb +3 -3
  19. data/lib/hanami/cli/commands/app/routes.rb +5 -5
  20. data/lib/hanami/cli/commands/app/server.rb +2 -2
  21. data/lib/hanami/cli/commands/app.rb +6 -1
  22. data/lib/hanami/cli/commands/gem/new.rb +63 -82
  23. data/lib/hanami/cli/errors.rb +1 -1
  24. data/lib/hanami/cli/files.rb +9 -2
  25. data/lib/hanami/cli/generators/app/action.rb +39 -21
  26. data/lib/hanami/cli/generators/app/component.rb +2 -2
  27. data/lib/hanami/cli/generators/app/mailer.rb +81 -0
  28. data/lib/hanami/cli/generators/app/migration.rb +1 -1
  29. data/lib/hanami/cli/generators/app/operation.rb +2 -2
  30. data/lib/hanami/cli/generators/app/part.rb +4 -4
  31. data/lib/hanami/cli/generators/app/provider.rb +54 -0
  32. data/lib/hanami/cli/generators/app/relation.rb +2 -2
  33. data/lib/hanami/cli/generators/app/repo.rb +2 -2
  34. data/lib/hanami/cli/generators/app/ruby_file.rb +8 -4
  35. data/lib/hanami/cli/generators/app/slice.rb +37 -14
  36. data/lib/hanami/cli/generators/app/struct.rb +2 -2
  37. data/lib/hanami/cli/generators/app/view.rb +20 -10
  38. data/lib/hanami/cli/generators/context.rb +32 -52
  39. data/lib/hanami/cli/generators/gem/app/app.erb +3 -0
  40. data/lib/hanami/cli/generators/gem/app/app_layout.haml.erb +15 -0
  41. data/lib/hanami/cli/generators/gem/app/app_layout.slim.erb +15 -0
  42. data/lib/hanami/cli/generators/gem/app/assets.js +1 -1
  43. data/lib/hanami/cli/generators/gem/app/context.erb +1 -1
  44. data/lib/hanami/cli/generators/gem/app/env.erb +18 -1
  45. data/lib/hanami/cli/generators/gem/app/gemfile.erb +50 -6
  46. data/lib/hanami/cli/generators/gem/app/package.json.erb +1 -0
  47. data/lib/hanami/cli/generators/gem/app/puma.erb +0 -3
  48. data/lib/hanami/cli/generators/gem/app/readme.erb +2 -2
  49. data/lib/hanami/cli/generators/gem/app/routes.erb +1 -1
  50. data/lib/hanami/cli/generators/gem/app.rb +26 -1
  51. data/lib/hanami/cli/generators/i18n.yml +3 -0
  52. data/lib/hanami/cli/version.rb +1 -1
  53. metadata +11 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4fab5179afc7358ed28f6f47f4f446004b66e2235b3e4064760277375b67f793
4
- data.tar.gz: 3ff9a30757fa557dd1a516a273a9a6618dd36a0b04318ab12603b01722bf2bd9
3
+ metadata.gz: 38ac5ab30e64a9471ad60f858b4d0131a1909871b422b13526f520169bddc0d5
4
+ data.tar.gz: 1714ec1452959aaebdb78f6252324fb90a0a19722b4a1a90fd5c21a8fe64dabd
5
5
  SHA512:
6
- metadata.gz: c66556edf928261ce41bcd910a39cf11a373db8f0b618314b6535fe8d747377fbe65b3630b24b40dea5f49cb8ebd16d5a2551c0fe4d6ff145d04f7c91fd405ea
7
- data.tar.gz: bdd6dfee069f0d5bb5883693d97a1c0bb4685023225ed5e6835446269db2578c79934add5b586319d21ad001c8981017d399b72230a6fad6ba987b6897710fbb
6
+ metadata.gz: 45a42295cf181115a14ad073a48cae13539966c5f85350a5faf4ca5a33935ebf3a804f41650a3cb43f72727d889037e330e41d27e143aca1e07bcad81325e2f6
7
+ data.tar.gz: e851af6f7c47ba168adab4e4f471b49a32d169ab4a17ed2861644577731b93b475569381b863f6a3fcfb1af0b337cba95ab1d07d42bc2ad8411881e4bfc0c3e5
data/CHANGELOG.md CHANGED
@@ -3,7 +3,7 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+ and this project adheres to [Break Versioning](https://www.taoensso.com/break-versioning).
7
7
 
8
8
  ## [Unreleased]
9
9
 
@@ -11,8 +11,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
11
11
 
12
12
  ### Changed
13
13
 
14
- - In `assets` commands, provide the node command with the assets config path _relative to app root_ instead of an absolute path (`config/assets.js` instead of `/full/path/to/config/assets.js`). This allows the assets commands to work in environments where Node.js is "sandboxed" in such a way that it doesn't share the same absolute path. (@haileys in #381).
15
-
16
14
  ### Deprecated
17
15
 
18
16
  ### Removed
@@ -21,7 +19,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
21
19
 
22
20
  ### Security
23
21
 
24
- [Unreleased]: https://github.com/hanami/cli/compare/v2.3.5...HEAD
22
+ [Unreleased]: https://github.com/hanami/cli/compare/v3.0.0.rc1...HEAD
23
+
24
+ ## [3.0.0.rc1] - 2026-06-16
25
+
26
+ ### Added
27
+
28
+ - Include `hanami-mailer` in the default `Gemfile`, include sample mailer env vars in `.env`, and generate a base `Mailer` class for the app and each slice (`app/mailer.rb` and `mailer.rb` in slices). Use `hanami new --skip-mailer` to opt out. (@timriley in #420, #425)
29
+ - Add `generate mailer` command. (@timriley in #426)
30
+ - Add `i18n` gem to the default `Gemfile`, and generate a placeholder `config/i18n/en.yml` for the app and each generated slice. (@timriley in #409)
31
+ - Add `--name` option to `hanami new`, to specify a custom module namespace while using the positional argument as the directory path. For example, `hanami new my_bookshelf --name=bookshelf` creates the app in `my_bookshelf/` with `Bookshelf` as the module name. (@aaronmallen in #387)
32
+ - Add `--test` option to `hanami new` to specify which test framework to use. Supports `rspec` (default) and `minitest`. (@timriley in #399)
33
+ - Add `generate provider` command. (@timriley in #419)
34
+ - Add `--template-engine` option to `hanami generate` and `hanami new` to specify which template engine should be used for generated template files. Supports `erb`, `haml` and `slim`. (@katafrakt in #280, #389, #390)
35
+ - Add `--force` option to all generators (except migration), which will override existing files instead of exiting early (@katafrakt in #397)
36
+
37
+ ### Changed
38
+
39
+ - In generated `Gemfile`, depend on dry-validation rather than hanami-validations. Hanami Validations will no longer be used; Hanami Action now checks for Dry Validation directly. (@timriley in #401)
40
+ - In generated `package.json`, include `esbuild` as a direct dependency. `esbuild` is now a peer dependency of `hanami-assets`, which requires the app to depend on it directly. (@timriley in #428)
41
+ - Check for the hanami-action gem rather than hanami-controller (now retired) across various commands. (@cllns in #402)
42
+ - Include rouge gem in generated `Gemfile` to enable SQL syntax highlighting in logs. (@kyleplump in #405)
43
+ - When `--gem-source=gem.coop` is used, Hanami and Dry gems are installed from their respective namespaces on gem.coop (@katafrakt in #424)
44
+ - Require Puma 7.1 or later, and remove unneeded `preload_app!` in generated `config/puma.rb`. Preloading is now enabled by default in Puma's cluster mode. (@joshuay03 in #372)
45
+ - In generated `.env`, include a link the guide explaining how these files are loaded. (@timriley in #425)
46
+ - In generated files, update all guides.hanamirb.org links to hanakai.org. (@yosangwon in #407)
47
+ - Require dry-cli 1.4 or later, allowing for simplified argument handling in hanami-rspec callback methods. (@timriley in #408)
48
+ - Link to new hanakai.org site in generated `README.md`. (@katafrakt in #423)
49
+ - Require Ruby 3.3 or newer.
50
+
51
+ ### Fixed
52
+
53
+ - Skip generating duplicate routes when running `generate action`. (@sandbergja in #417)
54
+ - Don't overwrite libpq ENV vars with empty strings derived from certain DATABASE_URLs. (@StantonMatt in #414)
55
+ - Remove duplicate text in `middleware` and `routes` command usage output. (@katafrakt in #406
56
+
57
+ [3.0.0.rc1]: https://github.com/hanami/cli/compare/v2.3.5...v3.0.0.rc1
25
58
 
26
59
  ## [2.3.5] - 2026-02-06
27
60
 
@@ -29,7 +62,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
29
62
 
30
63
  - In `assets` commands, provide the node command with the assets config path _relative to app root_ instead of an absolute path (`config/assets.js` instead of `/full/path/to/config/assets.js`). This allows the assets commands to work in environments where Node.js is "sandboxed" in such a way that it doesn't share the same absolute path. (@haileys in #381).
31
64
 
32
- [2.3.4]: https://github.com/hanami/cli/compare/v2.3.4...v2.3.5
65
+ [2.3.5]: https://github.com/hanami/cli/compare/v2.3.4...v2.3.5
33
66
 
34
67
  ## [2.3.4] - 2026-01-23
35
68
 
data/README.md CHANGED
@@ -1,10 +1,15 @@
1
1
  <!--- This file is synced from hanakai-rb/repo-sync -->
2
2
 
3
- [rubygem]: https://rubygems.org/gems/hanami-cli
4
3
  [actions]: https://github.com/hanami/hanami-cli/actions
4
+ [chat]: https://discord.gg/naQApPAsZB
5
+ [forum]: https://discourse.hanamirb.org
6
+ [rubygem]: https://rubygems.org/gems/hanami-cli
5
7
 
6
8
  # Hanami CLI [![Gem Version](https://badge.fury.io/rb/hanami-cli.svg)][rubygem] [![CI Status](https://github.com/hanami/hanami-cli/workflows/CI/badge.svg)][actions]
7
9
 
10
+ [![Forum](https://img.shields.io/badge/Forum-dc360f?logo=discourse&logoColor=white)][forum]
11
+ [![Chat](https://img.shields.io/badge/Chat-717cf8?logo=discord&logoColor=white)][chat]
12
+
8
13
  This library contains all of the CLI commands for [full-stack Hanami applications](`https://github.com/hanami/hanami`).
9
14
 
10
15
  **NOTE**: For versions 0.4 and below, there was a general purpose CLI utility library with this name.
data/hanami-cli.gemspec CHANGED
@@ -23,16 +23,15 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.extra_rdoc_files = ["README.md", "CHANGELOG.md", "LICENSE"]
25
25
 
26
- spec.metadata["allowed_push_host"] = "https://rubygems.org"
27
26
  spec.metadata["changelog_uri"] = "https://github.com/hanami/hanami-cli/blob/main/CHANGELOG.md"
28
27
  spec.metadata["source_code_uri"] = "https://github.com/hanami/hanami-cli"
29
28
  spec.metadata["bug_tracker_uri"] = "https://github.com/hanami/hanami-cli/issues"
30
29
  spec.metadata["funding_uri"] = "https://github.com/sponsors/hanami"
31
30
 
32
- spec.required_ruby_version = ">= 3.2"
31
+ spec.required_ruby_version = ">= 3.3"
33
32
 
34
33
  spec.add_runtime_dependency "bundler", ">= 2.1"
35
- spec.add_runtime_dependency "dry-cli", "~> 1.0", ">= 1.1.0"
34
+ spec.add_runtime_dependency "dry-cli", "~> 1.0", ">= 1.4.0"
36
35
  spec.add_runtime_dependency "dry-files", "~> 1.0", ">= 1.0.2"
37
36
  spec.add_runtime_dependency "dry-inflector", "~> 1.0"
38
37
  spec.add_runtime_dependency "irb"
@@ -12,10 +12,10 @@ module Hanami
12
12
  option :gateway, required: false, desc: "Use database for gateway"
13
13
  option :target, desc: "Target migration number", aliases: ["-t"]
14
14
  option :dump,
15
- required: false,
16
- type: :boolean,
17
- default: true,
18
- desc: "Dump the database structure after migrating"
15
+ required: false,
16
+ type: :boolean,
17
+ default: true,
18
+ desc: "Dump the database structure after migrating"
19
19
 
20
20
  def call(target: nil, app: false, slice: nil, gateway: nil, dump: true, command_exit: method(:exit), **)
21
21
  databases(app: app, slice: slice, gateway: gateway).each do |database|
@@ -86,12 +86,10 @@ module Hanami
86
86
  Shellwords.escape(name)
87
87
  end
88
88
 
89
- def cli_env_vars # rubocop:disable Metrics/AbcSize
90
- @cli_env_vars ||= {}.tap do |vars|
91
- vars["PGHOST"] = database_uri.host.to_s if database_uri.host
92
- vars["PGPORT"] = database_uri.port.to_s if database_uri.port
93
- vars["PGUSER"] = database_uri.user.to_s if database_uri.user
94
- vars["PGPASSWORD"] = database_uri.password.to_s if database_uri.password
89
+ def cli_env_vars
90
+ @cli_env_vars ||= %i[host port user password].each_with_object({}) do |field, vars|
91
+ value = database_uri.public_send(field).to_s
92
+ vars["PG#{field}".upcase] = value unless value.empty?
95
93
  end
96
94
  end
97
95
  end
@@ -28,6 +28,9 @@ module Hanami
28
28
  DEFAULT_SKIP_ROUTE = false
29
29
  private_constant :DEFAULT_SKIP_ROUTE
30
30
 
31
+ DEFAULT_TEMPLATE_ENGINE = "erb"
32
+ private_constant :DEFAULT_TEMPLATE_ENGINE
33
+
31
34
  argument :name, required: true, desc: "Action name"
32
35
 
33
36
  option :url, as: :url_path, required: false, type: :string, desc: "Action URL path"
@@ -56,6 +59,12 @@ module Hanami
56
59
  desc: "Skip route generation"
57
60
 
58
61
  option :slice, required: false, desc: "Slice name"
62
+ option :template_engine, required: false,
63
+ values: %w[erb haml slim],
64
+ desc: "Template engine to use"
65
+
66
+ option :force, required: false, type: :flag, default: false,
67
+ desc: "Overwrite existing files during generation"
59
68
 
60
69
  # option :format, required: false, type: :string, default: DEFAULT_FORMAT, desc: "Template format"
61
70
 
@@ -85,22 +94,37 @@ module Hanami
85
94
  http_method: nil,
86
95
  skip_view: DEFAULT_SKIP_VIEW,
87
96
  skip_route: DEFAULT_SKIP_ROUTE,
88
- skip_tests: DEFAULT_SKIP_TESTS
97
+ skip_tests: DEFAULT_SKIP_TESTS,
98
+ template_engine: nil,
99
+ force: false,
100
+ **opts
89
101
  )
90
102
  name = Naming.new(inflector:).action_name(name)
91
103
 
92
104
  raise InvalidActionNameError.new(name) unless name.include?(".")
93
105
 
94
106
  super(
95
- name: name,
96
- slice: slice,
97
- url_path: url_path,
98
- skip_route: skip_route,
99
- http_method: http_method,
107
+ name:,
108
+ slice:,
109
+ url_path:,
110
+ skip_route:,
111
+ http_method:,
100
112
  skip_view: skip_view || !Hanami.bundled?("hanami-view"),
101
- skip_tests: skip_tests
113
+ skip_tests:,
114
+ template_engine: template_engine || default_template_engine,
115
+ force:
102
116
  )
103
117
  end
118
+
119
+ private
120
+
121
+ def default_template_engine
122
+ if Hanami.bundled?("hanami-view") && app.config.views.respond_to?(:default_template_engine)
123
+ app.config.views.default_template_engine
124
+ else
125
+ DEFAULT_TEMPLATE_ENGINE
126
+ end
127
+ end
104
128
  end
105
129
  end
106
130
  end
@@ -13,6 +13,8 @@ module Hanami
13
13
  # @since 2.2.0
14
14
  class Component < Command
15
15
  argument :name, required: true, desc: "Component name"
16
+ option :force, required: false, type: :flag, default: false,
17
+ desc: "Overwrite existing files during generation"
16
18
 
17
19
  example [
18
20
  %(isbn_decoder (MyApp::IsbnDecoder)),
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ module CLI
5
+ module Commands
6
+ module App
7
+ module Generate
8
+ # @api private
9
+ class Mailer < Command
10
+ DEFAULT_TEMPLATE_ENGINE = "erb"
11
+
12
+ argument :name, required: true, desc: "Mailer name"
13
+
14
+ option :template_engine, required: false,
15
+ values: %w[erb haml slim],
16
+ desc: "Template engine to use (default: set in app config or erb)"
17
+
18
+ option :skip_tests, required: false, type: :flag, default: false,
19
+ desc: "Skip test generation"
20
+
21
+ option :force, required: false, type: :flag, default: false,
22
+ desc: "Overwrite existing files during generation"
23
+
24
+ example [
25
+ %(welcome (MyApp::Mailers::Welcome)),
26
+ %(welcome --slice=admin (Admin::Mailers::Welcome))
27
+ ]
28
+
29
+ def generator_class
30
+ Generators::App::Mailer
31
+ end
32
+
33
+ def call(template_engine: nil, **opts)
34
+ template_engine ||= default_template_engine
35
+ super(template_engine:, **opts)
36
+ end
37
+
38
+ private
39
+
40
+ def default_template_engine
41
+ if Hanami.bundled?("hanami-view") && app.config.views.respond_to?(:default_template_engine)
42
+ app.config.views.default_template_engine
43
+ else
44
+ DEFAULT_TEMPLATE_ENGINE
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -10,6 +10,12 @@ module Hanami
10
10
  class Operation < Command
11
11
  argument :name, required: true, desc: "Operation name"
12
12
 
13
+ option :skip_tests, required: false, type: :flag, default: false,
14
+ desc: "Skip test generation"
15
+
16
+ option :force, required: false, type: :flag, default: false,
17
+ desc: "Overwrite existing files during generation"
18
+
13
19
  example [
14
20
  %(books.add (MyApp::Books::Add)),
15
21
  %(books.add --slice=admin (Admin::Books::Add))
@@ -12,18 +12,14 @@ module Hanami
12
12
  # @since 2.1.0
13
13
  # @api private
14
14
  class Part < Command
15
- DEFAULT_SKIP_TESTS = false
16
- private_constant :DEFAULT_SKIP_TESTS
17
-
18
15
  argument :name, required: true, desc: "Part name"
19
16
 
20
- option \
21
- :skip_tests,
22
- required: false,
23
- type: :flag,
24
- default: DEFAULT_SKIP_TESTS,
17
+ option :skip_tests, required: false, type: :flag, default: false,
25
18
  desc: "Skip test generation"
26
19
 
20
+ option :force, required: false, type: :flag, default: false,
21
+ desc: "Overwrite existing files during generation"
22
+
27
23
  example [
28
24
  %(book (MyApp::Views::Parts::Book)),
29
25
  %(book --slice=admin (Admin::Views::Parts::Book))
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ module CLI
5
+ module Commands
6
+ module App
7
+ module Generate
8
+ # @api private
9
+ class Provider < Command
10
+ argument :name, required: true, desc: "Provider name"
11
+ option :force, required: false, type: :flag, default: false,
12
+ desc: "Overwrite existing files during generation"
13
+
14
+ example [
15
+ %(mailer (config/providers/mailer.rb)),
16
+ %(mailer --slice=admin (slices/admin/config/providers/mailer.rb))
17
+ ]
18
+
19
+ def generator_class
20
+ Generators::App::Provider
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -10,6 +10,8 @@ module Hanami
10
10
  class Relation < Command
11
11
  argument :name, required: true, desc: "Relation name"
12
12
  option :gateway, desc: "Generate relation for gateway"
13
+ option :force, required: false, type: :flag, default: false,
14
+ desc: "Overwrite existing files during generation"
13
15
 
14
16
  example [
15
17
  %(books (MyApp::Relation::Book)),
@@ -24,20 +26,22 @@ module Hanami
24
26
  Generators::App::Relation
25
27
  end
26
28
 
27
- def call(name:, slice: nil, gateway: nil)
29
+ def call(name:, slice: nil, gateway: nil, force: false)
28
30
  if slice
29
31
  generator.call(
30
32
  key: name,
31
33
  namespace: slice,
32
34
  base_path: fs.join("slices", inflector.underscore(slice)),
33
- gateway: gateway
35
+ gateway: gateway,
36
+ force: force
34
37
  )
35
38
  else
36
39
  generator.call(
37
40
  key: name,
38
41
  namespace: app.namespace,
39
42
  base_path: "app",
40
- gateway: gateway
43
+ gateway: gateway,
44
+ force: force
41
45
  )
42
46
  end
43
47
  end
@@ -15,6 +15,8 @@ module Hanami
15
15
  # @api private
16
16
  class Repo < Command
17
17
  argument :name, required: true, desc: "Repo name"
18
+ option :force, required: false, type: :flag, default: false,
19
+ desc: "Overwrite existing files during generation"
18
20
 
19
21
  example [
20
22
  %(books (MyApp::Repos::BooksRepo)),
@@ -30,7 +32,7 @@ module Hanami
30
32
 
31
33
  # @since 2.2.0
32
34
  # @api private
33
- def call(name:, **opts)
35
+ def call(name:, force: false, **opts)
34
36
  name = "#{inflector.singularize(name)}_repo" unless name.end_with?("_repo")
35
37
  super
36
38
  end
@@ -29,17 +29,22 @@ module Hanami
29
29
  # @since 2.2.0
30
30
  # @api private
31
31
  option :skip_db,
32
- type: :flag,
33
- required: false,
34
- default: SKIP_DB_DEFAULT,
35
- desc: "Skip database"
32
+ type: :flag,
33
+ required: false,
34
+ default: SKIP_DB_DEFAULT,
35
+ desc: "Skip database"
36
36
  # @since 2.2.0
37
37
  # @api private
38
38
  option :skip_route,
39
- type: :flag,
40
- required: false,
41
- default: DEFAULT_SKIP_ROUTE,
42
- desc: "Skip route generation"
39
+ type: :flag,
40
+ required: false,
41
+ default: DEFAULT_SKIP_ROUTE,
42
+ desc: "Skip route generation"
43
+
44
+ # @since 2.2.0
45
+ # @api private
46
+ option :force, required: false, type: :flag, default: false,
47
+ desc: "Overwrite existing files during generation"
43
48
 
44
49
  example [
45
50
  "admin # Admin slice (/admin URL prefix)",
@@ -63,7 +68,8 @@ module Hanami
63
68
  name:,
64
69
  url: nil,
65
70
  skip_db: SKIP_DB_DEFAULT,
66
- skip_route: DEFAULT_SKIP_ROUTE
71
+ skip_route: DEFAULT_SKIP_ROUTE,
72
+ force: false
67
73
  )
68
74
  require "hanami/setup"
69
75
 
@@ -71,7 +77,7 @@ module Hanami
71
77
  name = inflector.underscore(Shellwords.shellescape(name))
72
78
  url = sanitize_url_prefix(name, url)
73
79
 
74
- generator.call(app, name, url, skip_db: skip_db, skip_route: skip_route)
80
+ generator.call(app, name, url, skip_db: skip_db, skip_route: skip_route, force: force)
75
81
  end
76
82
 
77
83
  private
@@ -9,6 +9,8 @@ module Hanami
9
9
  # @api private
10
10
  class Struct < Command
11
11
  argument :name, required: true, desc: "Struct name"
12
+ option :force, required: false, type: :flag, default: false,
13
+ desc: "Overwrite existing files during generation"
12
14
 
13
15
  example [
14
16
  %(book (MyApp::Structs::Book)),
@@ -15,9 +15,16 @@ module Hanami
15
15
  # @api private
16
16
  class View < Command
17
17
  # TODO: make format configurable
18
- # TODO: make engine configurable
18
+
19
+ DEFAULT_TEMPLATE_ENGINE = "erb"
20
+ private_constant :DEFAULT_TEMPLATE_ENGINE
19
21
 
20
22
  argument :name, required: true, desc: "View name"
23
+ option :template_engine, required: false,
24
+ values: %w[erb haml slim],
25
+ desc: "Template engine to use (default: set in app config or erb)"
26
+ option :force, required: false, type: :flag, default: false,
27
+ desc: "Overwrite existing files during generation"
21
28
 
22
29
  example [
23
30
  %(books.index (MyApp::Actions::Books::Index)),
@@ -29,6 +36,22 @@ module Hanami
29
36
  def generator_class
30
37
  Generators::App::View
31
38
  end
39
+
40
+ # @since 2.0.0
41
+ # @api private
42
+ def call(name:, slice: nil, template_engine: nil, force: false, **opts)
43
+ super(name:, slice:, template_engine: template_engine || default_template_engine, force: force)
44
+ end
45
+
46
+ private
47
+
48
+ def default_template_engine
49
+ if Hanami.bundled?("hanami-view") && app.config.views.respond_to?(:default_template_engine)
50
+ app.config.views.default_template_engine
51
+ else
52
+ DEFAULT_TEMPLATE_ENGINE
53
+ end
54
+ end
32
55
  end
33
56
  end
34
57
  end
@@ -34,11 +34,11 @@ module Hanami
34
34
  private_constant :DEFAULT_WITH_ARGUMENTS
35
35
 
36
36
  option :with_arguments, default: DEFAULT_WITH_ARGUMENTS, required: false,
37
- desc: "Include inspected arguments", type: :flag
37
+ desc: "Include inspected arguments", type: :flag
38
38
 
39
39
  example [
40
- "middleware # Print app Rack middleware stack",
41
- "middleware --with-arguments # Print app Rack middleware stack, including initialize arguments"
40
+ " # Print app Rack middleware stack",
41
+ "--with-arguments # Print app Rack middleware stack, including initialize arguments"
42
42
  ]
43
43
 
44
44
  # @since 2.0.0
@@ -40,13 +40,13 @@ module Hanami
40
40
  desc "Print app routes"
41
41
 
42
42
  option :format,
43
- default: DEFAULT_FORMAT,
44
- required: false,
45
- desc: "Output format"
43
+ default: DEFAULT_FORMAT,
44
+ required: false,
45
+ desc: "Output format"
46
46
 
47
47
  example [
48
- "routes # Print app routes",
49
- "routes --format=csv # Print app routes, using CSV format"
48
+ " # Print app routes",
49
+ "--format=csv # Print app routes, using CSV format"
50
50
  ]
51
51
 
52
52
  # @since 2.0.0
@@ -36,9 +36,9 @@ module Hanami
36
36
  desc "Start Hanami app server"
37
37
 
38
38
  option :host, default: nil, required: false,
39
- desc: "The host address to bind to (falls back to the rack handler)"
39
+ desc: "The host address to bind to (falls back to the rack handler)"
40
40
  option :port, default: Hanami::Port::DEFAULT, required: false,
41
- desc: "The port to run the server on (falls back to the rack handler)"
41
+ desc: "The port to run the server on (falls back to the rack handler)"
42
42
  option :config, default: DEFAULT_CONFIG_PATH, required: false, desc: "Rack configuration file"
43
43
  option :debug, default: false, required: false, desc: "Turn on/off debug output", type: :flag
44
44
  option :warn, default: false, required: false, desc: "Turn on/off warnings", type: :flag
@@ -45,8 +45,9 @@ module Hanami
45
45
  register "generate", aliases: ["g"] do |prefix|
46
46
  prefix.register "slice", Generate::Slice
47
47
  prefix.register "component", Generate::Component
48
+ prefix.register "provider", Generate::Provider
48
49
 
49
- if Hanami.bundled?("hanami-controller")
50
+ if Hanami.bundled?("hanami-action")
50
51
  prefix.register "action", Generate::Action
51
52
  end
52
53
 
@@ -59,6 +60,10 @@ module Hanami
59
60
  prefix.register "part", Generate::Part
60
61
  end
61
62
 
63
+ if Hanami.bundled?("hanami-mailer")
64
+ prefix.register "mailer", Generate::Mailer
65
+ end
66
+
62
67
  if Hanami.bundled?("hanami-db")
63
68
  prefix.register "migration", Generate::Migration
64
69
  prefix.register "relation", Generate::Relation