hanami-cli 2.0.2 → 2.1.0.beta1
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/{.action_hero.yml → .repobot.yml} +1 -3
- data/CHANGELOG.md +26 -0
- data/LICENSE.md +1 -1
- data/README.md +1 -1
- data/lib/hanami/cli/bundler.rb +7 -4
- data/lib/hanami/cli/commands/app/db/rollback.rb +30 -6
- data/lib/hanami/cli/commands/app/db/utils/database.rb +5 -1
- data/lib/hanami/cli/commands/app/generate/action.rb +7 -4
- data/lib/hanami/cli/commands/app/generate/view.rb +57 -0
- data/lib/hanami/cli/commands/app/generate.rb +2 -2
- data/lib/hanami/cli/commands/app.rb +1 -0
- data/lib/hanami/cli/generators/app/action/slice_template.html.erb +1 -0
- data/lib/hanami/cli/generators/app/action/slice_view.erb +10 -0
- data/lib/hanami/cli/generators/app/action/template.html.erb +1 -2
- data/lib/hanami/cli/generators/app/action/view.erb +2 -5
- data/lib/hanami/cli/generators/app/action.rb +31 -16
- data/lib/hanami/cli/generators/app/action_context.rb +1 -1
- data/lib/hanami/cli/generators/app/slice/helpers.erb +10 -0
- data/lib/hanami/cli/generators/app/slice/layouts_app.html.erb +1 -0
- data/lib/hanami/cli/generators/app/slice/view.erb +0 -2
- data/lib/hanami/cli/generators/app/slice.rb +8 -5
- data/lib/hanami/cli/generators/app/view/app_template.html.erb +1 -0
- data/lib/hanami/cli/generators/app/view/app_view.erb +10 -0
- data/lib/hanami/cli/generators/app/view/slice_template.html.erb +1 -0
- data/lib/hanami/cli/generators/app/view/slice_view.erb +10 -0
- data/lib/hanami/cli/generators/app/view.rb +89 -0
- data/lib/hanami/cli/generators/app/view_context.rb +100 -0
- data/lib/hanami/cli/generators/context.rb +1 -1
- data/lib/hanami/cli/generators/gem/app/404.html +11 -0
- data/lib/hanami/cli/generators/gem/app/500.html +11 -0
- data/lib/hanami/cli/generators/gem/app/gemfile.erb +2 -0
- data/lib/hanami/cli/generators/gem/app/gitignore.erb +2 -0
- data/lib/hanami/cli/generators/gem/app/helpers.erb +10 -0
- data/lib/hanami/cli/generators/gem/app/layouts_app.html.erb +1 -0
- data/lib/hanami/cli/generators/gem/app/puma.erb +5 -3
- data/lib/hanami/cli/generators/gem/app/view.erb +9 -0
- data/lib/hanami/cli/generators/gem/app.rb +7 -0
- data/lib/hanami/cli/naming.rb +25 -0
- data/lib/hanami/cli/url.rb +1 -1
- data/lib/hanami/cli/version.rb +1 -1
- metadata +24 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '078a7a10f1196ed8635a9c27ee48ac10178cdcff50d2646138f61b55f79f86a7'
|
|
4
|
+
data.tar.gz: 870c056fc5da9f5952daf357ca2861f0e276510c6ca1e63a2f821af76ebdd09a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d70ee9d87779f442c25517abfefde102460848e8a29ba9ef30ae28cc2b2593f73027dad42b99e5617820952a84fd22013a8de5d039fb2e6161a64fd2eef706a1
|
|
7
|
+
data.tar.gz: 815418cd1c416bea1f7a77c56dff20ed143b582795bbcd79904260509c8c62c7d62a7be76c11305d26dc793dd2c2a13fcba0532c365ad47278212159e40eff69
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
Hanami Command Line Interface
|
|
4
4
|
|
|
5
|
+
## v2.1.0.beta1 - 2023-06-29
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- [Tim Riley] `hanami new` to generate default views, templates, and helpers
|
|
10
|
+
- [Tim Riley] `hanami generate slice` to generate default views, templates, and helpers
|
|
11
|
+
- [Tim Riley] `hanami generate action` to generate associated view and template
|
|
12
|
+
- [Tim Riley] Introduced `hanami generate view`
|
|
13
|
+
- [Tim Riley] `hanami new` to generate `Gemfile` with `hanami-view` and `hanami-webconsole` gems
|
|
14
|
+
- [Tim Riley] `hanami new` to generate default error pages for `404` and `500` HTTP errors
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- [Philip Arndt] `hanami server` to start only one Puma worker by default
|
|
19
|
+
|
|
20
|
+
## v2.0.3 - 2023-02-01
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- [Luca Guidi] Generate a default `.gitignore` when using `hanami new`
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- [dsisnero] Ensure to run automatically bundle gems when using `hanami new` on Windows
|
|
29
|
+
- [Luca Guidi] Ensure to generate the correct action identifier in routes when using `hanami generate action` with deeply nested action name
|
|
30
|
+
|
|
5
31
|
## v2.0.2 - 2022-12-25
|
|
6
32
|
|
|
7
33
|
### Added
|
data/LICENSE.md
CHANGED
data/README.md
CHANGED
data/lib/hanami/cli/bundler.rb
CHANGED
|
@@ -4,8 +4,8 @@ require "bundler"
|
|
|
4
4
|
require "open3"
|
|
5
5
|
require "etc"
|
|
6
6
|
require "dry/files"
|
|
7
|
-
require_relative "
|
|
8
|
-
require_relative "
|
|
7
|
+
require_relative "system_call"
|
|
8
|
+
require_relative "errors"
|
|
9
9
|
|
|
10
10
|
module Hanami
|
|
11
11
|
module CLI
|
|
@@ -146,10 +146,13 @@ module Hanami
|
|
|
146
146
|
# @since 2.0.0
|
|
147
147
|
# @api private
|
|
148
148
|
def which(cmd)
|
|
149
|
+
exts = ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : [""]
|
|
149
150
|
# Adapted from https://stackoverflow.com/a/5471032/498386
|
|
150
151
|
ENV["PATH"].split(File::PATH_SEPARATOR).each do |path|
|
|
151
|
-
|
|
152
|
-
|
|
152
|
+
exts.each do |ext|
|
|
153
|
+
exe = fs.join(path, "#{cmd}#{ext}")
|
|
154
|
+
return exe if fs.executable?(exe) && !fs.directory?(exe)
|
|
155
|
+
end
|
|
153
156
|
end
|
|
154
157
|
|
|
155
158
|
nil
|
|
@@ -20,12 +20,20 @@ module Hanami
|
|
|
20
20
|
migration_code, migration_name = find_migration(target)
|
|
21
21
|
|
|
22
22
|
if migration_name.nil?
|
|
23
|
-
|
|
23
|
+
output = if target
|
|
24
|
+
"==> migration file for target #{target} was not found"
|
|
25
|
+
else
|
|
26
|
+
"==> no migrations to rollback"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
out.puts output
|
|
24
30
|
return
|
|
25
31
|
end
|
|
26
32
|
|
|
27
33
|
measure "database #{database.name} rolled back to #{migration_name}" do
|
|
28
34
|
database.run_migrations(target: Integer(migration_code))
|
|
35
|
+
|
|
36
|
+
true
|
|
29
37
|
end
|
|
30
38
|
|
|
31
39
|
run_command Structure::Dump if dump
|
|
@@ -33,14 +41,30 @@ module Hanami
|
|
|
33
41
|
|
|
34
42
|
private
|
|
35
43
|
|
|
36
|
-
def find_migration(code)
|
|
37
|
-
|
|
44
|
+
def find_migration(code) # rubocop:disable Metrics/PerceivedComplexity
|
|
45
|
+
applied_migrations = database.applied_migrations
|
|
46
|
+
|
|
47
|
+
return if applied_migrations.empty?
|
|
48
|
+
|
|
49
|
+
# Rollback to initial state if we have only one migration and
|
|
50
|
+
# no target is specified. In this case the rollback target
|
|
51
|
+
# will be the current migration timestamp minus 1
|
|
52
|
+
if applied_migrations.one? && code.nil?
|
|
53
|
+
migration = applied_migrations.first
|
|
54
|
+
|
|
55
|
+
migration_code = Integer(migration.split("_").first) - 1
|
|
56
|
+
migration_name = "initial state"
|
|
57
|
+
|
|
58
|
+
return [migration_code, migration_name]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Otherwise rollback to target or to previous migration
|
|
62
|
+
migration =
|
|
38
63
|
if code
|
|
39
|
-
|
|
64
|
+
applied_migrations.detect { |m| m.split("_").first == code }
|
|
40
65
|
else
|
|
41
|
-
|
|
66
|
+
applied_migrations[-2]
|
|
42
67
|
end
|
|
43
|
-
}
|
|
44
68
|
|
|
45
69
|
return unless migration
|
|
46
70
|
|
|
@@ -139,7 +139,11 @@ module Hanami
|
|
|
139
139
|
@sequel_migrator ||= begin
|
|
140
140
|
require "sequel"
|
|
141
141
|
Sequel.extension :migration
|
|
142
|
-
|
|
142
|
+
|
|
143
|
+
require "rom/sql"
|
|
144
|
+
ROM::SQL.with_gateway(gateway) do
|
|
145
|
+
Sequel::TimestampMigrator.new(migrator.connection, migrations_path, {})
|
|
146
|
+
end
|
|
143
147
|
end
|
|
144
148
|
end
|
|
145
149
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "dry/inflector"
|
|
4
4
|
require "dry/files"
|
|
5
5
|
require "shellwords"
|
|
6
|
+
require_relative "../../../naming"
|
|
6
7
|
require_relative "../../../errors"
|
|
7
8
|
|
|
8
9
|
module Hanami
|
|
@@ -25,8 +26,8 @@ module Hanami
|
|
|
25
26
|
option :url, required: false, type: :string, desc: "Action URL"
|
|
26
27
|
option :http, required: false, type: :string, desc: "Action HTTP method"
|
|
27
28
|
# option :format, required: false, type: :string, default: DEFAULT_FORMAT, desc: "Template format"
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
option :skip_view, required: false, type: :boolean, default: DEFAULT_SKIP_VIEW,
|
|
30
|
+
desc: "Skip view and template generation"
|
|
30
31
|
option :slice, required: false, desc: "Slice name"
|
|
31
32
|
|
|
32
33
|
# rubocop:disable Layout/LineLength
|
|
@@ -48,7 +49,9 @@ module Hanami
|
|
|
48
49
|
# @since 2.0.0
|
|
49
50
|
# @api private
|
|
50
51
|
def initialize(fs: Hanami::CLI::Files.new, inflector: Dry::Inflector.new,
|
|
52
|
+
naming: Naming.new(inflector: inflector),
|
|
51
53
|
generator: Generators::App::Action.new(fs: fs, inflector: inflector), **)
|
|
54
|
+
@naming = naming
|
|
52
55
|
@generator = generator
|
|
53
56
|
super(fs: fs)
|
|
54
57
|
end
|
|
@@ -59,7 +62,7 @@ module Hanami
|
|
|
59
62
|
# @api private
|
|
60
63
|
def call(name:, url: nil, http: nil, format: DEFAULT_FORMAT, skip_view: DEFAULT_SKIP_VIEW, slice: nil, **)
|
|
61
64
|
slice = inflector.underscore(Shellwords.shellescape(slice)) if slice
|
|
62
|
-
name =
|
|
65
|
+
name = naming.action_name(name)
|
|
63
66
|
*controller, action = name.split(ACTION_SEPARATOR)
|
|
64
67
|
|
|
65
68
|
if controller.empty?
|
|
@@ -73,7 +76,7 @@ module Hanami
|
|
|
73
76
|
|
|
74
77
|
private
|
|
75
78
|
|
|
76
|
-
attr_reader :generator
|
|
79
|
+
attr_reader :naming, :generator
|
|
77
80
|
end
|
|
78
81
|
end
|
|
79
82
|
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dry/inflector"
|
|
4
|
+
require "dry/files"
|
|
5
|
+
require "shellwords"
|
|
6
|
+
require_relative "../../../naming"
|
|
7
|
+
require_relative "../../../errors"
|
|
8
|
+
|
|
9
|
+
module Hanami
|
|
10
|
+
module CLI
|
|
11
|
+
module Commands
|
|
12
|
+
module App
|
|
13
|
+
module Generate
|
|
14
|
+
# @since 2.0.0
|
|
15
|
+
# @api private
|
|
16
|
+
class View < App::Command
|
|
17
|
+
# TODO: make this configurable
|
|
18
|
+
DEFAULT_FORMAT = "html"
|
|
19
|
+
private_constant :DEFAULT_FORMAT
|
|
20
|
+
|
|
21
|
+
# TODO: make engine configurable
|
|
22
|
+
|
|
23
|
+
argument :name, required: true, desc: "View name"
|
|
24
|
+
option :slice, required: false, desc: "Slice name"
|
|
25
|
+
|
|
26
|
+
example [
|
|
27
|
+
%(books.index (MyApp::Actions::Books::Index)),
|
|
28
|
+
%(books.index --slice=admin (Admin::Actions::Books::Index)),
|
|
29
|
+
]
|
|
30
|
+
attr_reader :generator
|
|
31
|
+
private :generator
|
|
32
|
+
|
|
33
|
+
# @since 2.0.0
|
|
34
|
+
# @api private
|
|
35
|
+
def initialize(
|
|
36
|
+
fs: Hanami::CLI::Files.new,
|
|
37
|
+
inflector: Dry::Inflector.new,
|
|
38
|
+
generator: Generators::App::View.new(fs: fs, inflector: inflector),
|
|
39
|
+
**
|
|
40
|
+
)
|
|
41
|
+
@generator = generator
|
|
42
|
+
super(fs: fs)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @since 2.0.0
|
|
46
|
+
# @api private
|
|
47
|
+
def call(name:, format: DEFAULT_FORMAT, slice: nil, **)
|
|
48
|
+
slice = inflector.underscore(Shellwords.shellescape(slice)) if slice
|
|
49
|
+
|
|
50
|
+
generator.call(app.namespace, name, format, slice)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<h1><%= camelized_slice_name %>::Views::<%= camelized_controller_name %>::<%= camelized_action_name %></h1>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module <%= camelized_slice_name %>
|
|
4
|
+
module Views
|
|
5
|
+
<%= module_controller_declaration %>
|
|
6
|
+
<%= module_controller_offset %>class <%= camelized_action_name %> < <%= camelized_slice_name %>::View
|
|
7
|
+
<%= module_controller_offset %>end
|
|
8
|
+
<%= module_controller_end %>
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
<h1><%=
|
|
2
|
-
<h2><%= template_path %></h2>
|
|
1
|
+
<h1><%= camelized_app_name %>::Views::<%= camelized_controller_name %>::<%= camelized_action_name %></h1>
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
# auto_register: false
|
|
2
1
|
# frozen_string_literal: true
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
module <%= camelized_slice_name %>
|
|
3
|
+
module <%= camelized_app_name %>
|
|
7
4
|
module Views
|
|
8
5
|
<%= module_controller_declaration %>
|
|
9
|
-
<%= module_controller_offset %>class <%= camelized_action_name %> < <%=
|
|
6
|
+
<%= module_controller_offset %>class <%= camelized_action_name %> < <%= camelized_app_name %>::View
|
|
10
7
|
<%= module_controller_offset %>end
|
|
11
8
|
<%= module_controller_end %>
|
|
12
9
|
end
|
|
@@ -66,7 +66,8 @@ module Hanami
|
|
|
66
66
|
|
|
67
67
|
attr_reader :inflector
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
# rubocop:disable Metrics/AbcSize
|
|
70
|
+
def generate_for_slice(controller, action, url, http, format, skip_view, slice, context)
|
|
70
71
|
slice_directory = fs.join("slices", slice)
|
|
71
72
|
raise MissingSliceError.new(slice) unless fs.directory?(slice_directory)
|
|
72
73
|
|
|
@@ -79,16 +80,17 @@ module Hanami
|
|
|
79
80
|
fs.mkdir(directory = fs.join(slice_directory, "actions", controller))
|
|
80
81
|
fs.write(fs.join(directory, "#{action}.rb"), t("slice_action.erb", context))
|
|
81
82
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
83
|
+
unless skip_view
|
|
84
|
+
fs.mkdir(directory = fs.join(slice_directory, "views", controller))
|
|
85
|
+
fs.write(fs.join(directory, "#{action}.rb"), t("slice_view.erb", context))
|
|
86
|
+
|
|
87
|
+
fs.mkdir(directory = fs.join(slice_directory, "templates", controller))
|
|
88
|
+
fs.write(fs.join(directory, "#{action}.#{format}.erb"),
|
|
89
|
+
t(template_with_format_ext("slice_template", format), context))
|
|
90
|
+
end
|
|
89
91
|
end
|
|
90
92
|
|
|
91
|
-
def generate_for_app(controller, action, url, http,
|
|
93
|
+
def generate_for_app(controller, action, url, http, format, skip_view, context)
|
|
92
94
|
fs.inject_line_at_class_bottom(
|
|
93
95
|
fs.join("config", "routes.rb"),
|
|
94
96
|
"class Routes",
|
|
@@ -97,7 +99,17 @@ module Hanami
|
|
|
97
99
|
|
|
98
100
|
fs.mkdir(directory = fs.join("app", "actions", controller))
|
|
99
101
|
fs.write(fs.join(directory, "#{action}.rb"), t("action.erb", context))
|
|
102
|
+
|
|
103
|
+
unless skip_view
|
|
104
|
+
fs.mkdir(directory = fs.join("app", "views", controller))
|
|
105
|
+
fs.write(fs.join(directory, "#{action}.rb"), t("view.erb", context))
|
|
106
|
+
|
|
107
|
+
fs.mkdir(directory = fs.join("app", "templates", controller))
|
|
108
|
+
fs.write(fs.join(directory, "#{action}.#{format}.erb"),
|
|
109
|
+
t(template_with_format_ext("template", format), context))
|
|
110
|
+
end
|
|
100
111
|
end
|
|
112
|
+
# rubocop:enable Metrics/AbcSize
|
|
101
113
|
|
|
102
114
|
def slice_matcher(slice)
|
|
103
115
|
/slice[[:space:]]*:#{slice}/
|
|
@@ -108,13 +120,16 @@ module Hanami
|
|
|
108
120
|
http)} "#{route_url(controller, action, url)}", to: "#{controller.join('.')}.#{action}")
|
|
109
121
|
end
|
|
110
122
|
|
|
111
|
-
def
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
123
|
+
def template_with_format_ext(name, format)
|
|
124
|
+
ext =
|
|
125
|
+
case format.to_sym
|
|
126
|
+
when :html
|
|
127
|
+
".html.erb"
|
|
128
|
+
else
|
|
129
|
+
".erb"
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
"#{name}#{ext}"
|
|
118
133
|
end
|
|
119
134
|
|
|
120
135
|
def template(path, context)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= yield %>
|
|
@@ -19,7 +19,7 @@ module Hanami
|
|
|
19
19
|
|
|
20
20
|
# @since 2.0.0
|
|
21
21
|
# @api private
|
|
22
|
-
def call(app, slice, url, context: SliceContext.new(inflector, app, slice, url))
|
|
22
|
+
def call(app, slice, url, context: SliceContext.new(inflector, app, slice, url)) # rubocop:disable Metrics/AbcSize
|
|
23
23
|
fs.inject_line_at_class_bottom(
|
|
24
24
|
fs.join("config", "routes.rb"), "class Routes", t("routes.erb", context).chomp
|
|
25
25
|
)
|
|
@@ -28,14 +28,17 @@ module Hanami
|
|
|
28
28
|
|
|
29
29
|
# fs.write("#{directory}/config/slice.rb", t("slice.erb", context))
|
|
30
30
|
fs.write(fs.join(directory, "action.rb"), t("action.erb", context))
|
|
31
|
-
|
|
31
|
+
fs.write(fs.join(directory, "view.rb"), t("view.erb", context))
|
|
32
|
+
fs.write(fs.join(directory, "views", "helpers.rb"), t("helpers.erb", context))
|
|
33
|
+
fs.write(fs.join(directory, "templates", "layouts", "app.html.erb"),
|
|
34
|
+
File.read(File.join(__dir__, "slice", "layouts_app.html.erb")))
|
|
32
35
|
# fs.write(fs.join(directory, "/entities.rb"), t("entities.erb", context))
|
|
33
36
|
# fs.write(fs.join(directory, "/repository.rb"), t("repository.erb", context))
|
|
34
37
|
|
|
35
38
|
fs.write(fs.join(directory, "actions/.keep"), t("keep.erb", context))
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
fs.write(fs.join(directory, "views/.keep"), t("keep.erb", context))
|
|
40
|
+
fs.write(fs.join(directory, "templates/.keep"), t("keep.erb", context))
|
|
41
|
+
fs.write(fs.join(directory, "templates/layouts/.keep"), t("keep.erb", context))
|
|
39
42
|
# fs.write(fs.join(directory, entities/.keep"), t("keep.erb", context))
|
|
40
43
|
# fs.write(fs.join(directory, repositories/.keep"), t("keep.erb", context))
|
|
41
44
|
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<h1><%= camelized_app_name %>::Views::<%= camelized_namespace %>::<%= camelized_name %></h1>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module <%= camelized_app_name %>
|
|
4
|
+
module Views
|
|
5
|
+
<%= module_namespace_declaration %>
|
|
6
|
+
<%= module_namespace_offset %>class <%= camelized_name %> < <%= camelized_app_name %>::View
|
|
7
|
+
<%= module_namespace_offset %>end
|
|
8
|
+
<%= module_namespace_end %>
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<h1><%= camelized_slice_name %>::Views::<%= camelized_namespace %>::<%= camelized_name %></h1>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module <%= camelized_slice_name %>
|
|
4
|
+
module Views
|
|
5
|
+
<%= module_namespace_declaration %>
|
|
6
|
+
<%= module_namespace_offset %>class <%= camelized_name %> < <%= camelized_slice_name %>::View
|
|
7
|
+
<%= module_namespace_offset %>end
|
|
8
|
+
<%= module_namespace_end %>
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
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.0.0
|
|
12
|
+
# @api private
|
|
13
|
+
class View
|
|
14
|
+
# @since 2.0.0
|
|
15
|
+
# @api private
|
|
16
|
+
def initialize(fs:, inflector:)
|
|
17
|
+
@fs = fs
|
|
18
|
+
@inflector = inflector
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @since 2.0.0
|
|
22
|
+
# @api private
|
|
23
|
+
def call(app, key, format, slice)
|
|
24
|
+
context = ViewContext.new(inflector, app, slice, key)
|
|
25
|
+
|
|
26
|
+
if slice
|
|
27
|
+
generate_for_slice(context, format, slice)
|
|
28
|
+
else
|
|
29
|
+
generate_for_app(context, format, slice)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
attr_reader :fs
|
|
36
|
+
|
|
37
|
+
attr_reader :inflector
|
|
38
|
+
|
|
39
|
+
# rubocop:disable Metrics/AbcSize
|
|
40
|
+
|
|
41
|
+
def generate_for_slice(context, format, slice)
|
|
42
|
+
slice_directory = fs.join("slices", slice)
|
|
43
|
+
raise MissingSliceError.new(slice) unless fs.directory?(slice_directory)
|
|
44
|
+
|
|
45
|
+
fs.mkdir(directory = fs.join(slice_directory, "views", context.namespaces))
|
|
46
|
+
fs.write(fs.join(directory, "#{context.name}.rb"), t("slice_view.erb", context))
|
|
47
|
+
|
|
48
|
+
fs.mkdir(directory = fs.join(slice_directory, "templates", context.namespaces))
|
|
49
|
+
fs.write(fs.join(directory, "#{context.name}.#{format}.erb"),
|
|
50
|
+
t(template_with_format_ext("slice_template", format), context))
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def generate_for_app(context, format, _slice)
|
|
54
|
+
fs.mkdir(directory = fs.join("app", "views", context.namespaces))
|
|
55
|
+
fs.write(fs.join(directory, "#{context.name}.rb"), t("app_view.erb", context))
|
|
56
|
+
|
|
57
|
+
fs.mkdir(directory = fs.join("app", "templates", context.namespaces))
|
|
58
|
+
fs.write(fs.join(directory, "#{context.name}.#{format}.erb"),
|
|
59
|
+
t(template_with_format_ext("app_template", format), context))
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# rubocop:enable Metrics/AbcSize
|
|
63
|
+
|
|
64
|
+
def template_with_format_ext(name, format)
|
|
65
|
+
ext =
|
|
66
|
+
case format.to_sym
|
|
67
|
+
when :html
|
|
68
|
+
".html.erb"
|
|
69
|
+
else
|
|
70
|
+
".erb"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
"#{name}#{ext}"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def template(path, context)
|
|
77
|
+
require "erb"
|
|
78
|
+
|
|
79
|
+
ERB.new(
|
|
80
|
+
File.read(__dir__ + "/view/#{path}")
|
|
81
|
+
).result(context.ctx)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
alias_method :t, :template
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
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 ViewContext < SliceContext
|
|
15
|
+
# TODO: move these constants somewhere that will let us reuse them
|
|
16
|
+
KEY_SEPARATOR = "."
|
|
17
|
+
private_constant :KEY_SEPARATOR
|
|
18
|
+
|
|
19
|
+
NAMESPACE_SEPARATOR = "::"
|
|
20
|
+
private_constant :NAMESPACE_SEPARATOR
|
|
21
|
+
|
|
22
|
+
INDENTATION = " "
|
|
23
|
+
private_constant :INDENTATION
|
|
24
|
+
|
|
25
|
+
OFFSET = INDENTATION * 2
|
|
26
|
+
private_constant :OFFSET
|
|
27
|
+
|
|
28
|
+
# @since 2.1.0
|
|
29
|
+
# @api private
|
|
30
|
+
attr_reader :key
|
|
31
|
+
|
|
32
|
+
# @since 2.1.0
|
|
33
|
+
# @api private
|
|
34
|
+
def initialize(inflector, app, slice, key)
|
|
35
|
+
@key = key
|
|
36
|
+
super(inflector, app, slice, nil)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @since 2.1.0
|
|
40
|
+
# @api private
|
|
41
|
+
def namespaces
|
|
42
|
+
@namespaces ||= key.split(KEY_SEPARATOR)[..-2]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @since 2.1.0
|
|
46
|
+
# @api private
|
|
47
|
+
def name
|
|
48
|
+
@name ||= key.split(KEY_SEPARATOR)[-1]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @since 2.1.0
|
|
52
|
+
# @api private
|
|
53
|
+
def camelized_namespace
|
|
54
|
+
namespaces.map { inflector.camelize(_1) }.join(NAMESPACE_SEPARATOR)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# @since 2.1.0
|
|
58
|
+
# @api private
|
|
59
|
+
def camelized_name
|
|
60
|
+
inflector.camelize(name)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @since 2.1.0
|
|
64
|
+
# @api private
|
|
65
|
+
def underscored_namespace
|
|
66
|
+
namespaces.map { inflector.underscore(_1) }
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @since 2.1.0
|
|
70
|
+
# @api private
|
|
71
|
+
def underscored_name
|
|
72
|
+
inflector.underscore(name)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# @since 2.1.0
|
|
76
|
+
# @api private
|
|
77
|
+
def module_namespace_declaration
|
|
78
|
+
namespaces.each_with_index.map { |token, i|
|
|
79
|
+
"#{OFFSET}#{INDENTATION * i}module #{inflector.camelize(token)}"
|
|
80
|
+
}.join($/)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# @since 2.1.0
|
|
84
|
+
# @api private
|
|
85
|
+
def module_namespace_end
|
|
86
|
+
namespaces.each_with_index.map { |_, i|
|
|
87
|
+
"#{OFFSET}#{INDENTATION * i}end"
|
|
88
|
+
}.reverse.join($/)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# @since 2.1.0
|
|
92
|
+
# @api private
|
|
93
|
+
def module_namespace_offset
|
|
94
|
+
"#{OFFSET}#{INDENTATION * namespaces.count}"
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>The page you were looking for doesn’t exist (404)</title>
|
|
5
|
+
</head>
|
|
6
|
+
<body>
|
|
7
|
+
<!-- This file lives in public/404.html -->
|
|
8
|
+
<h1>The page you were looking for doesn’t exist.</h1>
|
|
9
|
+
<p>You may have mistyped the address or the page may have moved.</p>
|
|
10
|
+
</body>
|
|
11
|
+
</html>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>We’re sorry, but something went wrong (500)</title>
|
|
5
|
+
</head>
|
|
6
|
+
<body>
|
|
7
|
+
<!-- This file lives in public/500.html -->
|
|
8
|
+
<h1>We’re sorry, but something went wrong.</h1>
|
|
9
|
+
<p>If you are the application owner, check the logs for more information.</p>
|
|
10
|
+
</body>
|
|
11
|
+
</html>
|
|
@@ -6,6 +6,8 @@ gem "hanami", "<%= hanami_version %>"
|
|
|
6
6
|
gem "hanami-router", "<%= hanami_version %>"
|
|
7
7
|
gem "hanami-controller", "<%= hanami_version %>"
|
|
8
8
|
gem "hanami-validations", "<%= hanami_version %>"
|
|
9
|
+
gem "hanami-view", "<%= hanami_version %>"
|
|
10
|
+
gem "hanami-webconsole", "<%= hanami_version %>"
|
|
9
11
|
|
|
10
12
|
gem "dry-types", "~> 1.0", ">= 1.6.1"
|
|
11
13
|
gem "puma"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= yield %>
|
|
@@ -6,10 +6,12 @@ threads min_threads_count, max_threads_count
|
|
|
6
6
|
|
|
7
7
|
port ENV.fetch("<%= Hanami::Port::ENV_VAR %>", <%= Hanami::Port::DEFAULT %>)
|
|
8
8
|
environment ENV.fetch("HANAMI_ENV", "development")
|
|
9
|
-
workers ENV.fetch("HANAMI_WEB_CONCURRENCY",
|
|
9
|
+
workers ENV.fetch("HANAMI_WEB_CONCURRENCY", 0)
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
if ENV.fetch("HANAMI_WEB_CONCURRENCY", 0) > 0
|
|
12
|
+
on_worker_boot do
|
|
13
|
+
Hanami.shutdown
|
|
14
|
+
end
|
|
13
15
|
end
|
|
14
16
|
|
|
15
17
|
preload_app!
|
|
@@ -34,6 +34,7 @@ module Hanami
|
|
|
34
34
|
attr_reader :inflector
|
|
35
35
|
|
|
36
36
|
def generate_app(app, context) # rubocop:disable Metrics/AbcSize
|
|
37
|
+
fs.write(".gitignore", t("gitignore.erb", context))
|
|
37
38
|
fs.write(".env", t("env.erb", context))
|
|
38
39
|
|
|
39
40
|
fs.write("README.md", t("readme.erb", context))
|
|
@@ -51,6 +52,12 @@ module Hanami
|
|
|
51
52
|
|
|
52
53
|
fs.write("app/actions/.keep", t("keep.erb", context))
|
|
53
54
|
fs.write("app/action.rb", t("action.erb", context))
|
|
55
|
+
fs.write("app/view.rb", t("view.erb", context))
|
|
56
|
+
fs.write("app/views/helpers.rb", t("helpers.erb", context))
|
|
57
|
+
fs.write("app/templates/layouts/app.html.erb", File.read(File.join(__dir__, "app", "layouts_app.html.erb")))
|
|
58
|
+
|
|
59
|
+
fs.write("public/404.html", File.read(File.join(__dir__, "app", "404.html")))
|
|
60
|
+
fs.write("public/500.html", File.read(File.join(__dir__, "app", "500.html")))
|
|
54
61
|
end
|
|
55
62
|
|
|
56
63
|
def template(path, context)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "shellwords"
|
|
4
|
+
|
|
5
|
+
module Hanami
|
|
6
|
+
module CLI
|
|
7
|
+
class Naming
|
|
8
|
+
def initialize(inflector:)
|
|
9
|
+
@inflector = inflector
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def action_name(name)
|
|
13
|
+
inflector.underscore(escape(name)).gsub("/", ".")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
attr_reader :inflector
|
|
19
|
+
|
|
20
|
+
def escape(name)
|
|
21
|
+
Shellwords.shellescape(name)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/hanami/cli/url.rb
CHANGED
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.0.
|
|
4
|
+
version: 2.1.0.beta1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Luca Guidi
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2023-06-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -168,10 +168,10 @@ executables:
|
|
|
168
168
|
extensions: []
|
|
169
169
|
extra_rdoc_files: []
|
|
170
170
|
files:
|
|
171
|
-
- ".action_hero.yml"
|
|
172
171
|
- ".github/FUNDING.yml"
|
|
173
172
|
- ".github/workflows/ci.yml"
|
|
174
173
|
- ".gitignore"
|
|
174
|
+
- ".repobot.yml"
|
|
175
175
|
- ".rspec"
|
|
176
176
|
- ".rubocop.yml"
|
|
177
177
|
- ".yardopts"
|
|
@@ -212,6 +212,7 @@ files:
|
|
|
212
212
|
- lib/hanami/cli/commands/app/generate.rb
|
|
213
213
|
- lib/hanami/cli/commands/app/generate/action.rb
|
|
214
214
|
- lib/hanami/cli/commands/app/generate/slice.rb
|
|
215
|
+
- lib/hanami/cli/commands/app/generate/view.rb
|
|
215
216
|
- lib/hanami/cli/commands/app/install.rb
|
|
216
217
|
- lib/hanami/cli/commands/app/middleware.rb
|
|
217
218
|
- lib/hanami/cli/commands/app/routes.rb
|
|
@@ -225,6 +226,8 @@ files:
|
|
|
225
226
|
- lib/hanami/cli/generators/app/action.rb
|
|
226
227
|
- lib/hanami/cli/generators/app/action/action.erb
|
|
227
228
|
- lib/hanami/cli/generators/app/action/slice_action.erb
|
|
229
|
+
- lib/hanami/cli/generators/app/action/slice_template.html.erb
|
|
230
|
+
- lib/hanami/cli/generators/app/action/slice_view.erb
|
|
228
231
|
- lib/hanami/cli/generators/app/action/template.erb
|
|
229
232
|
- lib/hanami/cli/generators/app/action/template.html.erb
|
|
230
233
|
- lib/hanami/cli/generators/app/action/view.erb
|
|
@@ -232,20 +235,33 @@ files:
|
|
|
232
235
|
- lib/hanami/cli/generators/app/slice.rb
|
|
233
236
|
- lib/hanami/cli/generators/app/slice/action.erb
|
|
234
237
|
- lib/hanami/cli/generators/app/slice/entities.erb
|
|
238
|
+
- lib/hanami/cli/generators/app/slice/helpers.erb
|
|
235
239
|
- lib/hanami/cli/generators/app/slice/keep.erb
|
|
240
|
+
- lib/hanami/cli/generators/app/slice/layouts_app.html.erb
|
|
236
241
|
- lib/hanami/cli/generators/app/slice/repository.erb
|
|
237
242
|
- lib/hanami/cli/generators/app/slice/routes.erb
|
|
238
243
|
- lib/hanami/cli/generators/app/slice/slice.erb
|
|
239
244
|
- lib/hanami/cli/generators/app/slice/view.erb
|
|
240
245
|
- lib/hanami/cli/generators/app/slice_context.rb
|
|
246
|
+
- lib/hanami/cli/generators/app/view.rb
|
|
247
|
+
- lib/hanami/cli/generators/app/view/app_template.html.erb
|
|
248
|
+
- lib/hanami/cli/generators/app/view/app_view.erb
|
|
249
|
+
- lib/hanami/cli/generators/app/view/slice_template.html.erb
|
|
250
|
+
- lib/hanami/cli/generators/app/view/slice_view.erb
|
|
251
|
+
- lib/hanami/cli/generators/app/view_context.rb
|
|
241
252
|
- lib/hanami/cli/generators/context.rb
|
|
242
253
|
- lib/hanami/cli/generators/gem/app.rb
|
|
254
|
+
- lib/hanami/cli/generators/gem/app/404.html
|
|
255
|
+
- lib/hanami/cli/generators/gem/app/500.html
|
|
243
256
|
- lib/hanami/cli/generators/gem/app/action.erb
|
|
244
257
|
- lib/hanami/cli/generators/gem/app/app.erb
|
|
245
258
|
- lib/hanami/cli/generators/gem/app/config_ru.erb
|
|
246
259
|
- lib/hanami/cli/generators/gem/app/env.erb
|
|
247
260
|
- lib/hanami/cli/generators/gem/app/gemfile.erb
|
|
261
|
+
- lib/hanami/cli/generators/gem/app/gitignore.erb
|
|
262
|
+
- lib/hanami/cli/generators/gem/app/helpers.erb
|
|
248
263
|
- lib/hanami/cli/generators/gem/app/keep.erb
|
|
264
|
+
- lib/hanami/cli/generators/gem/app/layouts_app.html.erb
|
|
249
265
|
- lib/hanami/cli/generators/gem/app/puma.erb
|
|
250
266
|
- lib/hanami/cli/generators/gem/app/rakefile.erb
|
|
251
267
|
- lib/hanami/cli/generators/gem/app/readme.erb
|
|
@@ -253,8 +269,10 @@ files:
|
|
|
253
269
|
- lib/hanami/cli/generators/gem/app/settings.erb
|
|
254
270
|
- lib/hanami/cli/generators/gem/app/types.erb
|
|
255
271
|
- lib/hanami/cli/generators/gem/app/validator.erb
|
|
272
|
+
- lib/hanami/cli/generators/gem/app/view.erb
|
|
256
273
|
- lib/hanami/cli/generators/version.rb
|
|
257
274
|
- lib/hanami/cli/middleware_stack_inspector.rb
|
|
275
|
+
- lib/hanami/cli/naming.rb
|
|
258
276
|
- lib/hanami/cli/rake_tasks.rb
|
|
259
277
|
- lib/hanami/cli/repl/core.rb
|
|
260
278
|
- lib/hanami/cli/repl/irb.rb
|
|
@@ -286,11 +304,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
286
304
|
version: '3.0'
|
|
287
305
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
288
306
|
requirements:
|
|
289
|
-
- - "
|
|
307
|
+
- - ">"
|
|
290
308
|
- !ruby/object:Gem::Version
|
|
291
|
-
version:
|
|
309
|
+
version: 1.3.1
|
|
292
310
|
requirements: []
|
|
293
|
-
rubygems_version: 3.4.
|
|
311
|
+
rubygems_version: 3.4.13
|
|
294
312
|
signing_key:
|
|
295
313
|
specification_version: 4
|
|
296
314
|
summary: Hanami CLI
|