hanami-cli 2.0.2 → 2.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|