hanami-cli 2.3.0.beta1 ā 2.3.0
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/.github/workflows/ci.yml +2 -3
- data/.rubocop.yml +2 -0
- data/.rubocop_todo.yml +150 -0
- data/CHANGELOG.md +44 -0
- data/README.md +1 -4
- data/hanami-cli.gemspec +3 -3
- data/lib/hanami/cli/commands/app/command.rb +5 -1
- data/lib/hanami/cli/commands/app/console.rb +10 -1
- data/lib/hanami/cli/commands/app/db/migrate.rb +5 -2
- data/lib/hanami/cli/commands/app/db/rollback.rb +26 -14
- data/lib/hanami/cli/commands/app/db/structure/dump.rb +7 -3
- data/lib/hanami/cli/commands/app/db/utils/database.rb +22 -0
- data/lib/hanami/cli/commands/app/db/utils/mysql.rb +3 -1
- data/lib/hanami/cli/commands/app/db/utils/postgres.rb +16 -3
- data/lib/hanami/cli/commands/app/db/utils/sqlite.rb +1 -1
- data/lib/hanami/cli/commands/app/db/version.rb +2 -0
- data/lib/hanami/cli/commands/app/generate/action.rb +9 -12
- data/lib/hanami/cli/commands/app/generate/slice.rb +8 -8
- data/lib/hanami/cli/commands/app/run.rb +108 -0
- data/lib/hanami/cli/commands/app.rb +1 -0
- data/lib/hanami/cli/commands/gem/new.rb +33 -11
- data/lib/hanami/cli/errors.rb +2 -0
- data/lib/hanami/cli/generators/app/action.rb +11 -5
- data/lib/hanami/cli/generators/app/component.rb +1 -1
- data/lib/hanami/cli/generators/app/relation.rb +1 -1
- data/lib/hanami/cli/generators/app/ruby_file.rb +7 -12
- data/lib/hanami/cli/generators/app/slice.rb +19 -8
- data/lib/hanami/cli/generators/app/view.rb +1 -1
- data/lib/hanami/cli/generators/constants.rb +1 -1
- data/lib/hanami/cli/generators/context.rb +12 -1
- data/lib/hanami/cli/generators/gem/app/context.erb +10 -0
- data/lib/hanami/cli/generators/gem/app/gemfile.erb +3 -2
- data/lib/hanami/cli/generators/gem/app/readme.erb +6 -6
- data/lib/hanami/cli/generators/gem/app/setup.erb +27 -0
- data/lib/hanami/cli/generators/gem/app/types.erb +1 -1
- data/lib/hanami/cli/generators/gem/app.rb +4 -0
- data/lib/hanami/cli/generators/version.rb +5 -7
- data/lib/hanami/cli/interactive_system_call.rb +1 -2
- data/lib/hanami/cli/system_call.rb +1 -1
- data/lib/hanami/cli/version.rb +1 -1
- data/lib/hanami/console/context.rb +3 -0
- data/lib/hanami/console/plugins/unbooted_slice_warnings.rb +40 -0
- data/script/ci +31 -0
- metadata +10 -4
|
@@ -41,7 +41,6 @@ module Hanami
|
|
|
41
41
|
default: DEFAULT_SKIP_VIEW,
|
|
42
42
|
desc: "Skip view and template generation"
|
|
43
43
|
|
|
44
|
-
# TODO: Implement this
|
|
45
44
|
option \
|
|
46
45
|
:skip_tests,
|
|
47
46
|
required: false,
|
|
@@ -60,7 +59,6 @@ module Hanami
|
|
|
60
59
|
|
|
61
60
|
# option :format, required: false, type: :string, default: DEFAULT_FORMAT, desc: "Template format"
|
|
62
61
|
|
|
63
|
-
# rubocop:disable Layout/LineLength
|
|
64
62
|
example [
|
|
65
63
|
%(books.index # GET /books to: "books.index" (MyApp::Actions::Books::Index)),
|
|
66
64
|
%(books.new # GET /books/new to: "books.new" (MyApp::Actions::Books::New)),
|
|
@@ -74,15 +72,13 @@ module Hanami
|
|
|
74
72
|
%(authors.update --http=put # PUT /authors/:id to: "authors.update" (MyApp::Actions::Authors::Update)),
|
|
75
73
|
%(users.index --slice=admin # GET /admin/users to: "users.index" (Admin::Actions::Users::Update))
|
|
76
74
|
]
|
|
77
|
-
# rubocop:enable Layout/LineLength
|
|
78
|
-
|
|
79
75
|
def generator_class
|
|
80
76
|
Generators::App::Action
|
|
81
77
|
end
|
|
82
78
|
|
|
83
79
|
# @since 2.0.0
|
|
84
80
|
# @api private
|
|
85
|
-
# rubocop:disable
|
|
81
|
+
# rubocop:disable Metrics/ParameterLists
|
|
86
82
|
def call(
|
|
87
83
|
name:,
|
|
88
84
|
slice: nil,
|
|
@@ -90,22 +86,23 @@ module Hanami
|
|
|
90
86
|
http_method: nil,
|
|
91
87
|
skip_view: DEFAULT_SKIP_VIEW,
|
|
92
88
|
skip_route: DEFAULT_SKIP_ROUTE,
|
|
93
|
-
skip_tests: DEFAULT_SKIP_TESTS
|
|
89
|
+
skip_tests: DEFAULT_SKIP_TESTS
|
|
94
90
|
)
|
|
95
91
|
name = Naming.new(inflector:).action_name(name)
|
|
96
92
|
|
|
97
93
|
raise InvalidActionNameError.new(name) unless name.include?(".")
|
|
98
94
|
|
|
99
95
|
super(
|
|
100
|
-
name
|
|
101
|
-
slice
|
|
102
|
-
url_path
|
|
103
|
-
skip_route
|
|
104
|
-
http_method
|
|
96
|
+
name: name,
|
|
97
|
+
slice: slice,
|
|
98
|
+
url_path: url_path,
|
|
99
|
+
skip_route: skip_route,
|
|
100
|
+
http_method: http_method,
|
|
105
101
|
skip_view: skip_view || !Hanami.bundled?("hanami-view"),
|
|
102
|
+
skip_tests: skip_tests
|
|
106
103
|
)
|
|
107
104
|
end
|
|
108
|
-
# rubocop:enable
|
|
105
|
+
# rubocop:enable Metrics/ParameterLists
|
|
109
106
|
end
|
|
110
107
|
end
|
|
111
108
|
end
|
|
@@ -29,17 +29,17 @@ module Hanami
|
|
|
29
29
|
# @since 2.2.0
|
|
30
30
|
# @api private
|
|
31
31
|
option :skip_db,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
type: :flag,
|
|
33
|
+
required: false,
|
|
34
|
+
default: SKIP_DB_DEFAULT,
|
|
35
|
+
desc: "Skip database"
|
|
36
36
|
# @since 2.2.0
|
|
37
37
|
# @api private
|
|
38
38
|
option :skip_route,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
type: :flag,
|
|
40
|
+
required: false,
|
|
41
|
+
default: DEFAULT_SKIP_ROUTE,
|
|
42
|
+
desc: "Skip route generation"
|
|
43
43
|
|
|
44
44
|
example [
|
|
45
45
|
"admin # Admin slice (/admin URL prefix)",
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "hanami"
|
|
4
|
+
require_relative "../../errors"
|
|
5
|
+
|
|
6
|
+
module Hanami
|
|
7
|
+
module CLI
|
|
8
|
+
module Commands
|
|
9
|
+
module App
|
|
10
|
+
# Run a given code or file in the context of the application
|
|
11
|
+
#
|
|
12
|
+
# This command is useful for running scripts that need to load the application environment.
|
|
13
|
+
# You can pass a Ruby file to be executed, or you can run an interactive Ruby shell (IRB)
|
|
14
|
+
# with the application environment loaded.
|
|
15
|
+
#
|
|
16
|
+
# Examples:
|
|
17
|
+
#
|
|
18
|
+
# $ bundle exec hanami run path/to/script.rb
|
|
19
|
+
# $ bundle exec hanami run 'puts Hanami.app["repos.user_repo"].all.count'
|
|
20
|
+
#
|
|
21
|
+
# @since 2.0.0
|
|
22
|
+
# @api private
|
|
23
|
+
class Run < Hanami::CLI::Command
|
|
24
|
+
RunError = Class.new(StandardError)
|
|
25
|
+
|
|
26
|
+
desc "Run code in the context of the application"
|
|
27
|
+
|
|
28
|
+
example [
|
|
29
|
+
"path/to/script.rb # Run a Ruby script in the context of the application",
|
|
30
|
+
"'puts Hanami.app[\"repos.user_repo\"].all.count' # Run inline Ruby code in the context of the application",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
argument :code_or_path, required: true, desc: "Path to a Ruby file or inline Ruby code to be executed"
|
|
34
|
+
|
|
35
|
+
def initialize(command_exit: method(:exit), **opts)
|
|
36
|
+
super(**opts)
|
|
37
|
+
@command_exit = command_exit
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# rubocop:disable Metrics/AbcSize
|
|
41
|
+
def call(code_or_path:, **)
|
|
42
|
+
require "hanami/prepare"
|
|
43
|
+
|
|
44
|
+
if File.exist?(code_or_path)
|
|
45
|
+
validate_file_path!(code_or_path)
|
|
46
|
+
Kernel.load code_or_path
|
|
47
|
+
else
|
|
48
|
+
validate_inline_code!(code_or_path)
|
|
49
|
+
begin
|
|
50
|
+
eval(code_or_path, binding, __FILE__, __LINE__) # rubocop:disable Security/Eval
|
|
51
|
+
rescue SyntaxError => e
|
|
52
|
+
err.puts "Syntax error in code: #{e.message}"
|
|
53
|
+
raise RunError, "Syntax error in code: #{e.message}"
|
|
54
|
+
rescue NameError => e
|
|
55
|
+
err.puts "Name error in code: #{e.message}"
|
|
56
|
+
raise RunError, "Name error in code: #{e.message}"
|
|
57
|
+
rescue StandardError => e
|
|
58
|
+
err.puts "Error executing code: #{e.class}: #{e.message}"
|
|
59
|
+
raise RunError, "Error executing code: #{e.class}: #{e.message}"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
rescue RunError
|
|
63
|
+
@command_exit.call(1)
|
|
64
|
+
end
|
|
65
|
+
# rubocop:enable Metrics/AbcSize
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
def validate_file_path!(file_path)
|
|
70
|
+
errors = []
|
|
71
|
+
|
|
72
|
+
# Ensure the file is a Ruby file
|
|
73
|
+
unless file_path.end_with?(".rb")
|
|
74
|
+
errors << "Error: Only Ruby files (.rb) are allowed"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Resolve the absolute path and ensure it's within the app directory
|
|
78
|
+
resolved_path = File.expand_path(file_path)
|
|
79
|
+
app_root = File.expand_path(Dir.pwd)
|
|
80
|
+
|
|
81
|
+
unless resolved_path.start_with?(app_root)
|
|
82
|
+
errors << "Error: File must be within the application directory"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Check file size (prevent loading extremely large files)
|
|
86
|
+
file_size = File.size(file_path)
|
|
87
|
+
if file_size > 10 * 1024 * 1024 # 10MB limit
|
|
88
|
+
errors << "Error: File too large (maximum 10MB allowed)"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
unless errors.empty?
|
|
92
|
+
errors.each { |error| err.puts error }
|
|
93
|
+
raise RunError, errors.join("\n")
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def validate_inline_code!(code)
|
|
98
|
+
# Basic validation for inline code
|
|
99
|
+
if code.length > 10_000 # 10KB limit for inline code
|
|
100
|
+
err.puts "Error: Inline code too long (maximum 10,000 characters allowed)"
|
|
101
|
+
raise RunError, "Error: Inline code too long (maximum 10,000 characters allowed)"
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -18,6 +18,7 @@ module Hanami
|
|
|
18
18
|
register "console", Commands::App::Console, aliases: ["c"]
|
|
19
19
|
register "server", Commands::App::Server, aliases: ["s"]
|
|
20
20
|
register "routes", Commands::App::Routes
|
|
21
|
+
register "run", Commands::App::Run
|
|
21
22
|
register "middleware", Commands::App::Middleware
|
|
22
23
|
|
|
23
24
|
if Hanami.bundled?("hanami-assets")
|
|
@@ -10,16 +10,21 @@ module Hanami
|
|
|
10
10
|
# @since 2.0.0
|
|
11
11
|
# @api private
|
|
12
12
|
class New < Command
|
|
13
|
-
# @since 2.0.0
|
|
14
|
-
# @api private
|
|
15
|
-
SKIP_INSTALL_DEFAULT = false
|
|
16
|
-
private_constant :SKIP_INSTALL_DEFAULT
|
|
17
|
-
|
|
18
13
|
# @since 2.1.0
|
|
19
14
|
# @api private
|
|
20
15
|
HEAD_DEFAULT = false
|
|
21
16
|
private_constant :HEAD_DEFAULT
|
|
22
17
|
|
|
18
|
+
# @since 2.3.0
|
|
19
|
+
# @api private
|
|
20
|
+
GEM_SOURCE_DEFAULT = "rubygems.org"
|
|
21
|
+
private_constant :GEM_SOURCE_DEFAULT
|
|
22
|
+
|
|
23
|
+
# @since 2.0.0
|
|
24
|
+
# @api private
|
|
25
|
+
SKIP_INSTALL_DEFAULT = false
|
|
26
|
+
private_constant :SKIP_INSTALL_DEFAULT
|
|
27
|
+
|
|
23
28
|
# @since 2.1.0
|
|
24
29
|
# @api private
|
|
25
30
|
SKIP_ASSETS_DEFAULT = false
|
|
@@ -60,18 +65,24 @@ module Hanami
|
|
|
60
65
|
# @api private
|
|
61
66
|
argument :app, required: true, desc: "App name"
|
|
62
67
|
|
|
63
|
-
# @since 2.0.0
|
|
64
|
-
# @api private
|
|
65
|
-
option :skip_install, type: :flag, required: false,
|
|
66
|
-
default: SKIP_INSTALL_DEFAULT,
|
|
67
|
-
desc: "Skip app installation (Bundler, third-party Hanami plugins)"
|
|
68
|
-
|
|
69
68
|
# @since 2.1.0
|
|
70
69
|
# @api private
|
|
71
70
|
option :head, type: :flag, required: false,
|
|
72
71
|
default: HEAD_DEFAULT,
|
|
73
72
|
desc: "Use Hanami HEAD version (from GitHub `main` branches)"
|
|
74
73
|
|
|
74
|
+
# @since 2.3.0
|
|
75
|
+
# @api private
|
|
76
|
+
option :gem_source, required: true,
|
|
77
|
+
default: GEM_SOURCE_DEFAULT,
|
|
78
|
+
desc: "Where to source Ruby gems from"
|
|
79
|
+
|
|
80
|
+
# @since 2.0.0
|
|
81
|
+
# @api private
|
|
82
|
+
option :skip_install, type: :flag, required: false,
|
|
83
|
+
default: SKIP_INSTALL_DEFAULT,
|
|
84
|
+
desc: "Skip app installation (Bundler, third-party Hanami plugins)"
|
|
85
|
+
|
|
75
86
|
# @since 2.1.0
|
|
76
87
|
# @api private
|
|
77
88
|
option :skip_assets, type: :flag, required: false,
|
|
@@ -100,6 +111,7 @@ module Hanami
|
|
|
100
111
|
example [
|
|
101
112
|
"bookshelf # Generate a new Hanami app in `bookshelf/' directory, using `Bookshelf' namespace",
|
|
102
113
|
"bookshelf --head # Generate a new Hanami app, using Hanami HEAD version from GitHub `main' branches",
|
|
114
|
+
"bookshelf --gem-source=gem.coop # Generate a new Hanami app, using https://gem.coop as Ruby gem source",
|
|
103
115
|
"bookshelf --skip-install # Generate a new Hanami app, but it skips Hanami installation",
|
|
104
116
|
"bookshelf --skip-assets # Generate a new Hanami app without hanami-assets",
|
|
105
117
|
"bookshelf --skip-db # Generate a new Hanami app without hanami-db",
|
|
@@ -132,6 +144,7 @@ module Hanami
|
|
|
132
144
|
def call(
|
|
133
145
|
app:,
|
|
134
146
|
head: HEAD_DEFAULT,
|
|
147
|
+
gem_source: GEM_SOURCE_DEFAULT,
|
|
135
148
|
skip_install: SKIP_INSTALL_DEFAULT,
|
|
136
149
|
skip_assets: SKIP_ASSETS_DEFAULT,
|
|
137
150
|
skip_db: SKIP_DB_DEFAULT,
|
|
@@ -152,6 +165,7 @@ module Hanami
|
|
|
152
165
|
inflector,
|
|
153
166
|
app,
|
|
154
167
|
head: head,
|
|
168
|
+
gem_source: gem_source,
|
|
155
169
|
skip_assets: skip_assets,
|
|
156
170
|
skip_db: skip_db,
|
|
157
171
|
skip_view: skip_view,
|
|
@@ -177,6 +191,9 @@ module Hanami
|
|
|
177
191
|
out.puts "Running hanami install..."
|
|
178
192
|
run_install_command!(head: head)
|
|
179
193
|
|
|
194
|
+
out.puts "Running bundle binstubs hanami-cli rake..."
|
|
195
|
+
install_binstubs!
|
|
196
|
+
|
|
180
197
|
out.puts "Initializing git repository..."
|
|
181
198
|
init_git_repository
|
|
182
199
|
end
|
|
@@ -215,6 +232,11 @@ module Hanami
|
|
|
215
232
|
end
|
|
216
233
|
end
|
|
217
234
|
|
|
235
|
+
# @api private
|
|
236
|
+
def install_binstubs!
|
|
237
|
+
bundler.bundle("binstubs hanami-cli rake")
|
|
238
|
+
end
|
|
239
|
+
|
|
218
240
|
# @api private
|
|
219
241
|
def init_git_repository
|
|
220
242
|
system_call.call("git", ["init"]).tap do |result|
|
data/lib/hanami/cli/errors.rb
CHANGED
|
@@ -110,6 +110,7 @@ module Hanami
|
|
|
110
110
|
end
|
|
111
111
|
end
|
|
112
112
|
|
|
113
|
+
# rubocop:disable Layout/LineLength
|
|
113
114
|
# @since 2.2.0
|
|
114
115
|
# @api public
|
|
115
116
|
class DatabaseNotSupportedError < Error
|
|
@@ -117,6 +118,7 @@ module Hanami
|
|
|
117
118
|
super("`#{invalid_database}' is not a supported database. Supported databases are: #{supported_databases.join(', ')}")
|
|
118
119
|
end
|
|
119
120
|
end
|
|
121
|
+
# rubocop:enable Layout/LineLength
|
|
120
122
|
|
|
121
123
|
# @since 2.2.0
|
|
122
124
|
# @api public
|
|
@@ -27,10 +27,10 @@ module Hanami
|
|
|
27
27
|
|
|
28
28
|
# @since 2.0.0
|
|
29
29
|
# @api private
|
|
30
|
-
def call(key:, namespace:, base_path:, url_path:, http_method:, skip_view:, skip_route:)
|
|
30
|
+
def call(key:, namespace:, base_path:, url_path:, http_method:, skip_view:, skip_route:, skip_tests:)
|
|
31
31
|
insert_route(key:, namespace:, url_path:, http_method:) unless skip_route
|
|
32
32
|
|
|
33
|
-
generate_action(key
|
|
33
|
+
generate_action(key: key, namespace: namespace, base_path: base_path, include_placeholder_body: skip_view)
|
|
34
34
|
|
|
35
35
|
generate_view(key:, namespace:, base_path:) unless skip_view
|
|
36
36
|
end
|
|
@@ -83,8 +83,14 @@ module Hanami
|
|
|
83
83
|
if namespace == Hanami.app.namespace
|
|
84
84
|
fs.inject_line_at_class_bottom(routes_location, "class Routes", route)
|
|
85
85
|
else
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
slice_routes = fs.join("slices", namespace, "config", "routes.rb")
|
|
87
|
+
|
|
88
|
+
if fs.exist?(slice_routes)
|
|
89
|
+
fs.inject_line_at_class_bottom(slice_routes, "class Routes", route)
|
|
90
|
+
else
|
|
91
|
+
slice_matcher = /slice[[:space:]]*:#{namespace}/
|
|
92
|
+
fs.inject_line_at_block_bottom(routes_location, slice_matcher, route)
|
|
93
|
+
end
|
|
88
94
|
end
|
|
89
95
|
end
|
|
90
96
|
|
|
@@ -95,7 +101,7 @@ module Hanami
|
|
|
95
101
|
fs: fs,
|
|
96
102
|
inflector: inflector,
|
|
97
103
|
namespace: namespace,
|
|
98
|
-
key:
|
|
104
|
+
key: key,
|
|
99
105
|
base_path: base_path,
|
|
100
106
|
parent_class_name: "#{inflector.camelize(namespace)}::Action",
|
|
101
107
|
extra_namespace: "Actions",
|
|
@@ -20,7 +20,7 @@ module Hanami
|
|
|
20
20
|
# @since 2.2.0
|
|
21
21
|
# @api private
|
|
22
22
|
def call(key:, namespace:, base_path:, gateway:)
|
|
23
|
-
schema_name = key.split(KEY_SEPARATOR).last
|
|
23
|
+
schema_name = inflector.underscore(key.split(KEY_SEPARATOR).last)
|
|
24
24
|
body_content = ["schema :#{schema_name}, infer: true"]
|
|
25
25
|
|
|
26
26
|
body_content.prepend("gateway :#{gateway}") if gateway
|
|
@@ -17,11 +17,11 @@ module Hanami
|
|
|
17
17
|
extra_namespace: nil,
|
|
18
18
|
auto_register: nil,
|
|
19
19
|
body: [],
|
|
20
|
-
**
|
|
20
|
+
**_opts
|
|
21
21
|
)
|
|
22
22
|
@fs = fs
|
|
23
23
|
@inflector = inflector
|
|
24
|
-
@
|
|
24
|
+
@key_segments = key.split(KEY_SEPARATOR).map { |segment| inflector.underscore(segment) }
|
|
25
25
|
@namespace = namespace
|
|
26
26
|
@base_path = base_path
|
|
27
27
|
@extra_namespace = extra_namespace&.downcase
|
|
@@ -42,13 +42,13 @@ module Hanami
|
|
|
42
42
|
# @api private
|
|
43
43
|
def fully_qualified_name
|
|
44
44
|
inflector.camelize(
|
|
45
|
-
[namespace, extra_namespace, *
|
|
45
|
+
[namespace, extra_namespace, *key_segments].join("/"),
|
|
46
46
|
)
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
# @api private
|
|
50
50
|
def path
|
|
51
|
-
fs.join(directory, "#{
|
|
51
|
+
fs.join(directory, "#{key_segments.last}.rb")
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
private
|
|
@@ -57,7 +57,7 @@ module Hanami
|
|
|
57
57
|
attr_reader(
|
|
58
58
|
:fs,
|
|
59
59
|
:inflector,
|
|
60
|
-
:
|
|
60
|
+
:key_segments,
|
|
61
61
|
:base_path,
|
|
62
62
|
:namespace,
|
|
63
63
|
:extra_namespace,
|
|
@@ -79,7 +79,7 @@ module Hanami
|
|
|
79
79
|
|
|
80
80
|
# @api private
|
|
81
81
|
def local_namespaces
|
|
82
|
-
Array(extra_namespace) +
|
|
82
|
+
Array(extra_namespace) + key_segments[..-2]
|
|
83
83
|
end
|
|
84
84
|
|
|
85
85
|
# @api private
|
|
@@ -100,7 +100,7 @@ module Hanami
|
|
|
100
100
|
|
|
101
101
|
# @api private
|
|
102
102
|
def constant_name
|
|
103
|
-
normalize(
|
|
103
|
+
normalize(key_segments.last)
|
|
104
104
|
end
|
|
105
105
|
|
|
106
106
|
# @api private
|
|
@@ -116,11 +116,6 @@ module Hanami
|
|
|
116
116
|
def normalize(name)
|
|
117
117
|
inflector.camelize(name).gsub(/[^\p{Alnum}]/, "")
|
|
118
118
|
end
|
|
119
|
-
|
|
120
|
-
# @api private
|
|
121
|
-
def key_parts
|
|
122
|
-
key.split(KEY_SEPARATOR)
|
|
123
|
-
end
|
|
124
119
|
end
|
|
125
120
|
end
|
|
126
121
|
end
|
|
@@ -66,6 +66,17 @@ module Hanami
|
|
|
66
66
|
body: ["# Add your view helpers here"]
|
|
67
67
|
).create
|
|
68
68
|
|
|
69
|
+
RubyClassFile.new(
|
|
70
|
+
fs: fs,
|
|
71
|
+
inflector: inflector,
|
|
72
|
+
namespace: slice,
|
|
73
|
+
key: "views.context",
|
|
74
|
+
base_path: directory,
|
|
75
|
+
parent_class_name: "#{Hanami.app.namespace}::View::Context",
|
|
76
|
+
auto_register: false,
|
|
77
|
+
body: ["# Define your view context here. See https://guides.hanamirb.org/views/context/ for details."]
|
|
78
|
+
).create
|
|
79
|
+
|
|
69
80
|
fs.create(
|
|
70
81
|
fs.join(directory, "templates", "layouts", "app.html.erb"),
|
|
71
82
|
app_layout_template(
|
|
@@ -93,11 +104,11 @@ module Hanami
|
|
|
93
104
|
fs.create(
|
|
94
105
|
fs.join(directory, "assets", "css", "app.css"),
|
|
95
106
|
<<~CSS
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
107
|
+
body {
|
|
108
|
+
background-color: #fff;
|
|
109
|
+
color: #000;
|
|
110
|
+
font-family: sans-serif;
|
|
111
|
+
}
|
|
101
112
|
CSS
|
|
102
113
|
)
|
|
103
114
|
fs.create(fs.join(directory, "assets", "images", "favicon.ico"), file("favicon.ico"))
|
|
@@ -161,9 +172,9 @@ module Hanami
|
|
|
161
172
|
<head>
|
|
162
173
|
<meta charset="UTF-8">
|
|
163
174
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
164
|
-
<title>#{
|
|
165
|
-
#{'<%= favicon_tag %>' if bundled_assets
|
|
166
|
-
#{'<%= stylesheet_tag "app" %>' if bundled_assets
|
|
175
|
+
<title>#{page_title}</title>
|
|
176
|
+
#{'<%= favicon_tag %>' if bundled_assets}
|
|
177
|
+
#{'<%= stylesheet_tag "app" %>' if bundled_assets}
|
|
167
178
|
</head>
|
|
168
179
|
<body>
|
|
169
180
|
<%= yield %>
|
|
@@ -32,7 +32,9 @@ module Hanami
|
|
|
32
32
|
|
|
33
33
|
# @since 2.0.0
|
|
34
34
|
# @api private
|
|
35
|
-
def hanami_gem_version(
|
|
35
|
+
def hanami_gem_version(name)
|
|
36
|
+
gem_name = name == "hanami" ? "hanami" : "hanami-#{name}"
|
|
37
|
+
|
|
36
38
|
if hanami_head?
|
|
37
39
|
%(github: "hanami/#{gem_name}", branch: "main")
|
|
38
40
|
else
|
|
@@ -74,6 +76,15 @@ module Hanami
|
|
|
74
76
|
options.fetch(:head)
|
|
75
77
|
end
|
|
76
78
|
|
|
79
|
+
# @since 2.3.0
|
|
80
|
+
# @api private
|
|
81
|
+
def gem_source
|
|
82
|
+
value = options.fetch(:gem_source)
|
|
83
|
+
return value if value.match? %r{\A\w+://}
|
|
84
|
+
|
|
85
|
+
"https://#{value}"
|
|
86
|
+
end
|
|
87
|
+
|
|
77
88
|
# @since 2.1.0
|
|
78
89
|
# @api private
|
|
79
90
|
def generate_assets?
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
source "
|
|
3
|
+
source "<%= gem_source %>"
|
|
4
4
|
|
|
5
5
|
<%= hanami_gem("hanami") %>
|
|
6
6
|
<%- if hanami_head? -%>
|
|
7
7
|
<%= hanami_gem("cli") %>
|
|
8
|
+
<%= hanami_gem("utils") %>
|
|
8
9
|
<%- end -%>
|
|
9
10
|
<%- if generate_assets? -%>
|
|
10
11
|
<%= hanami_gem("assets") %>
|
|
@@ -20,7 +21,7 @@ source "https://rubygems.org"
|
|
|
20
21
|
<%- end -%>
|
|
21
22
|
|
|
22
23
|
gem "dry-types", "~> 1.7"
|
|
23
|
-
gem "dry-operation"
|
|
24
|
+
gem "dry-operation", ">= 1.0.1"
|
|
24
25
|
gem "puma"
|
|
25
26
|
gem "rake"
|
|
26
27
|
<%- if generate_sqlite? -%>
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# <%= camelized_app_name %>
|
|
2
2
|
|
|
3
|
-
Welcome to your Hanami app!
|
|
3
|
+
šø Welcome to your Hanami app!
|
|
4
4
|
|
|
5
|
-
## Getting
|
|
5
|
+
## Getting started
|
|
6
6
|
|
|
7
|
+
- Set up the project up with `bin/setup`
|
|
7
8
|
- Run the server with `bin/dev`
|
|
8
9
|
- View the app at [http://localhost:2300](http://localhost:2300)
|
|
9
10
|
- Run the tests with `bundle exec rake`
|
|
10
11
|
|
|
11
|
-
## Useful
|
|
12
|
+
## Useful links
|
|
12
13
|
|
|
13
|
-
- [Hanami
|
|
14
|
-
- [Hanami
|
|
15
|
-
- [Hanami API Doc](https://gemdocs.org/gems/hanami/latest)
|
|
14
|
+
- [Hanami](http://hanamirb.org)
|
|
15
|
+
- [Hanami guides](https://guides.hanamirb.org/)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
IFS=$'\n\t'
|
|
4
|
+
|
|
5
|
+
# This script is a way to set up and keep your development environment updated
|
|
6
|
+
# automatically. It is meant to be idempotent so that you can run it at any
|
|
7
|
+
# time to get the same result. Add any new necessary setup steps to this file
|
|
8
|
+
# as your application evolves.
|
|
9
|
+
|
|
10
|
+
announce() {
|
|
11
|
+
local bold='\033[1m'
|
|
12
|
+
local reset='\033[0m'
|
|
13
|
+
printf "${bold}${1}${reset}\n"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
announce "Running bundle install..."
|
|
17
|
+
bundle check || bundle install
|
|
18
|
+
|
|
19
|
+
announce "\nRunning npm install..."
|
|
20
|
+
npm install
|
|
21
|
+
|
|
22
|
+
<%- if generate_db? -%>
|
|
23
|
+
announce "\nPreparing the database..."
|
|
24
|
+
hanami db prepare
|
|
25
|
+
|
|
26
|
+
<%- end -%>
|
|
27
|
+
announce "\nšø Setup complete!"
|
|
@@ -46,6 +46,9 @@ module Hanami
|
|
|
46
46
|
fs.create("bin/dev", file("dev"))
|
|
47
47
|
fs.chmod("bin/dev", 0o755)
|
|
48
48
|
|
|
49
|
+
fs.create("bin/setup", t("setup.erb", context))
|
|
50
|
+
fs.chmod("bin/setup", 0o755)
|
|
51
|
+
|
|
49
52
|
fs.create("config/app.rb", t("app.erb", context))
|
|
50
53
|
fs.create("config/settings.rb", t("settings.erb", context))
|
|
51
54
|
fs.create("config/routes.rb", t("routes.erb", context))
|
|
@@ -60,6 +63,7 @@ module Hanami
|
|
|
60
63
|
if context.generate_view?
|
|
61
64
|
fs.create("app/view.rb", t("view.erb", context))
|
|
62
65
|
fs.create("app/views/helpers.rb", t("helpers.erb", context))
|
|
66
|
+
fs.create("app/views/context.rb", t("context.erb", context))
|
|
63
67
|
fs.create("app/templates/layouts/app.html.erb", t("app_layout.erb", context))
|
|
64
68
|
|
|
65
69
|
fs.create("public/404.html", file("404.html"))
|