hanami-cli 2.1.0.beta2 → 2.1.0.rc2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +37 -0
- data/Gemfile +2 -0
- data/lib/hanami/cli/commands/app/assets/command.rb +2 -29
- data/lib/hanami/cli/commands/app/assets/compile.rb +1 -1
- data/lib/hanami/cli/commands/app/assets/watch.rb +1 -5
- data/lib/hanami/cli/commands/app/dev.rb +4 -16
- data/lib/hanami/cli/commands/app/generate/action.rb +25 -4
- data/lib/hanami/cli/commands/app/generate/part.rb +58 -0
- data/lib/hanami/cli/commands/app/install.rb +0 -28
- data/lib/hanami/cli/commands/app.rb +1 -0
- data/lib/hanami/cli/commands/gem/new.rb +28 -3
- data/lib/hanami/cli/generators/app/action.rb +46 -6
- data/lib/hanami/cli/generators/app/part/app_base_part.erb +9 -0
- data/lib/hanami/cli/generators/app/part/app_part.erb +13 -0
- data/lib/hanami/cli/generators/app/part/slice_base_part.erb +9 -0
- data/lib/hanami/cli/generators/app/part/slice_part.erb +13 -0
- data/lib/hanami/cli/generators/app/part.rb +101 -0
- data/lib/hanami/cli/generators/app/part_context.rb +98 -0
- data/lib/hanami/cli/generators/app/slice/app_layout.erb +1 -1
- data/lib/hanami/cli/generators/app/slice_context.rb +2 -2
- data/lib/hanami/cli/generators/context.rb +20 -2
- data/lib/hanami/cli/generators/gem/app/404.html +76 -5
- data/lib/hanami/cli/generators/gem/app/500.html +76 -5
- data/lib/hanami/cli/generators/gem/app/app_layout.erb +3 -3
- data/lib/hanami/cli/generators/gem/app/assets.js +14 -0
- data/lib/hanami/cli/generators/gem/app/dev +8 -0
- data/lib/hanami/cli/generators/gem/app/package.json.erb +11 -0
- data/lib/hanami/cli/generators/gem/app/puma.erb +37 -7
- data/lib/hanami/cli/generators/gem/app/routes.erb +1 -1
- data/lib/hanami/cli/generators/gem/app.rb +12 -3
- data/lib/hanami/cli/generators/version.rb +14 -2
- data/lib/hanami/cli/version.rb +1 -1
- metadata +13 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: aa0dbea6bc97ed3a7d08b703e7fd9091def9a8326196d36c071fb8e3e9be654b
|
|
4
|
+
data.tar.gz: dc27646ce5d395932bd2fbddef1678cb5445959494270b8d5f149462a8648e90
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ac1ab34a920c7fea44106a75c8c7e8d1bb0e475ff1e48ce2ef9b87912e9da6c83aa847ddf56661db13a01551fd58e098245b6d8ac277ca7143c69681d97d5ece
|
|
7
|
+
data.tar.gz: 706d1bb79523ba8a7efd9281267de12a0f275be0b60374c619b132371e0339335e6a4112b7a53ed5951e57293799aea1b4a89ac5bf6f9ee718daec4e1c44ee45
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,43 @@
|
|
|
2
2
|
|
|
3
3
|
Hanami Command Line Interface
|
|
4
4
|
|
|
5
|
+
## v2.1.0.rc2 - 2023-11-08
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- [Tim Riley] Add `--skip-tests` for `hanami generate` commands. This CLI option will skip tests generation.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- [Tim Riley] Set `"type": "module"` in package.json, enabling ES modules by default
|
|
14
|
+
- [Tim Riley] Rename `config/assets.mjs` to `config/assets.js` (use a plain `.js` file extension)
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- [Tim Riley] Use correct helper names in generated app layout
|
|
19
|
+
- [Luca Guidi] Ensure to generate apps with correct pre-release version of `hanami-assets` NPM package
|
|
20
|
+
- [Sean Collins] Print to stderr NPM installation errors when running `hanami install`
|
|
21
|
+
- [Sean Collins] Ensure to install missing gems after `hanami install` is ran
|
|
22
|
+
|
|
23
|
+
## v2.1.0.rc1 - 2023-11-01
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- [Tim Riley] `hanami new` to generate `bin/dev` as configuration for `hanami dev`
|
|
28
|
+
- [Luca Guidi] Introducing `hanami generate part` to generate view parts
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- [Luca Guidi] `hanami new` generates a fully documented Puma configuration in `config/puma.rb`
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- [Tim Riley] `hanami new` generates a `config/assets.mjs` as Assets configuration
|
|
37
|
+
- [Tim Riley] `hanami new` generates a leaner `package.json`
|
|
38
|
+
- [Tim Riley] `hanami new` doesn't generate a default root route anymore
|
|
39
|
+
- [Aaron Moodie & Tim Riley] `hanami new` to generate a redesigned 404 and 500 error pages
|
|
40
|
+
- [Luca Guidi] When generating a RESTful action, skip `create`, if `new` is present, and `update`, if `edit` is present
|
|
41
|
+
|
|
5
42
|
## v2.1.0.beta2 - 2023-10-04
|
|
6
43
|
|
|
7
44
|
### Added
|
data/Gemfile
CHANGED
|
@@ -15,6 +15,8 @@ gem "hanami-controller", github: "hanami/controller", branch: "main"
|
|
|
15
15
|
gem "hanami-router", github: "hanami/router", branch: "main"
|
|
16
16
|
gem "hanami-utils", github: "hanami/utils", branch: "main"
|
|
17
17
|
|
|
18
|
+
gem "dry-files", github: "dry-rb/dry-files", branch: "main"
|
|
19
|
+
|
|
18
20
|
gem "rack"
|
|
19
21
|
|
|
20
22
|
group :test do
|
|
@@ -23,7 +23,7 @@ module Hanami
|
|
|
23
23
|
def call(**)
|
|
24
24
|
cmd, *args = cmd_with_args
|
|
25
25
|
|
|
26
|
-
system_call.call(cmd, *args
|
|
26
|
+
system_call.call(cmd, *args)
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
private
|
|
@@ -39,34 +39,7 @@ module Hanami
|
|
|
39
39
|
# @since 2.1.0
|
|
40
40
|
# @api private
|
|
41
41
|
def cmd_with_args
|
|
42
|
-
[
|
|
43
|
-
config.package_manager_executable,
|
|
44
|
-
config.package_manager_command,
|
|
45
|
-
config.executable
|
|
46
|
-
]
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# @since 2.1.0
|
|
50
|
-
# @api private
|
|
51
|
-
def env
|
|
52
|
-
ENV.to_h.merge(
|
|
53
|
-
"ESBUILD_ENTRY_POINTS" => entry_points,
|
|
54
|
-
"ESBUILD_OUTDIR" => destination
|
|
55
|
-
)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
# @since 2.1.0
|
|
59
|
-
# @api private
|
|
60
|
-
def entry_points
|
|
61
|
-
config.entry_points.map do |entry_point|
|
|
62
|
-
escape(entry_point)
|
|
63
|
-
end.join(" ")
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# @since 2.1.0
|
|
67
|
-
# @api private
|
|
68
|
-
def destination
|
|
69
|
-
escape(config.destination)
|
|
42
|
+
[config.package_manager_run_command, "assets"]
|
|
70
43
|
end
|
|
71
44
|
|
|
72
45
|
# @since 2.1.0
|
|
@@ -13,16 +13,6 @@ module Hanami
|
|
|
13
13
|
# @api private
|
|
14
14
|
desc "Start the application in development mode"
|
|
15
15
|
|
|
16
|
-
# @since 2.1.0
|
|
17
|
-
# @api private
|
|
18
|
-
option :procfile, type: :string, desc: "Path to Procfile", aliases: ["-f"]
|
|
19
|
-
|
|
20
|
-
# @since 2.1.0
|
|
21
|
-
# @api private
|
|
22
|
-
example [
|
|
23
|
-
"-f /path/to/Procfile",
|
|
24
|
-
]
|
|
25
|
-
|
|
26
16
|
# @since 2.1.0
|
|
27
17
|
# @api private
|
|
28
18
|
def initialize(interactive_system_call: InteractiveSystemCall.new, **)
|
|
@@ -32,8 +22,8 @@ module Hanami
|
|
|
32
22
|
|
|
33
23
|
# @since 2.1.0
|
|
34
24
|
# @api private
|
|
35
|
-
def call(
|
|
36
|
-
bin, args = executable
|
|
25
|
+
def call(**)
|
|
26
|
+
bin, args = executable
|
|
37
27
|
interactive_system_call.call(bin, *args)
|
|
38
28
|
end
|
|
39
29
|
|
|
@@ -45,10 +35,8 @@ module Hanami
|
|
|
45
35
|
|
|
46
36
|
# @since 2.1.0
|
|
47
37
|
# @api private
|
|
48
|
-
def executable
|
|
49
|
-
|
|
50
|
-
# See: https://github.com/ddollar/foreman#ports
|
|
51
|
-
["foreman", ["start", "-f", procfile || "Procfile.dev"]]
|
|
38
|
+
def executable
|
|
39
|
+
[::File.join("bin", "dev")]
|
|
52
40
|
end
|
|
53
41
|
end
|
|
54
42
|
end
|
|
@@ -22,12 +22,25 @@ module Hanami
|
|
|
22
22
|
DEFAULT_SKIP_VIEW = false
|
|
23
23
|
private_constant :DEFAULT_SKIP_VIEW
|
|
24
24
|
|
|
25
|
+
DEFAULT_SKIP_TESTS = false
|
|
26
|
+
private_constant :DEFAULT_SKIP_TESTS
|
|
27
|
+
|
|
25
28
|
argument :name, required: true, desc: "Action name"
|
|
26
29
|
option :url, required: false, type: :string, desc: "Action URL"
|
|
27
30
|
option :http, required: false, type: :string, desc: "Action HTTP method"
|
|
28
31
|
# option :format, required: false, type: :string, default: DEFAULT_FORMAT, desc: "Template format"
|
|
29
|
-
option
|
|
30
|
-
|
|
32
|
+
option \
|
|
33
|
+
:skip_view,
|
|
34
|
+
required: false,
|
|
35
|
+
type: :boolean,
|
|
36
|
+
default: DEFAULT_SKIP_VIEW,
|
|
37
|
+
desc: "Skip view and template generation"
|
|
38
|
+
option \
|
|
39
|
+
:skip_tests,
|
|
40
|
+
required: false,
|
|
41
|
+
type: :boolean,
|
|
42
|
+
default: DEFAULT_SKIP_TESTS,
|
|
43
|
+
desc: "Skip test generation"
|
|
31
44
|
option :slice, required: false, desc: "Slice name"
|
|
32
45
|
|
|
33
46
|
# rubocop:disable Layout/LineLength
|
|
@@ -60,8 +73,16 @@ module Hanami
|
|
|
60
73
|
|
|
61
74
|
# @since 2.0.0
|
|
62
75
|
# @api private
|
|
63
|
-
def call(
|
|
64
|
-
|
|
76
|
+
def call(
|
|
77
|
+
name:,
|
|
78
|
+
url: nil,
|
|
79
|
+
http: nil,
|
|
80
|
+
format: DEFAULT_FORMAT,
|
|
81
|
+
skip_view: DEFAULT_SKIP_VIEW,
|
|
82
|
+
skip_tests: DEFAULT_SKIP_TESTS, # rubocop:disable Lint/UnusedMethodArgument
|
|
83
|
+
slice: nil,
|
|
84
|
+
context: nil, **
|
|
85
|
+
)
|
|
65
86
|
slice = inflector.underscore(Shellwords.shellescape(slice)) if slice
|
|
66
87
|
name = naming.action_name(name)
|
|
67
88
|
*controller, action = name.split(ACTION_SEPARATOR)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dry/inflector"
|
|
4
|
+
require "dry/files"
|
|
5
|
+
require "shellwords"
|
|
6
|
+
|
|
7
|
+
module Hanami
|
|
8
|
+
module CLI
|
|
9
|
+
module Commands
|
|
10
|
+
module App
|
|
11
|
+
module Generate
|
|
12
|
+
# @since 2.1.0
|
|
13
|
+
# @api private
|
|
14
|
+
class Part < App::Command
|
|
15
|
+
DEFAULT_SKIP_TESTS = false
|
|
16
|
+
private_constant :DEFAULT_SKIP_TESTS
|
|
17
|
+
|
|
18
|
+
argument :name, required: true, desc: "Part name"
|
|
19
|
+
option :slice, required: false, desc: "Slice name"
|
|
20
|
+
option \
|
|
21
|
+
:skip_tests,
|
|
22
|
+
required: false,
|
|
23
|
+
type: :boolean,
|
|
24
|
+
default: DEFAULT_SKIP_TESTS,
|
|
25
|
+
desc: "Skip test generation"
|
|
26
|
+
|
|
27
|
+
example [
|
|
28
|
+
%(book (MyApp::Views::Parts::Book)),
|
|
29
|
+
%(book --slice=admin (Admin::Views::Parts::Book)),
|
|
30
|
+
]
|
|
31
|
+
attr_reader :generator
|
|
32
|
+
private :generator
|
|
33
|
+
|
|
34
|
+
# @since 2.0.0
|
|
35
|
+
# @api private
|
|
36
|
+
def initialize(
|
|
37
|
+
fs: Hanami::CLI::Files.new,
|
|
38
|
+
inflector: Dry::Inflector.new,
|
|
39
|
+
generator: Generators::App::Part.new(fs: fs, inflector: inflector),
|
|
40
|
+
**
|
|
41
|
+
)
|
|
42
|
+
@generator = generator
|
|
43
|
+
super(fs: fs)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @since 2.0.0
|
|
47
|
+
# @api private
|
|
48
|
+
def call(name:, slice: nil, skip_tests: DEFAULT_SKIP_TESTS, **) # rubocop:disable Lint/UnusedMethodArgument
|
|
49
|
+
slice = inflector.underscore(Shellwords.shellescape(slice)) if slice
|
|
50
|
+
|
|
51
|
+
generator.call(app.namespace, name, slice)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -33,37 +33,9 @@ module Hanami
|
|
|
33
33
|
# @api private
|
|
34
34
|
option :head, type: :boolean, desc: "Install head deps", default: DEFAULT_HEAD
|
|
35
35
|
|
|
36
|
-
# @since 2.1.0
|
|
37
|
-
# @api private
|
|
38
|
-
def initialize(system_call: SystemCall.new, **)
|
|
39
|
-
@system_call = system_call
|
|
40
|
-
super()
|
|
41
|
-
end
|
|
42
|
-
|
|
43
36
|
# @since 2.0.0
|
|
44
37
|
# @api private
|
|
45
38
|
def call(head: DEFAULT_HEAD, **)
|
|
46
|
-
install_hanami_assets!(head: head)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
private
|
|
50
|
-
|
|
51
|
-
# @since 2.1.0
|
|
52
|
-
# @api private
|
|
53
|
-
attr_reader :system_call
|
|
54
|
-
|
|
55
|
-
# @since 2.1.0
|
|
56
|
-
# @api private
|
|
57
|
-
def install_hanami_assets!(head:)
|
|
58
|
-
return unless Hanami.bundled?("hanami-assets")
|
|
59
|
-
|
|
60
|
-
system_call.call("npm", ["init", "-y"])
|
|
61
|
-
|
|
62
|
-
if head
|
|
63
|
-
system_call.call("npm", %w[install https://github.com/hanami/assets-js])
|
|
64
|
-
else
|
|
65
|
-
system_call.call("npm", %w[install hanami-assets])
|
|
66
|
-
end
|
|
67
39
|
end
|
|
68
40
|
end
|
|
69
41
|
end
|
|
@@ -58,6 +58,8 @@ module Hanami
|
|
|
58
58
|
]
|
|
59
59
|
# rubocop:enable Layout/LineLength
|
|
60
60
|
|
|
61
|
+
# rubocop:disable Metrics/ParameterLists
|
|
62
|
+
|
|
61
63
|
# @since 2.0.0
|
|
62
64
|
# @api private
|
|
63
65
|
def initialize(
|
|
@@ -65,13 +67,19 @@ module Hanami
|
|
|
65
67
|
inflector: Dry::Inflector.new,
|
|
66
68
|
bundler: CLI::Bundler.new(fs: fs),
|
|
67
69
|
generator: Generators::Gem::App.new(fs: fs, inflector: inflector),
|
|
70
|
+
system_call: SystemCall.new,
|
|
68
71
|
**other
|
|
69
72
|
)
|
|
70
73
|
@bundler = bundler
|
|
71
74
|
@generator = generator
|
|
75
|
+
@system_call = system_call
|
|
72
76
|
super(fs: fs, inflector: inflector, **other)
|
|
73
77
|
end
|
|
74
78
|
|
|
79
|
+
# rubocop:enable Metrics/ParameterLists
|
|
80
|
+
|
|
81
|
+
# rubocop:disable Metrics/AbcSize
|
|
82
|
+
|
|
75
83
|
# @since 2.0.0
|
|
76
84
|
# @api private
|
|
77
85
|
def call(app:, head: HEAD_DEFAULT, skip_install: SKIP_INSTALL_DEFAULT, skip_assets: SKIP_ASSETS_DEFAULT, **)
|
|
@@ -88,22 +96,39 @@ module Hanami
|
|
|
88
96
|
else
|
|
89
97
|
out.puts "Running Bundler install..."
|
|
90
98
|
bundler.install!
|
|
99
|
+
|
|
100
|
+
unless skip_assets
|
|
101
|
+
out.puts "Running npm install..."
|
|
102
|
+
system_call.call("npm", ["install"]).tap do |result|
|
|
103
|
+
unless result.successful?
|
|
104
|
+
puts "NPM ERROR:"
|
|
105
|
+
puts(result.err.lines.map { |line| line.prepend(" ") })
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
91
110
|
out.puts "Running Hanami install..."
|
|
92
|
-
|
|
111
|
+
run_install_command!(head: head)
|
|
93
112
|
end
|
|
94
113
|
end
|
|
95
114
|
end
|
|
96
115
|
end
|
|
116
|
+
# rubocop:enable Metrics/AbcSize
|
|
97
117
|
|
|
98
118
|
private
|
|
99
119
|
|
|
100
120
|
attr_reader :bundler
|
|
101
121
|
attr_reader :generator
|
|
122
|
+
attr_reader :system_call
|
|
102
123
|
|
|
103
|
-
def
|
|
124
|
+
def run_install_command!(head:)
|
|
104
125
|
head_flag = head ? " --head" : ""
|
|
105
126
|
bundler.exec("hanami install#{head_flag}").tap do |result|
|
|
106
|
-
|
|
127
|
+
if result.successful?
|
|
128
|
+
bundler.exec("check").successful? || bundler.exec("install")
|
|
129
|
+
else
|
|
130
|
+
raise HanamiInstallError.new(result.err)
|
|
131
|
+
end
|
|
107
132
|
end
|
|
108
133
|
end
|
|
109
134
|
end
|
|
@@ -56,6 +56,14 @@ module Hanami
|
|
|
56
56
|
}.freeze
|
|
57
57
|
private_constant :ROUTE_RESTFUL_URL_SUFFIXES
|
|
58
58
|
|
|
59
|
+
# @api private
|
|
60
|
+
# @since 2.1.0
|
|
61
|
+
RESTFUL_COUNTERPART_VIEWS = {
|
|
62
|
+
"create" => "new",
|
|
63
|
+
"update" => "edit"
|
|
64
|
+
}.freeze
|
|
65
|
+
private_constant :RESTFUL_COUNTERPART_VIEWS
|
|
66
|
+
|
|
59
67
|
PATH_SEPARATOR = "/"
|
|
60
68
|
private_constant :PATH_SEPARATOR
|
|
61
69
|
|
|
@@ -77,7 +85,7 @@ module Hanami
|
|
|
77
85
|
fs.mkdir(directory = fs.join(slice_directory, "actions", controller))
|
|
78
86
|
fs.write(fs.join(directory, "#{action}.rb"), t("slice_action.erb", context))
|
|
79
87
|
|
|
80
|
-
|
|
88
|
+
if generate_view?(skip_view, action, directory)
|
|
81
89
|
fs.mkdir(directory = fs.join(slice_directory, "views", controller))
|
|
82
90
|
fs.write(fs.join(directory, "#{action}.rb"), t("slice_view.erb", context))
|
|
83
91
|
|
|
@@ -97,12 +105,15 @@ module Hanami
|
|
|
97
105
|
fs.mkdir(directory = fs.join("app", "actions", controller))
|
|
98
106
|
fs.write(fs.join(directory, "#{action}.rb"), t("action.erb", context))
|
|
99
107
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
fs.write(fs.join(directory, "#{action}.rb"), t("view.erb", context))
|
|
108
|
+
view = action
|
|
109
|
+
view_directory = fs.join("app", "views", controller)
|
|
103
110
|
|
|
104
|
-
|
|
105
|
-
fs.
|
|
111
|
+
if generate_view?(skip_view, view, view_directory)
|
|
112
|
+
fs.mkdir(view_directory)
|
|
113
|
+
fs.write(fs.join(view_directory, "#{view}.rb"), t("view.erb", context))
|
|
114
|
+
|
|
115
|
+
fs.mkdir(template_directory = fs.join("app", "templates", controller))
|
|
116
|
+
fs.write(fs.join(template_directory, "#{view}.#{format}.erb"),
|
|
106
117
|
t(template_with_format_ext("template", format), context))
|
|
107
118
|
end
|
|
108
119
|
end
|
|
@@ -117,6 +128,35 @@ module Hanami
|
|
|
117
128
|
http)} "#{route_url(controller, action, url)}", to: "#{controller.join('.')}.#{action}")
|
|
118
129
|
end
|
|
119
130
|
|
|
131
|
+
# @api private
|
|
132
|
+
# @since 2.1.0
|
|
133
|
+
def generate_view?(skip_view, view, directory)
|
|
134
|
+
return false if skip_view
|
|
135
|
+
return generate_restful_view?(view, directory) if rest_view?(view)
|
|
136
|
+
|
|
137
|
+
true
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# @api private
|
|
141
|
+
# @since 2.1.0
|
|
142
|
+
def generate_restful_view?(view, directory)
|
|
143
|
+
corresponding_action = corresponding_restful_view(view)
|
|
144
|
+
|
|
145
|
+
!fs.exist?(fs.join(directory, "#{corresponding_action}.rb"))
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# @api private
|
|
149
|
+
# @since 2.1.0
|
|
150
|
+
def rest_view?(view)
|
|
151
|
+
RESTFUL_COUNTERPART_VIEWS.keys.include?(view)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# @api private
|
|
155
|
+
# @since 2.1.0
|
|
156
|
+
def corresponding_restful_view(view)
|
|
157
|
+
RESTFUL_COUNTERPART_VIEWS.fetch(view, nil)
|
|
158
|
+
end
|
|
159
|
+
|
|
120
160
|
def template_with_format_ext(name, format)
|
|
121
161
|
ext =
|
|
122
162
|
case format.to_sym
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# auto_register: false
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module <%= camelized_app_name %>
|
|
5
|
+
module Views
|
|
6
|
+
module Parts
|
|
7
|
+
<%= module_namespace_declaration -%>
|
|
8
|
+
<%= module_namespace_offset %>class <%= camelized_name %> < <%= camelized_app_name %>::Views::Part
|
|
9
|
+
<%= module_namespace_offset %>end
|
|
10
|
+
<%= module_namespace_end -%>
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# auto_register: false
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module <%= camelized_slice_name %>
|
|
5
|
+
module Views
|
|
6
|
+
module Parts
|
|
7
|
+
<%= module_namespace_declaration -%>
|
|
8
|
+
<%= module_namespace_offset %>class <%= camelized_name %> < <%= camelized_slice_name %>::Views::Part
|
|
9
|
+
<%= module_namespace_offset %>end
|
|
10
|
+
<%= module_namespace_end -%>
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "erb"
|
|
4
|
+
require "dry/files"
|
|
5
|
+
require_relative "../../errors"
|
|
6
|
+
|
|
7
|
+
module Hanami
|
|
8
|
+
module CLI
|
|
9
|
+
module Generators
|
|
10
|
+
module App
|
|
11
|
+
# @since 2.1.0
|
|
12
|
+
# @api private
|
|
13
|
+
class Part
|
|
14
|
+
# @since 2.1.0
|
|
15
|
+
# @api private
|
|
16
|
+
def initialize(fs:, inflector:)
|
|
17
|
+
@fs = fs
|
|
18
|
+
@inflector = inflector
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @since 2.1.0
|
|
22
|
+
# @api private
|
|
23
|
+
def call(app, key, slice)
|
|
24
|
+
context = PartContext.new(inflector, app, slice, key)
|
|
25
|
+
|
|
26
|
+
if slice
|
|
27
|
+
generate_for_slice(context, slice)
|
|
28
|
+
else
|
|
29
|
+
generate_for_app(context)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
# @since 2.1.0
|
|
36
|
+
# @api private
|
|
37
|
+
attr_reader :fs
|
|
38
|
+
|
|
39
|
+
# @since 2.1.0
|
|
40
|
+
# @api private
|
|
41
|
+
attr_reader :inflector
|
|
42
|
+
|
|
43
|
+
# @since 2.1.0
|
|
44
|
+
# @api private
|
|
45
|
+
def generate_for_slice(context, slice)
|
|
46
|
+
slice_directory = fs.join("slices", slice)
|
|
47
|
+
raise MissingSliceError.new(slice) unless fs.directory?(slice_directory)
|
|
48
|
+
|
|
49
|
+
generate_base_part_for_app(context)
|
|
50
|
+
generate_base_part_for_slice(context, slice)
|
|
51
|
+
|
|
52
|
+
fs.mkdir(directory = fs.join(slice_directory, "views", "parts", *context.underscored_namespace))
|
|
53
|
+
fs.write(fs.join(directory, "#{context.underscored_name}.rb"), t("slice_part.erb", context))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# @since 2.1.0
|
|
57
|
+
# @api private
|
|
58
|
+
def generate_for_app(context)
|
|
59
|
+
generate_base_part_for_app(context)
|
|
60
|
+
|
|
61
|
+
fs.mkdir(directory = fs.join("app", "views", "parts", *context.underscored_namespace))
|
|
62
|
+
fs.write(fs.join(directory, "#{context.underscored_name}.rb"), t("app_part.erb", context))
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# @since 2.1.0
|
|
66
|
+
# @api private
|
|
67
|
+
def generate_base_part_for_app(context)
|
|
68
|
+
path = fs.join("app", "views", "part.rb")
|
|
69
|
+
return if fs.exist?(path)
|
|
70
|
+
|
|
71
|
+
fs.write(path, t("app_base_part.erb", context))
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# @since 2.1.0
|
|
75
|
+
# @api private
|
|
76
|
+
def generate_base_part_for_slice(context, slice)
|
|
77
|
+
path = fs.join("slices", slice, "views", "part.rb")
|
|
78
|
+
return if fs.exist?(path)
|
|
79
|
+
|
|
80
|
+
fs.write(path, t("slice_base_part.erb", context))
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# @since 2.1.0
|
|
84
|
+
# @api private
|
|
85
|
+
def template(path, context)
|
|
86
|
+
require "erb"
|
|
87
|
+
|
|
88
|
+
ERB.new(
|
|
89
|
+
File.read(__dir__ + "/part/#{path}"),
|
|
90
|
+
trim_mode: "-"
|
|
91
|
+
).result(context.ctx)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# @since 2.1.0
|
|
95
|
+
# @api private
|
|
96
|
+
alias_method :t, :template
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "slice_context"
|
|
4
|
+
require "dry/files/path"
|
|
5
|
+
|
|
6
|
+
module Hanami
|
|
7
|
+
module CLI
|
|
8
|
+
module Generators
|
|
9
|
+
# @since 2.1.0
|
|
10
|
+
# @api private
|
|
11
|
+
module App
|
|
12
|
+
# @since 2.1.0
|
|
13
|
+
# @api private
|
|
14
|
+
class PartContext < SliceContext
|
|
15
|
+
# TODO: move these constants somewhere that will let us reuse them
|
|
16
|
+
|
|
17
|
+
# @since 2.1.0
|
|
18
|
+
# @api private
|
|
19
|
+
KEY_SEPARATOR = "."
|
|
20
|
+
private_constant :KEY_SEPARATOR
|
|
21
|
+
|
|
22
|
+
# @since 2.1.0
|
|
23
|
+
# @api private
|
|
24
|
+
INDENTATION = " "
|
|
25
|
+
private_constant :INDENTATION
|
|
26
|
+
|
|
27
|
+
# @since 2.1.0
|
|
28
|
+
# @api private
|
|
29
|
+
OFFSET = INDENTATION * 2
|
|
30
|
+
private_constant :OFFSET
|
|
31
|
+
|
|
32
|
+
# @since 2.1.0
|
|
33
|
+
# @api private
|
|
34
|
+
attr_reader :key
|
|
35
|
+
|
|
36
|
+
# @since 2.1.0
|
|
37
|
+
# @api private
|
|
38
|
+
def initialize(inflector, app, slice, key)
|
|
39
|
+
@key = key
|
|
40
|
+
super(inflector, app, slice, nil)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# @since 2.1.0
|
|
44
|
+
# @api private
|
|
45
|
+
def namespaces
|
|
46
|
+
@namespaces ||= key.split(KEY_SEPARATOR)[..-2]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @since 2.1.0
|
|
50
|
+
# @api private
|
|
51
|
+
def name
|
|
52
|
+
@name ||= key.split(KEY_SEPARATOR)[-1]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# @since 2.1.0
|
|
56
|
+
# @api private
|
|
57
|
+
def camelized_name
|
|
58
|
+
inflector.camelize(name)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @since 2.1.0
|
|
62
|
+
# @api private
|
|
63
|
+
def underscored_namespace
|
|
64
|
+
namespaces.map { inflector.underscore(_1) }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# @since 2.1.0
|
|
68
|
+
# @api private
|
|
69
|
+
def underscored_name
|
|
70
|
+
inflector.underscore(name)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# @since 2.1.0
|
|
74
|
+
# @api private
|
|
75
|
+
def module_namespace_declaration
|
|
76
|
+
namespaces.each_with_index.map { |token, i|
|
|
77
|
+
"#{OFFSET}#{INDENTATION * i}module #{inflector.camelize(token)}"
|
|
78
|
+
}.join($/)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# @since 2.1.0
|
|
82
|
+
# @api private
|
|
83
|
+
def module_namespace_end
|
|
84
|
+
namespaces.each_with_index.map { |_, i|
|
|
85
|
+
"#{OFFSET}#{INDENTATION * i}end"
|
|
86
|
+
}.reverse.join($/)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# @since 2.1.0
|
|
90
|
+
# @api private
|
|
91
|
+
def module_namespace_offset
|
|
92
|
+
"#{OFFSET}#{INDENTATION * namespaces.count}"
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title><%= humanized_app_name %> - <%= humanized_slice_name %></title>
|
|
7
7
|
<%- if bundled_assets? -%>
|
|
8
|
-
<%%=
|
|
8
|
+
<%%= favicon_tag %>
|
|
9
9
|
<%= stylesheet_erb_tag %>
|
|
10
10
|
<%- end -%>
|
|
11
11
|
</head>
|
|
@@ -38,13 +38,13 @@ module Hanami
|
|
|
38
38
|
# @since 2.1.0
|
|
39
39
|
# @api private
|
|
40
40
|
def stylesheet_erb_tag
|
|
41
|
-
%(<%=
|
|
41
|
+
%(<%= stylesheet_tag "#{slice}/app" %>)
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
# @since 2.1.0
|
|
45
45
|
# @api private
|
|
46
46
|
def javascript_erb_tag
|
|
47
|
-
%(<%=
|
|
47
|
+
%(<%= javascript_tag "#{slice}/app" %>)
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
private
|
|
@@ -27,12 +27,12 @@ module Hanami
|
|
|
27
27
|
def hanami_gem(name)
|
|
28
28
|
gem_name = name == "hanami" ? "hanami" : "hanami-#{name}"
|
|
29
29
|
|
|
30
|
-
%(gem "#{gem_name}", #{
|
|
30
|
+
%(gem "#{gem_name}", #{hanami_gem_version(name)})
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
# @since 2.0.0
|
|
34
34
|
# @api private
|
|
35
|
-
def
|
|
35
|
+
def hanami_gem_version(gem_name)
|
|
36
36
|
if hanami_head?
|
|
37
37
|
%(github: "hanami/#{gem_name}", branch: "main")
|
|
38
38
|
else
|
|
@@ -40,6 +40,16 @@ module Hanami
|
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
+
# @since 2.1.0
|
|
44
|
+
# @api private
|
|
45
|
+
def hanami_assets_npm_package
|
|
46
|
+
if hanami_head?
|
|
47
|
+
%("hanami-assets": "hanami/assets-js#main")
|
|
48
|
+
else
|
|
49
|
+
%("hanami-assets": "#{Version.npm_package_requirement}")
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
43
53
|
# @since 2.0.0
|
|
44
54
|
# @api private
|
|
45
55
|
def camelized_app_name
|
|
@@ -82,6 +92,14 @@ module Hanami
|
|
|
82
92
|
Hanami.bundled?("hanami-assets")
|
|
83
93
|
end
|
|
84
94
|
|
|
95
|
+
# @since 2.1.0
|
|
96
|
+
# @api private
|
|
97
|
+
#
|
|
98
|
+
# @see https://rubyreferences.github.io/rubychanges/3.1.html#values-in-hash-literals-and-keyword-arguments-can-be-omitted
|
|
99
|
+
def ruby_omit_hash_values?
|
|
100
|
+
RUBY_VERSION >= "3.1"
|
|
101
|
+
end
|
|
102
|
+
|
|
85
103
|
private
|
|
86
104
|
|
|
87
105
|
# @since 2.0.0
|
|
@@ -1,11 +1,82 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>The page you were looking for doesn’t exist (404)</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
--foreground-rgb: 0, 0, 0;
|
|
10
|
+
--background-rgb: 255, 255, 255;
|
|
11
|
+
--font-sans: ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@media (prefers-color-scheme: dark) {
|
|
15
|
+
:root {
|
|
16
|
+
--foreground-rgb: 255, 255, 255;
|
|
17
|
+
--background-rgb: 0, 0, 0;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
* {
|
|
22
|
+
box-sizing: border-box;
|
|
23
|
+
margin: 0;
|
|
24
|
+
padding: 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
body,
|
|
28
|
+
html {
|
|
29
|
+
max-width: 100vw;
|
|
30
|
+
overflow-x: hidden;
|
|
31
|
+
font-size: 100%;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
body {
|
|
35
|
+
color: rgb(var(--foreground-rgb));
|
|
36
|
+
background: rgb(var(--background-rgb));
|
|
37
|
+
font-family: var(--font-sans);
|
|
38
|
+
font-style: normal;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
main {
|
|
42
|
+
display: flex;
|
|
43
|
+
flex-direction: column;
|
|
44
|
+
align-items: center;
|
|
45
|
+
justify-content: center;
|
|
46
|
+
height: 100vh;
|
|
47
|
+
padding: 0 4vw;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.message {
|
|
51
|
+
display: flex;
|
|
52
|
+
gap: 1rem;
|
|
53
|
+
flex-direction: column;
|
|
54
|
+
text-align: center;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.message h1 {
|
|
58
|
+
font-size: 2rem;
|
|
59
|
+
font-weight: 500;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
p {
|
|
63
|
+
line-height: 1.6;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@media (prefers-color-scheme: dark) {
|
|
67
|
+
html {
|
|
68
|
+
color-scheme: dark;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
</style>
|
|
5
72
|
</head>
|
|
6
73
|
<body>
|
|
7
74
|
<!-- This file lives in public/404.html -->
|
|
8
|
-
<
|
|
9
|
-
|
|
75
|
+
<main>
|
|
76
|
+
<div class="message">
|
|
77
|
+
<h1>404</h1>
|
|
78
|
+
<p>The page you were looking for doesn’t exist.</p>
|
|
79
|
+
</div>
|
|
80
|
+
</main>
|
|
10
81
|
</body>
|
|
11
82
|
</html>
|
|
@@ -1,11 +1,82 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>We’re sorry, but something went wrong (500)</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
--foreground-rgb: 0, 0, 0;
|
|
10
|
+
--background-rgb: 255, 255, 255;
|
|
11
|
+
--font-sans: ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@media (prefers-color-scheme: dark) {
|
|
15
|
+
:root {
|
|
16
|
+
--foreground-rgb: 255, 255, 255;
|
|
17
|
+
--background-rgb: 0, 0, 0;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
* {
|
|
22
|
+
box-sizing: border-box;
|
|
23
|
+
margin: 0;
|
|
24
|
+
padding: 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
body,
|
|
28
|
+
html {
|
|
29
|
+
max-width: 100vw;
|
|
30
|
+
overflow-x: hidden;
|
|
31
|
+
font-size: 100%;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
body {
|
|
35
|
+
color: rgb(var(--foreground-rgb));
|
|
36
|
+
background: rgb(var(--background-rgb));
|
|
37
|
+
font-family: var(--font-sans);
|
|
38
|
+
font-style: normal;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
main {
|
|
42
|
+
display: flex;
|
|
43
|
+
flex-direction: column;
|
|
44
|
+
align-items: center;
|
|
45
|
+
justify-content: center;
|
|
46
|
+
height: 100vh;
|
|
47
|
+
padding: 0 4vw;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.message {
|
|
51
|
+
display: flex;
|
|
52
|
+
gap: 1rem;
|
|
53
|
+
flex-direction: column;
|
|
54
|
+
text-align: center;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.message h1 {
|
|
58
|
+
font-size: 2rem;
|
|
59
|
+
font-weight: 500;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
p {
|
|
63
|
+
line-height: 1.6;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@media (prefers-color-scheme: dark) {
|
|
67
|
+
html {
|
|
68
|
+
color-scheme: dark;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
</style>
|
|
5
72
|
</head>
|
|
6
73
|
<body>
|
|
7
74
|
<!-- This file lives in public/500.html -->
|
|
8
|
-
<
|
|
9
|
-
|
|
75
|
+
<main>
|
|
76
|
+
<div class="message">
|
|
77
|
+
<h1>500</h1>
|
|
78
|
+
<p>We’re sorry, but something went wrong.</p>
|
|
79
|
+
</div>
|
|
80
|
+
</main>
|
|
10
81
|
</body>
|
|
11
82
|
</html>
|
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title><%= humanized_app_name %></title>
|
|
7
7
|
<%- if generate_assets? -%>
|
|
8
|
-
<%%=
|
|
9
|
-
<%%=
|
|
8
|
+
<%%= favicon_tag %>
|
|
9
|
+
<%%= stylesheet_tag "app" %>
|
|
10
10
|
<%- end -%>
|
|
11
11
|
</head>
|
|
12
12
|
<body>
|
|
13
13
|
<%%= yield %>
|
|
14
14
|
<%- if generate_assets? -%>
|
|
15
|
-
<%%=
|
|
15
|
+
<%%= javascript_tag "app" %>
|
|
16
16
|
<%- end -%>
|
|
17
17
|
</body>
|
|
18
18
|
</html>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as assets from "hanami-assets";
|
|
2
|
+
|
|
3
|
+
await assets.run();
|
|
4
|
+
|
|
5
|
+
// To provide additional esbuild (https://esbuild.github.io) options, use the following:
|
|
6
|
+
//
|
|
7
|
+
// await assets.run({
|
|
8
|
+
// esbuildOptionsFn: (args, esbuildOptions) => {
|
|
9
|
+
// // Add to esbuildOptions here. Use `args.watch` as a condition for different options for
|
|
10
|
+
// // compile vs watch.
|
|
11
|
+
//
|
|
12
|
+
// return esbuildOptions;
|
|
13
|
+
// }
|
|
14
|
+
// });
|
|
@@ -1,17 +1,47 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
#
|
|
4
|
+
# Environment and port
|
|
5
|
+
#
|
|
6
|
+
port ENV.fetch("<%= Hanami::Port::ENV_VAR %>", <%= Hanami::Port::DEFAULT %>)
|
|
7
|
+
environment ENV.fetch("HANAMI_ENV", "development")
|
|
8
|
+
|
|
9
|
+
#
|
|
10
|
+
# Threads within each Puma/Ruby process (aka worker)
|
|
11
|
+
#
|
|
12
|
+
|
|
13
|
+
# Configure the minimum and maximum number of threads to use to answer requests.
|
|
3
14
|
max_threads_count = ENV.fetch("HANAMI_MAX_THREADS", 5)
|
|
4
15
|
min_threads_count = ENV.fetch("HANAMI_MIN_THREADS") { max_threads_count }
|
|
16
|
+
|
|
5
17
|
threads min_threads_count, max_threads_count
|
|
6
18
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
19
|
+
#
|
|
20
|
+
# Workers (aka Puma/Ruby processes)
|
|
21
|
+
#
|
|
10
22
|
|
|
11
|
-
|
|
12
|
-
|
|
23
|
+
puma_concurrency = Integer(ENV.fetch("HANAMI_WEB_CONCURRENCY", 0))
|
|
24
|
+
puma_cluster_mode = puma_concurrency > 1
|
|
25
|
+
|
|
26
|
+
# How many worker (Puma/Ruby) processes to run.
|
|
27
|
+
# Typically this is set to the number of available cores.
|
|
28
|
+
workers puma_concurrency
|
|
29
|
+
|
|
30
|
+
#
|
|
31
|
+
# Cluster mode (aka multiple workers)
|
|
32
|
+
#
|
|
33
|
+
|
|
34
|
+
if puma_cluster_mode
|
|
35
|
+
# Preload the application before starting the workers. Only in cluster mode.
|
|
36
|
+
preload_app!
|
|
37
|
+
|
|
38
|
+
# Code to run immediately before master process forks workers (once on boot).
|
|
39
|
+
#
|
|
40
|
+
# These hooks can block if necessary to wait for background operations unknown
|
|
41
|
+
# to puma to finish before the process terminates. This can be used to close
|
|
42
|
+
# any connections to remote servers (database, redis, …) that were opened when
|
|
43
|
+
# preloading the code.
|
|
44
|
+
before_fork do
|
|
13
45
|
Hanami.shutdown
|
|
14
46
|
end
|
|
15
47
|
end
|
|
16
|
-
|
|
17
|
-
preload_app!
|
|
@@ -43,6 +43,9 @@ module Hanami
|
|
|
43
43
|
fs.write("Procfile.dev", t("procfile.erb", context))
|
|
44
44
|
fs.write("config.ru", t("config_ru.erb", context))
|
|
45
45
|
|
|
46
|
+
fs.write("bin/dev", file("dev"))
|
|
47
|
+
fs.chmod("bin/dev", 0o755)
|
|
48
|
+
|
|
46
49
|
fs.write("config/app.rb", t("app.erb", context))
|
|
47
50
|
fs.write("config/settings.rb", t("settings.erb", context))
|
|
48
51
|
fs.write("config/routes.rb", t("routes.erb", context))
|
|
@@ -58,13 +61,15 @@ module Hanami
|
|
|
58
61
|
fs.write("app/templates/layouts/app.html.erb", t("app_layout.erb", context))
|
|
59
62
|
|
|
60
63
|
if context.generate_assets?
|
|
64
|
+
fs.write("package.json", t("package.json.erb", context))
|
|
65
|
+
fs.write("config/assets.js", file("assets.js"))
|
|
61
66
|
fs.write("app/assets/js/app.js", t("app_js.erb", context))
|
|
62
67
|
fs.write("app/assets/css/app.css", t("app_css.erb", context))
|
|
63
|
-
fs.write("app/assets/images/favicon.ico",
|
|
68
|
+
fs.write("app/assets/images/favicon.ico", file("favicon.ico"))
|
|
64
69
|
end
|
|
65
70
|
|
|
66
|
-
fs.write("public/404.html",
|
|
67
|
-
fs.write("public/500.html",
|
|
71
|
+
fs.write("public/404.html", file("404.html"))
|
|
72
|
+
fs.write("public/500.html", file("500.html"))
|
|
68
73
|
end
|
|
69
74
|
|
|
70
75
|
def template(path, context)
|
|
@@ -77,6 +82,10 @@ module Hanami
|
|
|
77
82
|
end
|
|
78
83
|
|
|
79
84
|
alias_method :t, :template
|
|
85
|
+
|
|
86
|
+
def file(path)
|
|
87
|
+
File.read(File.join(__dir__, "app", path))
|
|
88
|
+
end
|
|
80
89
|
end
|
|
81
90
|
end
|
|
82
91
|
end
|
|
@@ -9,7 +9,7 @@ module Hanami
|
|
|
9
9
|
# @since 2.0.0
|
|
10
10
|
# @api private
|
|
11
11
|
def self.version
|
|
12
|
-
return Hanami::VERSION if
|
|
12
|
+
return Hanami::VERSION if Hanami.const_defined?(:VERSION)
|
|
13
13
|
|
|
14
14
|
Hanami::CLI::VERSION
|
|
15
15
|
end
|
|
@@ -26,10 +26,22 @@ module Hanami
|
|
|
26
26
|
"~> #{result}"
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
+
def self.npm_package_requirement
|
|
30
|
+
result = version
|
|
31
|
+
# Change "2.1.0.beta2.1" to "2.1.0-beta.2" (the only format tolerable by `npm install`)
|
|
32
|
+
if prerelease?
|
|
33
|
+
result = result
|
|
34
|
+
.sub(/\.(alpha|beta|rc)/, '-\1')
|
|
35
|
+
.sub(/(alpha|beta|rc)(\d+)(?:\.\d+)?\Z/, '\1.\2')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
"^#{result}"
|
|
39
|
+
end
|
|
40
|
+
|
|
29
41
|
# @since 2.0.0
|
|
30
42
|
# @api private
|
|
31
43
|
def self.prerelease?
|
|
32
|
-
version
|
|
44
|
+
version.match?(/alpha|beta|rc/)
|
|
33
45
|
end
|
|
34
46
|
|
|
35
47
|
# @example
|
data/lib/hanami/cli/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hanami-cli
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.1.0.
|
|
4
|
+
version: 2.1.0.rc2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Luca Guidi
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-
|
|
11
|
+
date: 2023-11-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -216,6 +216,7 @@ files:
|
|
|
216
216
|
- lib/hanami/cli/commands/app/dev.rb
|
|
217
217
|
- lib/hanami/cli/commands/app/generate.rb
|
|
218
218
|
- lib/hanami/cli/commands/app/generate/action.rb
|
|
219
|
+
- lib/hanami/cli/commands/app/generate/part.rb
|
|
219
220
|
- lib/hanami/cli/commands/app/generate/slice.rb
|
|
220
221
|
- lib/hanami/cli/commands/app/generate/view.rb
|
|
221
222
|
- lib/hanami/cli/commands/app/install.rb
|
|
@@ -237,6 +238,12 @@ files:
|
|
|
237
238
|
- lib/hanami/cli/generators/app/action/template.html.erb
|
|
238
239
|
- lib/hanami/cli/generators/app/action/view.erb
|
|
239
240
|
- lib/hanami/cli/generators/app/action_context.rb
|
|
241
|
+
- lib/hanami/cli/generators/app/part.rb
|
|
242
|
+
- lib/hanami/cli/generators/app/part/app_base_part.erb
|
|
243
|
+
- lib/hanami/cli/generators/app/part/app_part.erb
|
|
244
|
+
- lib/hanami/cli/generators/app/part/slice_base_part.erb
|
|
245
|
+
- lib/hanami/cli/generators/app/part/slice_part.erb
|
|
246
|
+
- lib/hanami/cli/generators/app/part_context.rb
|
|
240
247
|
- lib/hanami/cli/generators/app/slice.rb
|
|
241
248
|
- lib/hanami/cli/generators/app/slice/action.erb
|
|
242
249
|
- lib/hanami/cli/generators/app/slice/app_css.erb
|
|
@@ -265,13 +272,16 @@ files:
|
|
|
265
272
|
- lib/hanami/cli/generators/gem/app/app_css.erb
|
|
266
273
|
- lib/hanami/cli/generators/gem/app/app_js.erb
|
|
267
274
|
- lib/hanami/cli/generators/gem/app/app_layout.erb
|
|
275
|
+
- lib/hanami/cli/generators/gem/app/assets.js
|
|
268
276
|
- lib/hanami/cli/generators/gem/app/config_ru.erb
|
|
277
|
+
- lib/hanami/cli/generators/gem/app/dev
|
|
269
278
|
- lib/hanami/cli/generators/gem/app/env.erb
|
|
270
279
|
- lib/hanami/cli/generators/gem/app/favicon.ico
|
|
271
280
|
- lib/hanami/cli/generators/gem/app/gemfile.erb
|
|
272
281
|
- lib/hanami/cli/generators/gem/app/gitignore.erb
|
|
273
282
|
- lib/hanami/cli/generators/gem/app/helpers.erb
|
|
274
283
|
- lib/hanami/cli/generators/gem/app/keep.erb
|
|
284
|
+
- lib/hanami/cli/generators/gem/app/package.json.erb
|
|
275
285
|
- lib/hanami/cli/generators/gem/app/procfile.erb
|
|
276
286
|
- lib/hanami/cli/generators/gem/app/puma.erb
|
|
277
287
|
- lib/hanami/cli/generators/gem/app/rakefile.erb
|
|
@@ -320,7 +330,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
320
330
|
- !ruby/object:Gem::Version
|
|
321
331
|
version: 1.3.1
|
|
322
332
|
requirements: []
|
|
323
|
-
rubygems_version: 3.4.
|
|
333
|
+
rubygems_version: 3.4.21
|
|
324
334
|
signing_key:
|
|
325
335
|
specification_version: 4
|
|
326
336
|
summary: Hanami CLI
|