Skip to content

Commit dfe885b

Browse files
committed
Merge branch 'main' into 2.1.x
2 parents 319b81a + a02dc31 commit dfe885b

37 files changed

+1934
-276
lines changed

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,25 @@
22

33
Hanami Command Line Interface
44

5+
## v2.1.0.rc1 - 2023-11-01
6+
7+
### Added
8+
9+
- [Tim Riley] `hanami new` to generate `bin/dev` as configuration for `hanami dev`
10+
- [Luca Guidi] Introducing `hanami generate part` to generate view parts
11+
12+
### Fixed
13+
14+
- [Luca Guidi] `hanami new` generates a fully documented Puma configuration in `config/puma.rb`
15+
16+
### Changed
17+
18+
- [Tim Riley] `hanami new` generates a `config/assets.mjs` as Assets configuration
19+
- [Tim Riley] `hanami new` generates a leaner `package.json`
20+
- [Tim Riley] `hanami new` doesn't generate a default root route anymore
21+
- [Aaron Moodie & Tim Riley] `hanami new` to generate a redesigned 404 and 500 error pages
22+
- [Luca Guidi] When generating a RESTful action, skip `create`, if `new` is present, and `update`, if `edit` is present
23+
524
## v2.1.0.beta2 - 2023-10-04
625

726
### Added

Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ gem "hanami-controller", github: "hanami/controller", branch: "main"
1515
gem "hanami-router", github: "hanami/router", branch: "main"
1616
gem "hanami-utils", github: "hanami/utils", branch: "main"
1717

18+
gem "dry-files", github: "dry-rb/dry-files", branch: "main"
19+
1820
gem "rack"
1921

2022
group :test do

lib/hanami/cli/commands/app.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ def self.extended(base)
3131
prefix.register "slice", Generate::Slice
3232
prefix.register "action", Generate::Action
3333
prefix.register "view", Generate::View
34+
prefix.register "part", Generate::Part
3435
end
3536
end
3637
end

lib/hanami/cli/commands/app/assets/command.rb

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def initialize(config: app.config.assets, system_call: SystemCall.new, **)
2323
def call(**)
2424
cmd, *args = cmd_with_args
2525

26-
system_call.call(cmd, *args, env: env)
26+
system_call.call(cmd, *args)
2727
end
2828

2929
private
@@ -39,20 +39,7 @@ def call(**)
3939
# @since 2.1.0
4040
# @api private
4141
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-
)
42+
[config.package_manager_run_command, "assets"]
5643
end
5744

5845
# @since 2.1.0

lib/hanami/cli/commands/app/assets/watch.rb

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,7 @@ def initialize(config: app.config.assets, system_call: InteractiveSystemCall.new
2222
# @since 2.1.0
2323
# @api private
2424
def cmd_with_args
25-
super +
26-
[
27-
"--",
28-
"--watch"
29-
]
25+
super + ["--", "--watch"]
3026
end
3127
end
3228
end

lib/hanami/cli/commands/app/dev.rb

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,6 @@ class Dev < App::Command
1313
# @api private
1414
desc "Start the application in development mode"
1515

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-
2616
# @since 2.1.0
2717
# @api private
2818
def initialize(interactive_system_call: InteractiveSystemCall.new, **)
@@ -32,8 +22,8 @@ def initialize(interactive_system_call: InteractiveSystemCall.new, **)
3222

3323
# @since 2.1.0
3424
# @api private
35-
def call(procfile: nil, **)
36-
bin, args = executable(procfile: procfile)
25+
def call(**)
26+
bin, args = executable
3727
interactive_system_call.call(bin, *args)
3828
end
3929

@@ -45,10 +35,8 @@ def call(procfile: nil, **)
4535

4636
# @since 2.1.0
4737
# @api private
48-
def executable(procfile: nil)
49-
# TODO: support other implementations of Foreman
50-
# See: https://github.com/ddollar/foreman#ports
51-
["foreman", ["start", "-f", procfile || "Procfile.dev"]]
38+
def executable
39+
[::File.join("bin", "dev")]
5240
end
5341
end
5442
end
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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+
argument :name, required: true, desc: "Part name"
16+
option :slice, required: false, desc: "Slice name"
17+
18+
example [
19+
%(book (MyApp::Views::Parts::Book)),
20+
%(book --slice=admin (Admin::Views::Parts::Book)),
21+
]
22+
attr_reader :generator
23+
private :generator
24+
25+
# @since 2.0.0
26+
# @api private
27+
def initialize(
28+
fs: Hanami::CLI::Files.new,
29+
inflector: Dry::Inflector.new,
30+
generator: Generators::App::Part.new(fs: fs, inflector: inflector),
31+
**
32+
)
33+
@generator = generator
34+
super(fs: fs)
35+
end
36+
37+
# @since 2.0.0
38+
# @api private
39+
def call(name:, slice: nil, **)
40+
slice = inflector.underscore(Shellwords.shellescape(slice)) if slice
41+
42+
generator.call(app.namespace, name, slice)
43+
end
44+
end
45+
end
46+
end
47+
end
48+
end
49+
end

lib/hanami/cli/commands/app/install.rb

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -33,37 +33,9 @@ class Install < Command
3333
# @api private
3434
option :head, type: :boolean, desc: "Install head deps", default: DEFAULT_HEAD
3535

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-
4336
# @since 2.0.0
4437
# @api private
4538
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
6739
end
6840
end
6941
end

lib/hanami/cli/commands/gem/new.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,20 +58,28 @@ class New < Command
5858
]
5959
# rubocop:enable Layout/LineLength
6060

61+
# rubocop:disable Metrics/ParameterLists
62+
6163
# @since 2.0.0
6264
# @api private
6365
def initialize(
6466
fs: Hanami::CLI::Files.new,
6567
inflector: Dry::Inflector.new,
6668
bundler: CLI::Bundler.new(fs: fs),
6769
generator: Generators::Gem::App.new(fs: fs, inflector: inflector),
70+
system_call: SystemCall.new,
6871
**other
6972
)
7073
@bundler = bundler
7174
@generator = generator
75+
@system_call = system_call
7276
super(fs: fs, inflector: inflector, **other)
7377
end
7478

79+
# rubocop:enable Metrics/ParameterLists
80+
81+
# rubocop:disable Metrics/AbcSize
82+
7583
# @since 2.0.0
7684
# @api private
7785
def call(app:, head: HEAD_DEFAULT, skip_install: SKIP_INSTALL_DEFAULT, skip_assets: SKIP_ASSETS_DEFAULT, **)
@@ -88,17 +96,25 @@ def call(app:, head: HEAD_DEFAULT, skip_install: SKIP_INSTALL_DEFAULT, skip_asse
8896
else
8997
out.puts "Running Bundler install..."
9098
bundler.install!
99+
100+
unless skip_assets
101+
out.puts "Running npm install..."
102+
system_call.call("npm", ["install"])
103+
end
104+
91105
out.puts "Running Hanami install..."
92106
run_install_commmand!(head: head)
93107
end
94108
end
95109
end
96110
end
111+
# rubocop:enable Metrics/AbcSize
97112

98113
private
99114

100115
attr_reader :bundler
101116
attr_reader :generator
117+
attr_reader :system_call
102118

103119
def run_install_commmand!(head:)
104120
head_flag = head ? " --head" : ""

lib/hanami/cli/generators/app/action.rb

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ def call(app, controller, action, url, http, format, skip_view, slice, context:
5656
}.freeze
5757
private_constant :ROUTE_RESTFUL_URL_SUFFIXES
5858

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+
5967
PATH_SEPARATOR = "/"
6068
private_constant :PATH_SEPARATOR
6169

@@ -77,7 +85,7 @@ def generate_for_slice(controller, action, url, http, format, skip_view, slice,
7785
fs.mkdir(directory = fs.join(slice_directory, "actions", controller))
7886
fs.write(fs.join(directory, "#{action}.rb"), t("slice_action.erb", context))
7987

80-
unless skip_view
88+
if generate_view?(skip_view, action, directory)
8189
fs.mkdir(directory = fs.join(slice_directory, "views", controller))
8290
fs.write(fs.join(directory, "#{action}.rb"), t("slice_view.erb", context))
8391

@@ -97,12 +105,15 @@ def generate_for_app(controller, action, url, http, format, skip_view, context)
97105
fs.mkdir(directory = fs.join("app", "actions", controller))
98106
fs.write(fs.join(directory, "#{action}.rb"), t("action.erb", context))
99107

100-
unless skip_view
101-
fs.mkdir(directory = fs.join("app", "views", controller))
102-
fs.write(fs.join(directory, "#{action}.rb"), t("view.erb", context))
108+
view = action
109+
view_directory = fs.join("app", "views", controller)
103110

104-
fs.mkdir(directory = fs.join("app", "templates", controller))
105-
fs.write(fs.join(directory, "#{action}.#{format}.erb"),
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"),
106117
t(template_with_format_ext("template", format), context))
107118
end
108119
end
@@ -117,6 +128,35 @@ def route(controller, action, url, http)
117128
http)} "#{route_url(controller, action, url)}", to: "#{controller.join('.')}.#{action}")
118129
end
119130

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+
120160
def template_with_format_ext(name, format)
121161
ext =
122162
case format.to_sym

0 commit comments

Comments
 (0)