hanami 1.3.1 → 2.0.0.alpha2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +110 -6
- data/FEATURES.md +9 -1
- data/LICENSE.md +1 -1
- data/README.md +4 -5
- data/hanami.gemspec +26 -30
- data/lib/hanami.rb +40 -243
- data/lib/hanami/application.rb +338 -174
- data/lib/hanami/application/autoloader/inflector_adapter.rb +22 -0
- data/lib/hanami/application/container/boot/inflector.rb +7 -0
- data/lib/hanami/application/container/boot/logger.rb +8 -0
- data/lib/hanami/application/container/boot/rack_logger.rb +19 -0
- data/lib/hanami/application/container/boot/rack_monitor.rb +12 -0
- data/lib/hanami/application/container/boot/settings.rb +7 -0
- data/lib/hanami/application/router.rb +59 -0
- data/lib/hanami/application/routing/middleware/stack.rb +89 -0
- data/lib/hanami/application/routing/resolver.rb +82 -0
- data/lib/hanami/application/routing/resolver/node.rb +50 -0
- data/lib/hanami/application/routing/resolver/trie.rb +59 -0
- data/lib/hanami/application/settings.rb +23 -0
- data/lib/hanami/application/settings/definition.rb +26 -0
- data/lib/hanami/application/settings/loader.rb +97 -0
- data/lib/hanami/application/settings/struct.rb +65 -0
- data/lib/hanami/boot.rb +5 -0
- data/lib/hanami/cli/application/cli.rb +40 -0
- data/lib/hanami/cli/application/command.rb +47 -0
- data/lib/hanami/cli/application/commands.rb +16 -0
- data/lib/hanami/cli/application/commands/console.rb +81 -0
- data/lib/hanami/cli/base_command.rb +48 -0
- data/lib/hanami/cli/commands.rb +6 -42
- data/lib/hanami/cli/commands/command.rb +20 -30
- data/lib/hanami/cli/commands/server.rb +63 -14
- data/lib/hanami/configuration.rb +248 -190
- data/lib/hanami/configuration/middleware.rb +8 -28
- data/lib/hanami/configuration/router.rb +50 -0
- data/lib/hanami/configuration/sessions.rb +50 -0
- data/lib/hanami/init.rb +5 -0
- data/lib/hanami/server.rb +5 -69
- data/lib/hanami/setup.rb +8 -2
- data/lib/hanami/slice.rb +138 -0
- data/lib/hanami/version.rb +3 -1
- data/lib/hanami/web/rack_logger.rb +96 -0
- metadata +84 -228
- data/bin/hanami +0 -6
- data/lib/hanami/action/csrf_protection.rb +0 -211
- data/lib/hanami/action/routing_helpers.rb +0 -40
- data/lib/hanami/app.rb +0 -96
- data/lib/hanami/application_configuration.rb +0 -1495
- data/lib/hanami/application_name.rb +0 -108
- data/lib/hanami/application_namespace.rb +0 -14
- data/lib/hanami/assets/asset.rb +0 -72
- data/lib/hanami/assets/static.rb +0 -102
- data/lib/hanami/cli/commands/assets.rb +0 -16
- data/lib/hanami/cli/commands/assets/precompile.rb +0 -42
- data/lib/hanami/cli/commands/console.rb +0 -95
- data/lib/hanami/cli/commands/db.rb +0 -32
- data/lib/hanami/cli/commands/db/apply.rb +0 -32
- data/lib/hanami/cli/commands/db/console.rb +0 -44
- data/lib/hanami/cli/commands/db/create.rb +0 -32
- data/lib/hanami/cli/commands/db/drop.rb +0 -32
- data/lib/hanami/cli/commands/db/migrate.rb +0 -39
- data/lib/hanami/cli/commands/db/prepare.rb +0 -32
- data/lib/hanami/cli/commands/db/rollback.rb +0 -59
- data/lib/hanami/cli/commands/db/version.rb +0 -32
- data/lib/hanami/cli/commands/destroy.rb +0 -26
- data/lib/hanami/cli/commands/destroy/action.rb +0 -137
- data/lib/hanami/cli/commands/destroy/app.rb +0 -159
- data/lib/hanami/cli/commands/destroy/mailer.rb +0 -74
- data/lib/hanami/cli/commands/destroy/migration.rb +0 -51
- data/lib/hanami/cli/commands/destroy/model.rb +0 -84
- data/lib/hanami/cli/commands/generate.rb +0 -28
- data/lib/hanami/cli/commands/generate/action.rb +0 -321
- data/lib/hanami/cli/commands/generate/action/action.erb +0 -7
- data/lib/hanami/cli/commands/generate/action/action_spec.minitest.erb +0 -11
- data/lib/hanami/cli/commands/generate/action/action_spec.rspec.erb +0 -9
- data/lib/hanami/cli/commands/generate/action/action_without_view.erb +0 -7
- data/lib/hanami/cli/commands/generate/action/view.erb +0 -7
- data/lib/hanami/cli/commands/generate/action/view_spec.minitest.erb +0 -12
- data/lib/hanami/cli/commands/generate/action/view_spec.rspec.erb +0 -10
- data/lib/hanami/cli/commands/generate/app.rb +0 -243
- data/lib/hanami/cli/commands/generate/app/application.erb +0 -313
- data/lib/hanami/cli/commands/generate/app/favicon.ico +0 -0
- data/lib/hanami/cli/commands/generate/app/gitkeep.erb +0 -0
- data/lib/hanami/cli/commands/generate/app/layout.erb +0 -7
- data/lib/hanami/cli/commands/generate/app/layout_spec.minitest.erb +0 -10
- data/lib/hanami/cli/commands/generate/app/layout_spec.rspec.erb +0 -10
- data/lib/hanami/cli/commands/generate/app/routes.erb +0 -5
- data/lib/hanami/cli/commands/generate/app/template.erb.erb +0 -10
- data/lib/hanami/cli/commands/generate/app/template.haml.erb +0 -7
- data/lib/hanami/cli/commands/generate/app/template.slim.erb +0 -8
- data/lib/hanami/cli/commands/generate/mailer.rb +0 -104
- data/lib/hanami/cli/commands/generate/mailer/mailer.erb +0 -9
- data/lib/hanami/cli/commands/generate/mailer/mailer_spec.minitest.erb +0 -7
- data/lib/hanami/cli/commands/generate/mailer/mailer_spec.rspec.erb +0 -5
- data/lib/hanami/cli/commands/generate/migration.rb +0 -41
- data/lib/hanami/cli/commands/generate/migration/migration.erb +0 -4
- data/lib/hanami/cli/commands/generate/model.rb +0 -125
- data/lib/hanami/cli/commands/generate/model/entity.erb +0 -2
- data/lib/hanami/cli/commands/generate/model/entity_spec.minitest.erb +0 -5
- data/lib/hanami/cli/commands/generate/model/entity_spec.rspec.erb +0 -3
- data/lib/hanami/cli/commands/generate/model/migration.erb +0 -10
- data/lib/hanami/cli/commands/generate/model/repository.erb +0 -5
- data/lib/hanami/cli/commands/generate/model/repository_spec.minitest.erb +0 -5
- data/lib/hanami/cli/commands/generate/model/repository_spec.rspec.erb +0 -3
- data/lib/hanami/cli/commands/generate/secret.rb +0 -48
- data/lib/hanami/cli/commands/new.rb +0 -578
- data/lib/hanami/cli/commands/new/.env.development.erb +0 -3
- data/lib/hanami/cli/commands/new/.env.test.erb +0 -3
- data/lib/hanami/cli/commands/new/.gitkeep.erb +0 -0
- data/lib/hanami/cli/commands/new/Gemfile.erb +0 -58
- data/lib/hanami/cli/commands/new/README.md.erb +0 -33
- data/lib/hanami/cli/commands/new/config.ru.erb +0 -3
- data/lib/hanami/cli/commands/new/config/boot.erb +0 -2
- data/lib/hanami/cli/commands/new/config/environment.erb +0 -49
- data/lib/hanami/cli/commands/new/gitignore.erb +0 -2
- data/lib/hanami/cli/commands/new/gitignore_with_sqlite.erb +0 -3
- data/lib/hanami/cli/commands/new/hanamirc.erb +0 -3
- data/lib/hanami/cli/commands/new/lib/project.erb +0 -2
- data/lib/hanami/cli/commands/new/minitest/Rakefile.erb +0 -12
- data/lib/hanami/cli/commands/new/minitest/features_helper.erb +0 -11
- data/lib/hanami/cli/commands/new/minitest/spec_helper.erb +0 -7
- data/lib/hanami/cli/commands/new/rspec/Rakefile.erb +0 -9
- data/lib/hanami/cli/commands/new/rspec/capybara.erb +0 -8
- data/lib/hanami/cli/commands/new/rspec/features_helper.erb +0 -12
- data/lib/hanami/cli/commands/new/rspec/rspec.erb +0 -2
- data/lib/hanami/cli/commands/new/rspec/spec_helper.erb +0 -103
- data/lib/hanami/cli/commands/new/schema.sql.erb +0 -0
- data/lib/hanami/cli/commands/project.rb +0 -421
- data/lib/hanami/cli/commands/routes.rb +0 -21
- data/lib/hanami/cli/commands/templates.rb +0 -31
- data/lib/hanami/cli/commands/version.rb +0 -19
- data/lib/hanami/common_logger.rb +0 -93
- data/lib/hanami/components.rb +0 -156
- data/lib/hanami/components/app/assets.rb +0 -59
- data/lib/hanami/components/app/controller.rb +0 -74
- data/lib/hanami/components/app/routes.rb +0 -59
- data/lib/hanami/components/app/view.rb +0 -44
- data/lib/hanami/components/component.rb +0 -182
- data/lib/hanami/components/components.rb +0 -479
- data/lib/hanami/components/routes_inspector.rb +0 -72
- data/lib/hanami/config/cookies.rb +0 -69
- data/lib/hanami/config/framework_configuration.rb +0 -43
- data/lib/hanami/config/load_paths.rb +0 -46
- data/lib/hanami/config/mapper.rb +0 -47
- data/lib/hanami/config/routes.rb +0 -20
- data/lib/hanami/config/security.rb +0 -110
- data/lib/hanami/config/sessions.rb +0 -103
- data/lib/hanami/configuration/app.rb +0 -18
- data/lib/hanami/early_hints.rb +0 -129
- data/lib/hanami/env.rb +0 -69
- data/lib/hanami/environment.rb +0 -513
- data/lib/hanami/environment_application_configurations.rb +0 -37
- data/lib/hanami/frameworks.rb +0 -22
- data/lib/hanami/hanamirc.rb +0 -169
- data/lib/hanami/mailer/glue.rb +0 -27
- data/lib/hanami/middleware_stack.rb +0 -172
- data/lib/hanami/rake_helper.rb +0 -78
- data/lib/hanami/rake_tasks.rb +0 -2
- data/lib/hanami/rendering_policy.rb +0 -95
- data/lib/hanami/routes.rb +0 -219
- data/lib/hanami/routing/default.rb +0 -32
- data/lib/hanami/static.rb +0 -63
- data/lib/hanami/templates/default.html.erb +0 -30
- data/lib/hanami/templates/welcome.html.erb +0 -52
- data/lib/hanami/views/default.rb +0 -37
- data/lib/hanami/views/default_template_finder.rb +0 -22
- data/lib/hanami/views/null_view.rb +0 -15
- data/lib/hanami/welcome.rb +0 -36
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
module Hanami
|
|
2
|
-
class CLI
|
|
3
|
-
module Commands
|
|
4
|
-
module Destroy
|
|
5
|
-
# @since 1.1.0
|
|
6
|
-
# @api private
|
|
7
|
-
class App < Command
|
|
8
|
-
desc "Destroy an app"
|
|
9
|
-
|
|
10
|
-
argument :app, required: true, desc: "The application name (eg. `web`)"
|
|
11
|
-
|
|
12
|
-
example [
|
|
13
|
-
"admin # Destroy `admin` app"
|
|
14
|
-
]
|
|
15
|
-
|
|
16
|
-
# @since 1.1.0
|
|
17
|
-
# @api private
|
|
18
|
-
def call(app:, **options) # rubocop:disable Metrics/MethodLength
|
|
19
|
-
app = Utils::String.underscore(app)
|
|
20
|
-
context = Context.new(app: app, options: options)
|
|
21
|
-
|
|
22
|
-
assert_valid_app!(context)
|
|
23
|
-
context = context.with(base_url: base_url(context))
|
|
24
|
-
|
|
25
|
-
remove_test_http_session_secret(context)
|
|
26
|
-
remove_development_http_session_secret(context)
|
|
27
|
-
|
|
28
|
-
remove_mount_app(context)
|
|
29
|
-
remove_require_app(context)
|
|
30
|
-
|
|
31
|
-
recursively_destroy_precompiled_assets(context)
|
|
32
|
-
destroy_assets_manifest(context)
|
|
33
|
-
|
|
34
|
-
recursively_destroy_specs(context)
|
|
35
|
-
recursively_destroy_app(context)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
private
|
|
39
|
-
|
|
40
|
-
# @since 1.1.0
|
|
41
|
-
# @api private
|
|
42
|
-
def assert_valid_app!(context)
|
|
43
|
-
return if project.app?(context)
|
|
44
|
-
|
|
45
|
-
existing_apps = project.apps.map { |name| "`#{name}'" }.join(' ')
|
|
46
|
-
warn "`#{context.app}' is not a valid APP. Please specify one of: #{existing_apps}"
|
|
47
|
-
exit(1)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# @since 1.1.0
|
|
51
|
-
# @api private
|
|
52
|
-
def remove_test_http_session_secret(context)
|
|
53
|
-
content = "#{context.app.upcase}_SESSIONS_SECRET"
|
|
54
|
-
destination = project.env(context, "test")
|
|
55
|
-
|
|
56
|
-
files.remove_line(destination, content)
|
|
57
|
-
say(:subtract, destination)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
# @since 1.1.0
|
|
61
|
-
# @api private
|
|
62
|
-
def remove_development_http_session_secret(context)
|
|
63
|
-
content = "#{context.app.upcase}_SESSIONS_SECRET"
|
|
64
|
-
destination = project.env(context, "development")
|
|
65
|
-
|
|
66
|
-
files.remove_line(destination, content)
|
|
67
|
-
say(:subtract, destination)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
# @since 1.1.0
|
|
71
|
-
# @api private
|
|
72
|
-
def remove_mount_app(context)
|
|
73
|
-
content = "mount #{context.app.classify}::Application"
|
|
74
|
-
destination = project.environment(context)
|
|
75
|
-
|
|
76
|
-
files.remove_line(destination, content)
|
|
77
|
-
say(:subtract, destination)
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
# @since 1.1.0
|
|
81
|
-
# @api private
|
|
82
|
-
def remove_require_app(context)
|
|
83
|
-
content = "require_relative '../apps/#{context.app}/application'"
|
|
84
|
-
destination = project.environment(context)
|
|
85
|
-
|
|
86
|
-
files.remove_line(destination, content)
|
|
87
|
-
say(:subtract, destination)
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
# @since 1.1.0
|
|
91
|
-
# @api private
|
|
92
|
-
def recursively_destroy_precompiled_assets(context)
|
|
93
|
-
destination = project.public_app_assets(context)
|
|
94
|
-
return unless files.directory?(destination)
|
|
95
|
-
|
|
96
|
-
files.delete_directory(destination)
|
|
97
|
-
say(:remove, destination)
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
# @since 1.1.0
|
|
101
|
-
# @api private
|
|
102
|
-
def destroy_assets_manifest(context)
|
|
103
|
-
destination = project.assets_manifest(context)
|
|
104
|
-
return unless files.exist?(destination)
|
|
105
|
-
|
|
106
|
-
files.delete(destination)
|
|
107
|
-
say(:remove, destination)
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
# @since 1.1.0
|
|
111
|
-
# @api private
|
|
112
|
-
def recursively_destroy_specs(context)
|
|
113
|
-
destination = project.app_spec(context)
|
|
114
|
-
|
|
115
|
-
files.delete_directory(destination)
|
|
116
|
-
say(:remove, destination)
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
# @since 1.1.0
|
|
120
|
-
# @api private
|
|
121
|
-
def recursively_destroy_app(context)
|
|
122
|
-
destination = project.app(context)
|
|
123
|
-
|
|
124
|
-
files.delete_directory(destination)
|
|
125
|
-
say(:remove, destination)
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
# @since 1.1.0
|
|
129
|
-
# @api private
|
|
130
|
-
def base_url(context)
|
|
131
|
-
content = "mount #{context.app.classify}::Application"
|
|
132
|
-
destination = project.environment(context)
|
|
133
|
-
|
|
134
|
-
line = read_matching_line(destination, content)
|
|
135
|
-
*, at = line.split(/at\:[[:space:]]*/)
|
|
136
|
-
|
|
137
|
-
at.strip.gsub(/["']*/, "")
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
# @since 1.1.0
|
|
141
|
-
# @api private
|
|
142
|
-
def read_matching_line(path, target)
|
|
143
|
-
content = ::File.readlines(path)
|
|
144
|
-
line = content.find do |l|
|
|
145
|
-
case target
|
|
146
|
-
when String
|
|
147
|
-
l.include?(target)
|
|
148
|
-
when Regexp
|
|
149
|
-
l =~ target
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
line or raise ArgumentError.new("Cannot find `#{target}' inside `#{path}'.")
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
end
|
|
158
|
-
end
|
|
159
|
-
end
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
module Hanami
|
|
2
|
-
class CLI
|
|
3
|
-
module Commands
|
|
4
|
-
module Destroy
|
|
5
|
-
# @since 1.1.0
|
|
6
|
-
# @api private
|
|
7
|
-
class Mailer < Command
|
|
8
|
-
requires "environment"
|
|
9
|
-
desc "Destroy a mailer"
|
|
10
|
-
|
|
11
|
-
argument :mailer, required: true, desc: "The mailer name (eg. `welcome`)"
|
|
12
|
-
|
|
13
|
-
example [
|
|
14
|
-
"welcome # Destroy `WelcomeMailer` mailer"
|
|
15
|
-
]
|
|
16
|
-
|
|
17
|
-
# @since 1.1.0
|
|
18
|
-
# @api private
|
|
19
|
-
def call(mailer:, **options)
|
|
20
|
-
mailer = Utils::String.transform(mailer, :underscore, :singularize)
|
|
21
|
-
context = Context.new(mailer: mailer, options: options)
|
|
22
|
-
|
|
23
|
-
assert_valid_mailer!(context)
|
|
24
|
-
|
|
25
|
-
destroy_mailer_spec(context)
|
|
26
|
-
destroy_templates(context)
|
|
27
|
-
destroy_mailer(context)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
private
|
|
31
|
-
|
|
32
|
-
# @since 1.1.0
|
|
33
|
-
# @api private
|
|
34
|
-
def assert_valid_mailer!(context)
|
|
35
|
-
destination = project.mailer(context)
|
|
36
|
-
return if files.exist?(destination)
|
|
37
|
-
|
|
38
|
-
destination = project.mailers(context)
|
|
39
|
-
warn "cannot find `#{context.mailer}' mailer. Please have a look at `#{destination}' directory to find an existing mailer."
|
|
40
|
-
exit(1)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# @since 1.1.0
|
|
44
|
-
# @api private
|
|
45
|
-
def destroy_mailer_spec(context)
|
|
46
|
-
destination = project.mailer_spec(context)
|
|
47
|
-
|
|
48
|
-
files.delete(destination)
|
|
49
|
-
say(:remove, destination)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
# @since 1.1.0
|
|
53
|
-
# @api private
|
|
54
|
-
def destroy_templates(context)
|
|
55
|
-
destinations = project.mailer_templates(context)
|
|
56
|
-
destinations.each do |destination|
|
|
57
|
-
files.delete(destination)
|
|
58
|
-
say(:remove, destination)
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
# @since 1.1.0
|
|
63
|
-
# @api private
|
|
64
|
-
def destroy_mailer(context)
|
|
65
|
-
destination = project.mailer(context)
|
|
66
|
-
|
|
67
|
-
files.delete(destination)
|
|
68
|
-
say(:remove, destination)
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
end
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
module Hanami
|
|
2
|
-
class CLI
|
|
3
|
-
module Commands
|
|
4
|
-
module Destroy
|
|
5
|
-
# @since 1.1.0
|
|
6
|
-
# @api private
|
|
7
|
-
class Migration < Command
|
|
8
|
-
desc "Destroy a migration"
|
|
9
|
-
|
|
10
|
-
argument :migration, required: true, desc: "The migration name (eg. `create_users`)"
|
|
11
|
-
|
|
12
|
-
example [
|
|
13
|
-
"create_users # Destroy `db/migrations/#{Project.migration_timestamp}_create_users.rb`"
|
|
14
|
-
]
|
|
15
|
-
|
|
16
|
-
# @since 1.1.0
|
|
17
|
-
# @api private
|
|
18
|
-
def call(migration:, **options)
|
|
19
|
-
migration = Utils::String.underscore(migration)
|
|
20
|
-
context = Context.new(migration: migration, options: options)
|
|
21
|
-
context = context.with(destination: project.find_migration(context))
|
|
22
|
-
|
|
23
|
-
assert_valid_migration!(context)
|
|
24
|
-
|
|
25
|
-
destroy_migration(context)
|
|
26
|
-
true
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
private
|
|
30
|
-
|
|
31
|
-
# @since 1.1.0
|
|
32
|
-
# @api private
|
|
33
|
-
def assert_valid_migration!(context)
|
|
34
|
-
return if !context.destination.nil? && files.exist?(context.destination)
|
|
35
|
-
|
|
36
|
-
destination = project.migrations(context)
|
|
37
|
-
warn "cannot find `#{context.migration}'. Please have a look at `#{destination}' directory to find an existing migration"
|
|
38
|
-
exit(1)
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
# @since 1.1.0
|
|
42
|
-
# @api private
|
|
43
|
-
def destroy_migration(context)
|
|
44
|
-
files.delete(context.destination)
|
|
45
|
-
say(:remove, context.destination)
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
end
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
module Hanami
|
|
2
|
-
class CLI
|
|
3
|
-
module Commands
|
|
4
|
-
module Destroy
|
|
5
|
-
# @since 1.1.0
|
|
6
|
-
# @api private
|
|
7
|
-
class Model < Command
|
|
8
|
-
requires "environment"
|
|
9
|
-
|
|
10
|
-
desc "Destroy a model"
|
|
11
|
-
|
|
12
|
-
argument :model, required: true, desc: "The model name (eg. `user`)"
|
|
13
|
-
|
|
14
|
-
example [
|
|
15
|
-
"user # Destroy `User` entity and `UserRepository` repository"
|
|
16
|
-
]
|
|
17
|
-
|
|
18
|
-
# @since 1.1.0
|
|
19
|
-
# @api private
|
|
20
|
-
def call(model:, **options)
|
|
21
|
-
model = Utils::String.transform(model, :underscore, :singularize)
|
|
22
|
-
context = Context.new(model: model, options: options)
|
|
23
|
-
|
|
24
|
-
assert_valid_model!(context)
|
|
25
|
-
|
|
26
|
-
destroy_repository_spec(context)
|
|
27
|
-
destroy_entity_spec(context)
|
|
28
|
-
destroy_repository(context)
|
|
29
|
-
destroy_entity(context)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
private
|
|
33
|
-
|
|
34
|
-
# @since 1.1.0
|
|
35
|
-
# @api private
|
|
36
|
-
def assert_valid_model!(context)
|
|
37
|
-
destination = project.entity(context)
|
|
38
|
-
return if files.exist?(destination)
|
|
39
|
-
|
|
40
|
-
destination = project.entities(context)
|
|
41
|
-
warn "cannot find `#{context.model}' model. Please have a look at `#{destination}' directory to find an existing model."
|
|
42
|
-
exit(1)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# @since 1.1.0
|
|
46
|
-
# @api private
|
|
47
|
-
def destroy_repository_spec(context)
|
|
48
|
-
destination = project.repository_spec(context)
|
|
49
|
-
|
|
50
|
-
files.delete(destination)
|
|
51
|
-
say(:remove, destination)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# @since 1.1.0
|
|
55
|
-
# @api private
|
|
56
|
-
def destroy_entity_spec(context)
|
|
57
|
-
destination = project.entity_spec(context)
|
|
58
|
-
|
|
59
|
-
files.delete(destination)
|
|
60
|
-
say(:remove, destination)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# @since 1.1.0
|
|
64
|
-
# @api private
|
|
65
|
-
def destroy_repository(context)
|
|
66
|
-
destination = project.repository(context)
|
|
67
|
-
|
|
68
|
-
files.delete(destination)
|
|
69
|
-
say(:remove, destination)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
# @since 1.1.0
|
|
73
|
-
# @api private
|
|
74
|
-
def destroy_entity(context)
|
|
75
|
-
destination = project.entity(context)
|
|
76
|
-
|
|
77
|
-
files.delete(destination)
|
|
78
|
-
say(:remove, destination)
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
end
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
module Hanami
|
|
2
|
-
# Hanami CLI
|
|
3
|
-
#
|
|
4
|
-
# @since 1.1.0
|
|
5
|
-
class CLI
|
|
6
|
-
module Commands
|
|
7
|
-
# @since 1.1.0
|
|
8
|
-
# @api private
|
|
9
|
-
module Generate
|
|
10
|
-
require "hanami/cli/commands/generate/app"
|
|
11
|
-
require "hanami/cli/commands/generate/action"
|
|
12
|
-
require "hanami/cli/commands/generate/mailer"
|
|
13
|
-
require "hanami/cli/commands/generate/migration"
|
|
14
|
-
require "hanami/cli/commands/generate/model"
|
|
15
|
-
require "hanami/cli/commands/generate/secret"
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
register "generate", aliases: ["g"] do |prefix|
|
|
20
|
-
prefix.register "app", Commands::Generate::App
|
|
21
|
-
prefix.register "action", Commands::Generate::Action
|
|
22
|
-
prefix.register "mailer", Commands::Generate::Mailer
|
|
23
|
-
prefix.register "migration", Commands::Generate::Migration
|
|
24
|
-
prefix.register "model", Commands::Generate::Model
|
|
25
|
-
prefix.register "secret", Commands::Generate::Secret
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
@@ -1,321 +0,0 @@
|
|
|
1
|
-
module Hanami
|
|
2
|
-
class CLI
|
|
3
|
-
module Commands
|
|
4
|
-
module Generate
|
|
5
|
-
# @since 1.1.0
|
|
6
|
-
# @api private
|
|
7
|
-
class Action < Command
|
|
8
|
-
requires "environment"
|
|
9
|
-
|
|
10
|
-
desc "Generate an action for app"
|
|
11
|
-
|
|
12
|
-
example [
|
|
13
|
-
"web home#index # Basic usage",
|
|
14
|
-
"admin home#index # Generate for `admin` app",
|
|
15
|
-
"web home#index --url=/ # Specify URL",
|
|
16
|
-
"web sessions#destroy --method=GET # Specify HTTP method",
|
|
17
|
-
"web books#create --skip-view # Skip view and template"
|
|
18
|
-
]
|
|
19
|
-
|
|
20
|
-
argument :app, required: true, desc: "The application name (eg. `web`)"
|
|
21
|
-
argument :action, required: true, desc: "The action name (eg. `home#index`)"
|
|
22
|
-
|
|
23
|
-
option :url, desc: "The action URL"
|
|
24
|
-
option :method, desc: "The action HTTP method"
|
|
25
|
-
option :skip_view, type: :boolean, default: false, desc: "Skip view and template"
|
|
26
|
-
|
|
27
|
-
# @since 1.1.0
|
|
28
|
-
# @api private
|
|
29
|
-
#
|
|
30
|
-
# rubocop:disable Metrics/AbcSize
|
|
31
|
-
# rubocop:disable Metrics/MethodLength
|
|
32
|
-
def call(app:, action:, **options)
|
|
33
|
-
*controller, action = controller_and_action_name(action)
|
|
34
|
-
classified_controller_name = classified_controller(controller)
|
|
35
|
-
http_method = route_http_method(action, options)
|
|
36
|
-
context = Context.new(app: app, controller: controller, classified_controller_name: classified_controller_name, action: action, test: options.fetch(:test), http_method: http_method, options: options)
|
|
37
|
-
context = context.with(template: project.template(context),
|
|
38
|
-
action_class_definition: action_class_definition(context),
|
|
39
|
-
view_class_definition: view_class_definition(context),
|
|
40
|
-
beginning_module_definition: beginning_module_definition(context),
|
|
41
|
-
ending_module_definition: ending_module_definition(context))
|
|
42
|
-
|
|
43
|
-
assert_valid_app!(context)
|
|
44
|
-
assert_valid_route_url!(context)
|
|
45
|
-
assert_valid_route_http_method!(context)
|
|
46
|
-
|
|
47
|
-
generate_action(context)
|
|
48
|
-
generate_view(context)
|
|
49
|
-
generate_template(context)
|
|
50
|
-
generate_action_spec(context)
|
|
51
|
-
generate_view_spec(context)
|
|
52
|
-
insert_route(context)
|
|
53
|
-
end
|
|
54
|
-
# rubocop:enable Metrics/MethodLength
|
|
55
|
-
# rubocop:enable Metrics/AbcSize
|
|
56
|
-
|
|
57
|
-
private
|
|
58
|
-
|
|
59
|
-
# @since 1.3.0
|
|
60
|
-
# @api private
|
|
61
|
-
def beginning_module_definition(context)
|
|
62
|
-
length = context.classified_controller_name.split("::").size
|
|
63
|
-
first_indentation = " " * 4
|
|
64
|
-
indentation = first_indentation
|
|
65
|
-
beginning_module_definition = ""
|
|
66
|
-
|
|
67
|
-
context.classified_controller_name.split("::").each_with_index do |module_name, index|
|
|
68
|
-
beginning_module_definition += "module #{module_name}".prepend(indentation)
|
|
69
|
-
beginning_module_definition += "\n" unless length == index + 1
|
|
70
|
-
indentation += " "
|
|
71
|
-
end
|
|
72
|
-
beginning_module_definition
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
# @since 1.3.0
|
|
76
|
-
# @api private
|
|
77
|
-
def ending_module_definition(context)
|
|
78
|
-
length = context.classified_controller_name.split("::").size
|
|
79
|
-
first_indentation = " " * 4
|
|
80
|
-
indentation = first_indentation + " " * (length - 1)
|
|
81
|
-
ending_module_definition = ""
|
|
82
|
-
|
|
83
|
-
context.classified_controller_name.split("::").each_with_index do |_, index|
|
|
84
|
-
ending_module_definition += "end".prepend(indentation)
|
|
85
|
-
ending_module_definition += "\n" unless length == index + 1
|
|
86
|
-
indentation = " " * (indentation.size - 2)
|
|
87
|
-
end
|
|
88
|
-
ending_module_definition
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
# @since 1.3.0
|
|
92
|
-
# @api private
|
|
93
|
-
def action_class_definition(context)
|
|
94
|
-
body_line_position = 4
|
|
95
|
-
view_class = [
|
|
96
|
-
"class #{context.action.classify}",
|
|
97
|
-
" include #{context.app.classify}::Action",
|
|
98
|
-
"",
|
|
99
|
-
" def call(params)",
|
|
100
|
-
" end",
|
|
101
|
-
"end"
|
|
102
|
-
]
|
|
103
|
-
view_class.insert(body_line_position, " self.body = 'OK'") if skip_view?(context)
|
|
104
|
-
|
|
105
|
-
add_indentation_to_class_definition(context, view_class)
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
# @since 1.3.0
|
|
109
|
-
# @api private
|
|
110
|
-
def view_class_definition(context)
|
|
111
|
-
view_class = [
|
|
112
|
-
"class #{context.action.classify}",
|
|
113
|
-
" include #{context.app.classify}::View",
|
|
114
|
-
"end"
|
|
115
|
-
]
|
|
116
|
-
|
|
117
|
-
add_indentation_to_class_definition(context, view_class)
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
# @since 1.3.0
|
|
121
|
-
# @api private
|
|
122
|
-
def add_indentation_to_class_definition(context, view_content)
|
|
123
|
-
length = context.classified_controller_name.split("::").size
|
|
124
|
-
first_indentation = " " * 4
|
|
125
|
-
indentation = first_indentation + " " * length * 2
|
|
126
|
-
|
|
127
|
-
content = ""
|
|
128
|
-
view_content.each do |line|
|
|
129
|
-
next content += "\n" if line.empty?
|
|
130
|
-
content += "#{line}\n".prepend(indentation)
|
|
131
|
-
end
|
|
132
|
-
content.chomp
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
# @since 1.1.0
|
|
136
|
-
# @api private
|
|
137
|
-
def controller_and_action_name(name)
|
|
138
|
-
# FIXME: extract this regexp
|
|
139
|
-
name.split(/#|\//)
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
# @since 1.1.0
|
|
143
|
-
# @api private
|
|
144
|
-
def assert_valid_app!(context)
|
|
145
|
-
return if project.app?(context)
|
|
146
|
-
|
|
147
|
-
existing_apps = project.apps.map { |name| "`#{name}'" }.join(' ')
|
|
148
|
-
warn "`#{context.app}' is not a valid APP. Please specify one of: #{existing_apps}"
|
|
149
|
-
exit(1)
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
# @since 1.1.0
|
|
153
|
-
# @api private
|
|
154
|
-
def assert_valid_route_url!(context)
|
|
155
|
-
if context.options.key?(:url) && Utils::Blank.blank?(context.options[:url]) # rubocop:disable Style/GuardClause
|
|
156
|
-
warn "`#{context.options[:url]}' is not a valid URL"
|
|
157
|
-
exit(1)
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
# @since 1.1.0
|
|
162
|
-
# @api private
|
|
163
|
-
def assert_valid_route_http_method!(context)
|
|
164
|
-
unless Hanami::Routing::Route::VALID_HTTP_VERBS.include?(context.http_method.upcase) # rubocop:disable Style/GuardClause
|
|
165
|
-
warn "`#{context.http_method.upcase}' is not a valid HTTP method. Please use one of: #{Hanami::Routing::Route::VALID_HTTP_VERBS.map { |verb| "`#{verb}'" }.join(' ')}"
|
|
166
|
-
exit(1)
|
|
167
|
-
end
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
# @since 1.1.0
|
|
171
|
-
# @api private
|
|
172
|
-
def generate_action(context)
|
|
173
|
-
source = if skip_view?(context)
|
|
174
|
-
templates.find("action_without_view.erb")
|
|
175
|
-
else
|
|
176
|
-
templates.find("action.erb")
|
|
177
|
-
end
|
|
178
|
-
destination = project.action(context)
|
|
179
|
-
|
|
180
|
-
generate_file(source, destination, context)
|
|
181
|
-
say(:create, destination)
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
# @since 1.1.0
|
|
185
|
-
# @api private
|
|
186
|
-
def generate_view(context)
|
|
187
|
-
return if skip_view?(context)
|
|
188
|
-
|
|
189
|
-
source = templates.find("view.erb")
|
|
190
|
-
destination = project.view(context)
|
|
191
|
-
|
|
192
|
-
generate_file(source, destination, context)
|
|
193
|
-
say(:create, destination)
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
# @since 1.1.0
|
|
197
|
-
# @api private
|
|
198
|
-
def generate_template(context)
|
|
199
|
-
return if skip_view?(context)
|
|
200
|
-
destination = project.template(context)
|
|
201
|
-
|
|
202
|
-
files.touch(destination)
|
|
203
|
-
say(:create, destination)
|
|
204
|
-
end
|
|
205
|
-
|
|
206
|
-
# @since 1.1.0
|
|
207
|
-
# @api private
|
|
208
|
-
def generate_action_spec(context)
|
|
209
|
-
source = templates.find("action_spec.#{context.test}.erb")
|
|
210
|
-
destination = project.action_spec(context)
|
|
211
|
-
|
|
212
|
-
generate_file(source, destination, context)
|
|
213
|
-
say(:create, destination)
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
# @since 1.1.0
|
|
217
|
-
# @api private
|
|
218
|
-
def generate_view_spec(context)
|
|
219
|
-
return if skip_view?(context)
|
|
220
|
-
|
|
221
|
-
source = templates.find("view_spec.#{context.test}.erb")
|
|
222
|
-
destination = project.view_spec(context)
|
|
223
|
-
|
|
224
|
-
generate_file(source, destination, context)
|
|
225
|
-
say(:create, destination)
|
|
226
|
-
end
|
|
227
|
-
|
|
228
|
-
# @since 1.1.0
|
|
229
|
-
# @api private
|
|
230
|
-
def insert_route(context)
|
|
231
|
-
content = "#{context.http_method} '#{route_url(context)}', to: '#{route_endpoint(context)}'".downcase
|
|
232
|
-
destination = project.app_routes(context)
|
|
233
|
-
|
|
234
|
-
files.append(destination, content)
|
|
235
|
-
say(:insert, destination)
|
|
236
|
-
end
|
|
237
|
-
|
|
238
|
-
# @since 1.1.0
|
|
239
|
-
# @api private
|
|
240
|
-
def route_http_method(action, options)
|
|
241
|
-
options.fetch(:method) { route_resourceful_http_method(action) }
|
|
242
|
-
end
|
|
243
|
-
|
|
244
|
-
# @since 1.1.0
|
|
245
|
-
# @api private
|
|
246
|
-
def skip_view?(context)
|
|
247
|
-
context.options.fetch(:skip_view, false)
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
# @since 1.1.0
|
|
251
|
-
# @api private
|
|
252
|
-
DEFAULT_HTTP_METHOD = 'GET'.freeze
|
|
253
|
-
|
|
254
|
-
# @since 1.1.0
|
|
255
|
-
# @api private
|
|
256
|
-
RESOURCEFUL_HTTP_METHODS = {
|
|
257
|
-
'create' => 'POST',
|
|
258
|
-
'update' => 'PATCH',
|
|
259
|
-
'destroy' => 'DELETE'
|
|
260
|
-
}.freeze
|
|
261
|
-
|
|
262
|
-
# @since 1.1.0
|
|
263
|
-
# @api private
|
|
264
|
-
def route_resourceful_http_method(action)
|
|
265
|
-
RESOURCEFUL_HTTP_METHODS.fetch(action, DEFAULT_HTTP_METHOD)
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
# @since 1.1.0
|
|
269
|
-
# @api private
|
|
270
|
-
def route_url(context)
|
|
271
|
-
context.options.fetch(:url) { route_resourceful_url(context) }
|
|
272
|
-
end
|
|
273
|
-
|
|
274
|
-
# @since 1.1.0
|
|
275
|
-
# @api private
|
|
276
|
-
def route_resourceful_url(context)
|
|
277
|
-
"/#{namespaced_controller(context)}#{route_resourceful_url_suffix(context)}"
|
|
278
|
-
end
|
|
279
|
-
|
|
280
|
-
# @since 1.1.0
|
|
281
|
-
# @api private
|
|
282
|
-
RESOURCEFUL_ROUTE_URL_SUFFIXES = {
|
|
283
|
-
'index' => '',
|
|
284
|
-
'new' => '/new',
|
|
285
|
-
'create' => '',
|
|
286
|
-
'edit' => '/:id/edit',
|
|
287
|
-
'update' => '/:id',
|
|
288
|
-
'show' => '/:id',
|
|
289
|
-
'destroy' => '/:id'
|
|
290
|
-
}.freeze
|
|
291
|
-
|
|
292
|
-
# @since 1.1.0
|
|
293
|
-
# @api private
|
|
294
|
-
def route_resourceful_url_suffix(context)
|
|
295
|
-
RESOURCEFUL_ROUTE_URL_SUFFIXES.fetch(context.action) { "/#{context.action}" }
|
|
296
|
-
end
|
|
297
|
-
|
|
298
|
-
# @since 1.1.0
|
|
299
|
-
# @api private
|
|
300
|
-
def route_endpoint(context)
|
|
301
|
-
"#{namespaced_controller(context)}##{context.action}"
|
|
302
|
-
end
|
|
303
|
-
|
|
304
|
-
# @since 1.1.0
|
|
305
|
-
# @api private
|
|
306
|
-
def classified_controller(controller)
|
|
307
|
-
controller.
|
|
308
|
-
map { |controller_name| Utils::String.new(controller_name).classify }.
|
|
309
|
-
join("::")
|
|
310
|
-
end
|
|
311
|
-
|
|
312
|
-
# @since 1.1.0
|
|
313
|
-
# @api private
|
|
314
|
-
def namespaced_controller(context)
|
|
315
|
-
context.controller.join("/")
|
|
316
|
-
end
|
|
317
|
-
end
|
|
318
|
-
end
|
|
319
|
-
end
|
|
320
|
-
end
|
|
321
|
-
end
|