hanami 2.0.0.alpha7.1 → 2.0.0.beta1.1
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 +457 -237
- data/FEATURES.md +30 -9
- data/README.md +1 -3
- data/hanami.gemspec +21 -11
- data/lib/hanami/app.rb +141 -0
- data/lib/hanami/assets/application_configuration.rb +10 -4
- data/lib/hanami/configuration/actions/content_security_policy.rb +118 -0
- data/lib/hanami/configuration/actions/cookies.rb +29 -0
- data/lib/hanami/configuration/actions/sessions.rb +46 -0
- data/lib/hanami/configuration/actions.rb +23 -12
- data/lib/hanami/configuration/logger.rb +13 -10
- data/lib/hanami/configuration/router.rb +2 -6
- data/lib/hanami/configuration/sessions.rb +1 -1
- data/lib/hanami/configuration/views.rb +86 -0
- data/lib/hanami/configuration.rb +139 -82
- data/lib/hanami/constants.rb +30 -2
- data/lib/hanami/errors.rb +4 -1
- data/lib/hanami/extensions/action/slice_configured_action.rb +103 -0
- data/lib/hanami/extensions/action.rb +79 -0
- data/lib/hanami/extensions/view/context.rb +106 -0
- data/lib/hanami/extensions/view/slice_configured_context.rb +71 -0
- data/lib/hanami/extensions/view/slice_configured_view.rb +107 -0
- data/lib/hanami/extensions/view.rb +33 -0
- data/lib/hanami/extensions.rb +10 -0
- data/lib/hanami/providers/inflector.rb +13 -0
- data/lib/hanami/providers/logger.rb +13 -0
- data/lib/hanami/providers/rack.rb +27 -0
- data/lib/hanami/providers/routes.rb +33 -0
- data/lib/hanami/providers/settings.rb +23 -0
- data/lib/hanami/rake_tasks.rb +61 -0
- data/lib/hanami/routes.rb +51 -0
- data/lib/hanami/server.rb +1 -1
- data/lib/hanami/settings/dotenv_store.rb +58 -0
- data/lib/hanami/settings.rb +90 -0
- data/lib/hanami/setup.rb +4 -2
- data/lib/hanami/{application → slice}/router.rb +18 -13
- data/lib/hanami/slice/routes_helper.rb +37 -0
- data/lib/hanami/{application → slice}/routing/middleware/stack.rb +43 -5
- data/lib/hanami/slice/routing/resolver.rb +97 -0
- data/lib/hanami/slice/view_name_inferrer.rb +63 -0
- data/lib/hanami/slice.rb +252 -82
- data/lib/hanami/slice_configurable.rb +62 -0
- data/lib/hanami/slice_name.rb +111 -0
- data/lib/hanami/slice_registrar.rb +119 -0
- data/lib/hanami/version.rb +1 -1
- data/lib/hanami/web/rack_logger.rb +1 -1
- data/lib/hanami.rb +34 -26
- data/spec/integration/application_middleware_stack_spec.rb +84 -0
- data/spec/integration/assets/cdn_spec.rb +48 -0
- data/spec/integration/assets/fingerprint_spec.rb +42 -0
- data/spec/integration/assets/helpers_spec.rb +50 -0
- data/spec/integration/assets/serve_spec.rb +70 -0
- data/spec/integration/assets/subresource_integrity_spec.rb +54 -0
- data/spec/integration/body_parsers_spec.rb +50 -0
- data/spec/integration/cli/assets/precompile_spec.rb +147 -0
- data/spec/integration/cli/assets_spec.rb +14 -0
- data/spec/integration/cli/console_spec.rb +105 -0
- data/spec/integration/cli/db/apply_spec.rb +74 -0
- data/spec/integration/cli/db/console_spec.rb +40 -0
- data/spec/integration/cli/db/create_spec.rb +50 -0
- data/spec/integration/cli/db/drop_spec.rb +54 -0
- data/spec/integration/cli/db/migrate_spec.rb +108 -0
- data/spec/integration/cli/db/prepare_spec.rb +36 -0
- data/spec/integration/cli/db/rollback_spec.rb +96 -0
- data/spec/integration/cli/db/version_spec.rb +38 -0
- data/spec/integration/cli/db_spec.rb +21 -0
- data/spec/integration/cli/destroy/action_spec.rb +143 -0
- data/spec/integration/cli/destroy/app_spec.rb +118 -0
- data/spec/integration/cli/destroy/mailer_spec.rb +74 -0
- data/spec/integration/cli/destroy/migration_spec.rb +70 -0
- data/spec/integration/cli/destroy/model_spec.rb +113 -0
- data/spec/integration/cli/destroy_spec.rb +18 -0
- data/spec/integration/cli/generate/action_spec.rb +469 -0
- data/spec/integration/cli/generate/app_spec.rb +215 -0
- data/spec/integration/cli/generate/mailer_spec.rb +189 -0
- data/spec/integration/cli/generate/migration_spec.rb +72 -0
- data/spec/integration/cli/generate/model_spec.rb +290 -0
- data/spec/integration/cli/generate/secret_spec.rb +56 -0
- data/spec/integration/cli/generate_spec.rb +19 -0
- data/spec/integration/cli/new/database_spec.rb +235 -0
- data/spec/integration/cli/new/hanami_head_spec.rb +27 -0
- data/spec/integration/cli/new/template_spec.rb +118 -0
- data/spec/integration/cli/new/test_spec.rb +274 -0
- data/spec/integration/cli/new_spec.rb +970 -0
- data/spec/integration/cli/plugins_spec.rb +39 -0
- data/spec/integration/cli/routes_spec.rb +49 -0
- data/spec/integration/cli/server_spec.rb +626 -0
- data/spec/integration/cli/version_spec.rb +85 -0
- data/spec/integration/early_hints_spec.rb +35 -0
- data/spec/integration/handle_exceptions_spec.rb +244 -0
- data/spec/integration/head_spec.rb +89 -0
- data/spec/integration/http_headers_spec.rb +29 -0
- data/spec/integration/mailer_spec.rb +32 -0
- data/spec/integration/middleware_spec.rb +81 -0
- data/spec/integration/mount_applications_spec.rb +88 -0
- data/spec/integration/project_initializers_spec.rb +40 -0
- data/spec/integration/rackup_spec.rb +35 -0
- data/spec/integration/rake/with_minitest_spec.rb +67 -0
- data/spec/integration/rake/with_rspec_spec.rb +69 -0
- data/spec/integration/routing_helpers_spec.rb +61 -0
- data/spec/integration/security/content_security_policy_spec.rb +46 -0
- data/spec/integration/security/csrf_protection_spec.rb +42 -0
- data/spec/integration/security/force_ssl_spec.rb +29 -0
- data/spec/integration/security/x_content_type_options_spec.rb +46 -0
- data/spec/integration/security/x_frame_options_spec.rb +46 -0
- data/spec/integration/security/x_xss_protection_spec.rb +46 -0
- data/spec/integration/send_file_spec.rb +51 -0
- data/spec/integration/sessions_spec.rb +247 -0
- data/spec/integration/static_middleware_spec.rb +21 -0
- data/spec/integration/streaming_spec.rb +41 -0
- data/spec/integration/unsafe_send_file_spec.rb +52 -0
- data/spec/isolation/hanami/application/already_configured_spec.rb +19 -0
- data/spec/isolation/hanami/application/inherit_anonymous_class_spec.rb +10 -0
- data/spec/isolation/hanami/application/inherit_concrete_class_spec.rb +14 -0
- data/spec/isolation/hanami/application/not_configured_spec.rb +9 -0
- data/spec/isolation/hanami/application/routes/configured_spec.rb +44 -0
- data/spec/isolation/hanami/application/routes/not_configured_spec.rb +16 -0
- data/spec/isolation/hanami/boot/success_spec.rb +50 -0
- data/spec/new_integration/action/configuration_spec.rb +26 -0
- data/spec/new_integration/action/cookies_spec.rb +58 -0
- data/spec/new_integration/action/csrf_protection_spec.rb +54 -0
- data/spec/new_integration/action/routes_spec.rb +73 -0
- data/spec/new_integration/action/sessions_spec.rb +50 -0
- data/spec/new_integration/action/view_integration_spec.rb +165 -0
- data/spec/new_integration/action/view_rendering/automatic_rendering_spec.rb +247 -0
- data/spec/new_integration/action/view_rendering/paired_view_inference_spec.rb +115 -0
- data/spec/new_integration/action/view_rendering_spec.rb +107 -0
- data/spec/new_integration/code_loading/loading_from_app_spec.rb +152 -0
- data/spec/new_integration/code_loading/loading_from_slice_spec.rb +165 -0
- data/spec/new_integration/container/application_routes_helper_spec.rb +48 -0
- data/spec/new_integration/container/auto_injection_spec.rb +53 -0
- data/spec/new_integration/container/auto_registration_spec.rb +86 -0
- data/spec/new_integration/container/autoloader_spec.rb +80 -0
- data/spec/new_integration/container/imports_spec.rb +253 -0
- data/spec/new_integration/container/prepare_container_spec.rb +123 -0
- data/spec/new_integration/container/shutdown_spec.rb +91 -0
- data/spec/new_integration/container/standard_bootable_components_spec.rb +124 -0
- data/spec/new_integration/rack_app/middleware_spec.rb +215 -0
- data/spec/new_integration/rack_app/non_booted_rack_app_spec.rb +105 -0
- data/spec/new_integration/rack_app/rack_app_spec.rb +524 -0
- data/spec/new_integration/settings_spec.rb +115 -0
- data/spec/new_integration/slices/external_slice_spec.rb +92 -0
- data/spec/new_integration/slices/slice_configuration_spec.rb +40 -0
- data/spec/new_integration/slices/slice_routing_spec.rb +226 -0
- data/spec/new_integration/slices/slice_settings_spec.rb +141 -0
- data/spec/new_integration/slices_spec.rb +101 -0
- data/spec/new_integration/view/configuration_spec.rb +49 -0
- data/spec/new_integration/view/context/assets_spec.rb +67 -0
- data/spec/new_integration/view/context/inflector_spec.rb +48 -0
- data/spec/new_integration/view/context/request_spec.rb +61 -0
- data/spec/new_integration/view/context/routes_spec.rb +86 -0
- data/spec/new_integration/view/context/settings_spec.rb +50 -0
- data/spec/new_integration/view/inflector_spec.rb +57 -0
- data/spec/new_integration/view/part_namespace_spec.rb +96 -0
- data/spec/new_integration/view/path_spec.rb +56 -0
- data/spec/new_integration/view/template_spec.rb +68 -0
- data/spec/new_integration/view/views_spec.rb +103 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/support/app_integration.rb +91 -0
- data/spec/support/coverage.rb +1 -0
- data/spec/support/fixtures/hanami-plugin/Gemfile +8 -0
- data/spec/support/fixtures/hanami-plugin/README.md +35 -0
- data/spec/support/fixtures/hanami-plugin/Rakefile +4 -0
- data/spec/support/fixtures/hanami-plugin/bin/console +15 -0
- data/spec/support/fixtures/hanami-plugin/bin/setup +8 -0
- data/spec/support/fixtures/hanami-plugin/hanami-plugin.gemspec +28 -0
- data/spec/support/fixtures/hanami-plugin/lib/hanami/plugin/cli.rb +19 -0
- data/spec/support/fixtures/hanami-plugin/lib/hanami/plugin/version.rb +7 -0
- data/spec/support/fixtures/hanami-plugin/lib/hanami/plugin.rb +8 -0
- data/spec/support/rspec.rb +27 -0
- data/spec/support/shared_examples/cli/generate/app.rb +494 -0
- data/spec/support/shared_examples/cli/generate/migration.rb +32 -0
- data/spec/support/shared_examples/cli/generate/model.rb +81 -0
- data/spec/support/shared_examples/cli/new.rb +97 -0
- data/spec/unit/hanami/configuration/actions/content_security_policy_spec.rb +102 -0
- data/spec/unit/hanami/configuration/actions/cookies_spec.rb +46 -0
- data/spec/unit/hanami/configuration/actions/csrf_protection_spec.rb +57 -0
- data/spec/unit/hanami/configuration/actions/default_values_spec.rb +52 -0
- data/spec/unit/hanami/configuration/actions/sessions_spec.rb +50 -0
- data/spec/unit/hanami/configuration/actions_spec.rb +78 -0
- data/spec/unit/hanami/configuration/base_url_spec.rb +25 -0
- data/spec/unit/hanami/configuration/inflector_spec.rb +35 -0
- data/spec/unit/hanami/configuration/logger_spec.rb +203 -0
- data/spec/unit/hanami/configuration/views_spec.rb +120 -0
- data/spec/unit/hanami/configuration_spec.rb +43 -0
- data/spec/unit/hanami/env_spec.rb +54 -0
- data/spec/unit/hanami/routes_spec.rb +25 -0
- data/spec/unit/hanami/settings/dotenv_store_spec.rb +119 -0
- data/spec/unit/hanami/settings_spec.rb +56 -0
- data/spec/unit/hanami/slice_configurable_spec.rb +104 -0
- data/spec/unit/hanami/slice_name_spec.rb +47 -0
- data/spec/unit/hanami/slice_spec.rb +17 -0
- data/spec/unit/hanami/version_spec.rb +7 -0
- data/spec/unit/hanami/web/rack_logger_spec.rb +78 -0
- metadata +363 -55
- data/lib/hanami/application/container/providers/inflector.rb +0 -7
- data/lib/hanami/application/container/providers/logger.rb +0 -7
- data/lib/hanami/application/container/providers/rack_logger.rb +0 -15
- data/lib/hanami/application/container/providers/rack_monitor.rb +0 -12
- data/lib/hanami/application/container/providers/routes_helper.rb +0 -9
- data/lib/hanami/application/container/providers/settings.rb +0 -7
- data/lib/hanami/application/routes.rb +0 -55
- data/lib/hanami/application/routes_helper.rb +0 -34
- data/lib/hanami/application/routing/resolver/node.rb +0 -50
- data/lib/hanami/application/routing/resolver/trie.rb +0 -59
- data/lib/hanami/application/routing/resolver.rb +0 -87
- data/lib/hanami/application/routing/router.rb +0 -36
- data/lib/hanami/application/settings/dotenv_store.rb +0 -60
- data/lib/hanami/application/settings.rb +0 -93
- data/lib/hanami/application/slice_registrar.rb +0 -106
- data/lib/hanami/application.rb +0 -299
- data/lib/hanami/boot/source_dirs.rb +0 -44
- data/lib/hanami/cli/application/cli.rb +0 -40
- data/lib/hanami/cli/application/command.rb +0 -47
- data/lib/hanami/cli/application/commands/console.rb +0 -81
- data/lib/hanami/cli/application/commands.rb +0 -16
- data/lib/hanami/cli/base_command.rb +0 -48
- data/lib/hanami/cli/commands/command.rb +0 -171
- data/lib/hanami/cli/commands/server.rb +0 -88
- data/lib/hanami/cli/commands.rb +0 -65
- data/lib/hanami/configuration/middleware.rb +0 -20
- data/lib/hanami/configuration/source_dirs.rb +0 -42
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dry/configurable"
|
|
4
|
+
require "dry/core/constants"
|
|
5
|
+
|
|
6
|
+
module Hanami
|
|
7
|
+
# App settings
|
|
8
|
+
#
|
|
9
|
+
# Users are expected to inherit from this class to define their app settings.
|
|
10
|
+
#
|
|
11
|
+
# @example
|
|
12
|
+
# # config/settings.rb
|
|
13
|
+
# # frozen_string_literal: true
|
|
14
|
+
#
|
|
15
|
+
# require "hanami/settings"
|
|
16
|
+
# require "my_app/types"
|
|
17
|
+
#
|
|
18
|
+
# module MyApp
|
|
19
|
+
# class Settings < Hanami::Settings
|
|
20
|
+
# setting :database_url
|
|
21
|
+
# setting :feature_flag, default: false, constructor: Types::Params::Bool
|
|
22
|
+
# end
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
25
|
+
# Settings are defined with
|
|
26
|
+
# [dry-configurable](https://dry-rb.org/gems/dry-configurable/), so you can
|
|
27
|
+
# take a look there to see the supported syntax.
|
|
28
|
+
#
|
|
29
|
+
# Users work with an instance of this class made available within the
|
|
30
|
+
# `settings` key in the container. The instance gets its settings populated
|
|
31
|
+
# from a configurable store, which defaults to
|
|
32
|
+
# {Hanami::Settings::DotenvStore}.
|
|
33
|
+
#
|
|
34
|
+
# A different store can be set through the `settings_store` Hanami
|
|
35
|
+
# configuration option. All it needs to do is implementing a `#fetch` method
|
|
36
|
+
# with the same signature as `Hash#fetch`.
|
|
37
|
+
#
|
|
38
|
+
# @see Hanami::Settings::DotenvStore
|
|
39
|
+
# @since 2.0.0
|
|
40
|
+
class Settings
|
|
41
|
+
# Exception for errors in the definition of settings.
|
|
42
|
+
#
|
|
43
|
+
# Its message collects all the individual errors that can be raised for
|
|
44
|
+
# each setting.
|
|
45
|
+
InvalidSettingsError = Class.new(StandardError) do
|
|
46
|
+
def initialize(errors)
|
|
47
|
+
@errors = errors
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def to_s
|
|
51
|
+
<<~STR.strip
|
|
52
|
+
Could not initialize settings. The following settings were invalid:
|
|
53
|
+
|
|
54
|
+
#{@errors.map { |setting, message| "#{setting}: #{message}" }.join("\n")}
|
|
55
|
+
STR
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @api private
|
|
60
|
+
EMPTY_STORE = Dry::Core::Constants::EMPTY_HASH
|
|
61
|
+
|
|
62
|
+
include Dry::Configurable
|
|
63
|
+
|
|
64
|
+
# @api private
|
|
65
|
+
def initialize(store = EMPTY_STORE)
|
|
66
|
+
errors = config._settings.map(&:name).reduce({}) do |errs, name|
|
|
67
|
+
public_send("#{name}=", store.fetch(name) { Dry::Core::Constants::Undefined })
|
|
68
|
+
errs
|
|
69
|
+
rescue => e # rubocop:disable Style/RescueStandardError
|
|
70
|
+
errs.merge(name => e)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
raise InvalidSettingsError, errors if errors.any?
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def method_missing(name, *args, &block)
|
|
79
|
+
if config.respond_to?(name)
|
|
80
|
+
config.send(name, *args, &block)
|
|
81
|
+
else
|
|
82
|
+
super
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def respond_to_missing?(name, _include_all = false)
|
|
87
|
+
config.respond_to?(name) || super
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
data/lib/hanami/setup.rb
CHANGED
|
@@ -4,6 +4,8 @@ require "bundler/setup"
|
|
|
4
4
|
require "hanami"
|
|
5
5
|
|
|
6
6
|
begin
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
app_require_path = File.join(Dir.pwd, "config/app")
|
|
8
|
+
require app_require_path
|
|
9
|
+
rescue LoadError => e
|
|
10
|
+
raise e unless e.path == app_require_path
|
|
9
11
|
end
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "hanami/router"
|
|
4
|
-
|
|
4
|
+
require_relative "routing/middleware/stack"
|
|
5
5
|
|
|
6
6
|
module Hanami
|
|
7
|
-
class
|
|
8
|
-
# Hanami
|
|
7
|
+
class Slice
|
|
8
|
+
# Hanami app router
|
|
9
9
|
# @since 2.0.0
|
|
10
10
|
class Router < ::Hanami::Router
|
|
11
|
+
# @api private
|
|
12
|
+
attr_reader :middleware_stack
|
|
13
|
+
|
|
11
14
|
# @since 2.0.0
|
|
12
15
|
# @api private
|
|
13
16
|
def initialize(routes:, middleware_stack: Routing::Middleware::Stack.new, **kwargs, &blk)
|
|
@@ -27,32 +30,34 @@ module Hanami
|
|
|
27
30
|
|
|
28
31
|
# @since 2.0.0
|
|
29
32
|
# @api private
|
|
30
|
-
def use(
|
|
31
|
-
|
|
33
|
+
def use(...)
|
|
34
|
+
middleware_stack.use(...)
|
|
32
35
|
end
|
|
33
36
|
|
|
34
37
|
# @since 2.0.0
|
|
35
38
|
# @api private
|
|
36
39
|
def scope(*args, &blk)
|
|
37
|
-
|
|
40
|
+
middleware_stack.with(args.first) do
|
|
38
41
|
super
|
|
39
42
|
end
|
|
40
43
|
end
|
|
41
44
|
|
|
42
45
|
# @since 2.0.0
|
|
43
|
-
def slice(
|
|
44
|
-
|
|
45
|
-
@resolver.register_slice_at_path(name, path)
|
|
46
|
+
def slice(slice_name, at:, &blk)
|
|
47
|
+
blk ||= @resolver.find_slice(slice_name).routes
|
|
46
48
|
|
|
47
|
-
|
|
49
|
+
prev_resolver = @resolver
|
|
50
|
+
@resolver = @resolver.to_slice(slice_name)
|
|
51
|
+
|
|
52
|
+
scope(prefixed_path(at), &blk)
|
|
53
|
+
ensure
|
|
54
|
+
@resolver = prev_resolver
|
|
48
55
|
end
|
|
49
56
|
|
|
50
57
|
# @since 2.0.0
|
|
51
58
|
# @api private
|
|
52
59
|
def to_rack_app
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
@middleware_stack.to_rack_app(self)
|
|
60
|
+
middleware_stack.to_rack_app(self)
|
|
56
61
|
end
|
|
57
62
|
end
|
|
58
63
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hanami
|
|
4
|
+
class Slice
|
|
5
|
+
# Hanami app routes helpers
|
|
6
|
+
#
|
|
7
|
+
# An instance of this class will be registered with slice (at the "routes" key). You
|
|
8
|
+
# can use it to access the route helpers for your app.
|
|
9
|
+
#
|
|
10
|
+
# @example
|
|
11
|
+
# MyApp::App["routes"].path(:root) # => "/"
|
|
12
|
+
#
|
|
13
|
+
# @see Hanami::Router::UrlHelpers
|
|
14
|
+
# @since 2.0.0
|
|
15
|
+
class RoutesHelper
|
|
16
|
+
# @since 2.0.0
|
|
17
|
+
# @api private
|
|
18
|
+
def initialize(router)
|
|
19
|
+
@router = router
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @see Hanami::Router::UrlHelpers#path
|
|
23
|
+
def path(...)
|
|
24
|
+
router.path(...)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @see Hanami::Router::UrlHelpers#url
|
|
28
|
+
def url(...)
|
|
29
|
+
router.url(...)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
attr_reader :router
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
require "rack/builder"
|
|
4
4
|
|
|
5
5
|
module Hanami
|
|
6
|
-
class
|
|
6
|
+
class Slice
|
|
7
7
|
module Routing
|
|
8
8
|
# Hanami::Applicatione::Router middleware stack
|
|
9
9
|
#
|
|
@@ -20,6 +20,10 @@ module Hanami
|
|
|
20
20
|
ROOT_PREFIX = "/"
|
|
21
21
|
private_constant :ROOT_PREFIX
|
|
22
22
|
|
|
23
|
+
# @since 2.0.0
|
|
24
|
+
# @api private
|
|
25
|
+
attr_reader :stack
|
|
26
|
+
|
|
23
27
|
# @since 2.0.0
|
|
24
28
|
# @api private
|
|
25
29
|
def initialize
|
|
@@ -29,8 +33,35 @@ module Hanami
|
|
|
29
33
|
|
|
30
34
|
# @since 2.0.0
|
|
31
35
|
# @api private
|
|
32
|
-
def
|
|
33
|
-
|
|
36
|
+
def initialize_copy(source)
|
|
37
|
+
super
|
|
38
|
+
@prefix = source.instance_variable_get(:@prefix).dup
|
|
39
|
+
@stack = stack.dup
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @since 2.0.0
|
|
43
|
+
# @api private
|
|
44
|
+
def use(middleware, *args, before: nil, after: nil, &blk)
|
|
45
|
+
item = [middleware, args, blk]
|
|
46
|
+
|
|
47
|
+
if before
|
|
48
|
+
@stack[@prefix].insert((idx = index_of(before)).zero? ? 0 : idx - 1, item)
|
|
49
|
+
elsif after
|
|
50
|
+
@stack[@prefix].insert(index_of(after) + 1, item)
|
|
51
|
+
else
|
|
52
|
+
@stack[@prefix].push([middleware, args, blk])
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
self
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# @since 2.0.0
|
|
59
|
+
# @api private
|
|
60
|
+
def update(other)
|
|
61
|
+
other.stack.each do |prefix, items|
|
|
62
|
+
stack[prefix].concat(items)
|
|
63
|
+
end
|
|
64
|
+
self
|
|
34
65
|
end
|
|
35
66
|
|
|
36
67
|
# @since 2.0.0
|
|
@@ -45,7 +76,7 @@ module Hanami
|
|
|
45
76
|
|
|
46
77
|
# @since 2.0.0
|
|
47
78
|
# @api private
|
|
48
|
-
def to_rack_app(app)
|
|
79
|
+
def to_rack_app(app)
|
|
49
80
|
s = self
|
|
50
81
|
|
|
51
82
|
Rack::Builder.new do
|
|
@@ -58,7 +89,7 @@ module Hanami
|
|
|
58
89
|
|
|
59
90
|
run app
|
|
60
91
|
end
|
|
61
|
-
end
|
|
92
|
+
end
|
|
62
93
|
end
|
|
63
94
|
|
|
64
95
|
# @since 2.0.0
|
|
@@ -82,6 +113,13 @@ module Hanami
|
|
|
82
113
|
builder.map(prefix, &blk)
|
|
83
114
|
end
|
|
84
115
|
end
|
|
116
|
+
|
|
117
|
+
private
|
|
118
|
+
|
|
119
|
+
# @since 2.0.0
|
|
120
|
+
def index_of(middleware)
|
|
121
|
+
@stack[@prefix].index { |(m, *)| m.equal?(middleware) }
|
|
122
|
+
end
|
|
85
123
|
end
|
|
86
124
|
end
|
|
87
125
|
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hanami
|
|
4
|
+
class Slice
|
|
5
|
+
module Routing
|
|
6
|
+
# @since 2.0.0
|
|
7
|
+
class UnknownActionError < Hanami::Error
|
|
8
|
+
def initialize(identifier)
|
|
9
|
+
super("unknown action referenced in router: `#{identifier.inspect}'")
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @since 2.0.0
|
|
14
|
+
class NotCallableEndpointError < StandardError
|
|
15
|
+
def initialize(endpoint)
|
|
16
|
+
super("#{endpoint.inspect} is not compatible with Rack. Please make sure it implements #call.")
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Hanami app router endpoint resolver
|
|
21
|
+
#
|
|
22
|
+
# @since 2.0.0
|
|
23
|
+
class Resolver
|
|
24
|
+
SLICE_ACTIONS_KEY_NAMESPACE = "actions"
|
|
25
|
+
|
|
26
|
+
# @api private
|
|
27
|
+
# @since 2.0.0
|
|
28
|
+
def initialize(slice:)
|
|
29
|
+
@slice = slice
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @api private
|
|
33
|
+
# @since 2.0.0
|
|
34
|
+
def find_slice(slice_name)
|
|
35
|
+
slice.slices[slice_name]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @api private
|
|
39
|
+
# @since 2.0.0
|
|
40
|
+
def to_slice(slice_name)
|
|
41
|
+
self.class.new(slice: find_slice(slice_name))
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# @api private
|
|
45
|
+
# @since 2.0.0
|
|
46
|
+
def call(_path, endpoint)
|
|
47
|
+
endpoint =
|
|
48
|
+
case endpoint
|
|
49
|
+
when String
|
|
50
|
+
resolve_slice_action(endpoint)
|
|
51
|
+
when Class
|
|
52
|
+
endpoint.respond_to?(:call) ? endpoint : endpoint.new
|
|
53
|
+
else
|
|
54
|
+
endpoint
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
unless endpoint.respond_to?(:call)
|
|
58
|
+
raise NotCallableEndpointError.new(endpoint)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
endpoint
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
# @api private
|
|
67
|
+
# @since 2.0.0
|
|
68
|
+
attr_reader :slice
|
|
69
|
+
|
|
70
|
+
# @api private
|
|
71
|
+
# @since 2.0.0
|
|
72
|
+
def resolve_slice_action(key)
|
|
73
|
+
action_key = "#{SLICE_ACTIONS_KEY_NAMESPACE}.#{key}"
|
|
74
|
+
|
|
75
|
+
ensure_action_in_slice(action_key)
|
|
76
|
+
|
|
77
|
+
# Lazily resolve action from the slice to reduce router initialization time, and
|
|
78
|
+
# circumvent endless loops from the action requiring access to router-related
|
|
79
|
+
# concerns (which may not be fully loaded at the time of reading the routes)
|
|
80
|
+
-> (*args) {
|
|
81
|
+
action = slice.resolve(action_key) do
|
|
82
|
+
raise UnknownActionError.new(key)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
action.call(*args)
|
|
86
|
+
}
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def ensure_action_in_slice(key)
|
|
90
|
+
return unless slice.booted?
|
|
91
|
+
|
|
92
|
+
raise UnknownActionError.new(key) unless slice.key?(key)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../constants"
|
|
4
|
+
|
|
5
|
+
module Hanami
|
|
6
|
+
class Slice
|
|
7
|
+
# Infers a view name for automatically rendering within actions.
|
|
8
|
+
#
|
|
9
|
+
# @api private
|
|
10
|
+
# @since 2.0.0
|
|
11
|
+
class ViewNameInferrer
|
|
12
|
+
ALTERNATIVE_NAMES = {
|
|
13
|
+
"create" => "new",
|
|
14
|
+
"update" => "edit"
|
|
15
|
+
}.freeze
|
|
16
|
+
|
|
17
|
+
class << self
|
|
18
|
+
# Returns an array of container keys for views matching the given action.
|
|
19
|
+
#
|
|
20
|
+
# Also provides alternative view keys for common RESTful actions.
|
|
21
|
+
#
|
|
22
|
+
# @example
|
|
23
|
+
# ViewNameInferrer.call(action_name: "Main::Actions::Posts::Create", slice: Main::Slice)
|
|
24
|
+
# # => ["views.posts.create", "views.posts.new"]
|
|
25
|
+
#
|
|
26
|
+
# @param action_name [String] action class name
|
|
27
|
+
# @param slice [Hanami::Slice, Hanami::Application] Hanami slice containing the action
|
|
28
|
+
#
|
|
29
|
+
# @return [Array<string>] array of paired view container keys
|
|
30
|
+
def call(action_class_name:, slice:)
|
|
31
|
+
action_key_base = slice.config.actions.name_inference_base
|
|
32
|
+
view_key_base = slice.config.actions.view_name_inference_base
|
|
33
|
+
|
|
34
|
+
action_name_key = action_name_key(action_class_name, slice, action_key_base)
|
|
35
|
+
|
|
36
|
+
view_key = [view_key_base, action_name_key].compact.join(CONTAINER_KEY_DELIMITER)
|
|
37
|
+
|
|
38
|
+
[view_key, alternative_view_key(view_key)].compact
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def action_name_key(action_name, slice, key_base)
|
|
44
|
+
slice
|
|
45
|
+
.inflector
|
|
46
|
+
.underscore(action_name)
|
|
47
|
+
.sub(%r{^#{slice.slice_name.path}#{PATH_DELIMITER}}, "")
|
|
48
|
+
.sub(%r{^#{key_base}#{PATH_DELIMITER}}, "")
|
|
49
|
+
.gsub("/", CONTAINER_KEY_DELIMITER)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def alternative_view_key(view_key)
|
|
53
|
+
parts = view_key.split(CONTAINER_KEY_DELIMITER)
|
|
54
|
+
|
|
55
|
+
alternative_name = ALTERNATIVE_NAMES[parts.last]
|
|
56
|
+
return unless alternative_name
|
|
57
|
+
|
|
58
|
+
[parts[0..-2], alternative_name].join(CONTAINER_KEY_DELIMITER)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|