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,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dry/configurable"
|
|
4
|
+
require "hanami/view"
|
|
5
|
+
|
|
6
|
+
module Hanami
|
|
7
|
+
class Configuration
|
|
8
|
+
# Hanami actions configuration
|
|
9
|
+
#
|
|
10
|
+
# @since 2.0.0
|
|
11
|
+
class Views
|
|
12
|
+
include Dry::Configurable
|
|
13
|
+
|
|
14
|
+
setting :parts_path, default: "views/parts"
|
|
15
|
+
|
|
16
|
+
attr_reader :base_configuration
|
|
17
|
+
protected :base_configuration
|
|
18
|
+
|
|
19
|
+
def initialize(*)
|
|
20
|
+
super
|
|
21
|
+
|
|
22
|
+
@base_configuration = Hanami::View.config.dup
|
|
23
|
+
|
|
24
|
+
configure_defaults
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def initialize_copy(source)
|
|
28
|
+
super
|
|
29
|
+
@base_configuration = source.base_configuration.dup
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Returns the list of available settings
|
|
33
|
+
#
|
|
34
|
+
# @return [Set]
|
|
35
|
+
#
|
|
36
|
+
# @since 2.0.0
|
|
37
|
+
# @api private
|
|
38
|
+
def settings
|
|
39
|
+
self.class.settings + View.settings - NON_FORWARDABLE_METHODS
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def finalize!
|
|
43
|
+
return self if frozen?
|
|
44
|
+
|
|
45
|
+
base_configuration.finalize!
|
|
46
|
+
|
|
47
|
+
super
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def configure_defaults
|
|
53
|
+
self.paths = ["templates"]
|
|
54
|
+
self.template_inference_base = "views"
|
|
55
|
+
self.layout = "app"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# An inflector for views is not configurable via `config.views.inflector` on an
|
|
59
|
+
# `Hanami::App`. The app-wide inflector is already configurable
|
|
60
|
+
# there as `config.inflector` and will be used as the default inflector for views.
|
|
61
|
+
#
|
|
62
|
+
# A custom inflector may still be provided in an `Hanami::View` subclass, via
|
|
63
|
+
# `config.inflector=`.
|
|
64
|
+
NON_FORWARDABLE_METHODS = %i[inflector inflector=].freeze
|
|
65
|
+
private_constant :NON_FORWARDABLE_METHODS
|
|
66
|
+
|
|
67
|
+
def method_missing(name, *args, &block)
|
|
68
|
+
return super if NON_FORWARDABLE_METHODS.include?(name)
|
|
69
|
+
|
|
70
|
+
if config.respond_to?(name)
|
|
71
|
+
config.public_send(name, *args, &block)
|
|
72
|
+
elsif base_configuration.respond_to?(name)
|
|
73
|
+
base_configuration.public_send(name, *args, &block)
|
|
74
|
+
else
|
|
75
|
+
super
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def respond_to_missing?(name, _include_all = false)
|
|
80
|
+
return false if NON_FORWARDABLE_METHODS.include?(name)
|
|
81
|
+
|
|
82
|
+
config.respond_to?(name) || base_configuration.respond_to?(name) || super
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
data/lib/hanami/configuration.rb
CHANGED
|
@@ -7,88 +7,134 @@ require "dry/configurable"
|
|
|
7
7
|
require "dry/inflector"
|
|
8
8
|
require "pathname"
|
|
9
9
|
|
|
10
|
-
require_relative "
|
|
10
|
+
require_relative "constants"
|
|
11
11
|
require_relative "configuration/logger"
|
|
12
|
-
require_relative "configuration/middleware"
|
|
13
12
|
require_relative "configuration/router"
|
|
14
13
|
require_relative "configuration/sessions"
|
|
15
|
-
require_relative "
|
|
16
|
-
require_relative "
|
|
14
|
+
require_relative "settings/dotenv_store"
|
|
15
|
+
require_relative "slice/routing/middleware/stack"
|
|
17
16
|
|
|
18
17
|
module Hanami
|
|
19
|
-
# Hanami
|
|
18
|
+
# Hanami app configuration
|
|
20
19
|
#
|
|
21
20
|
# @since 2.0.0
|
|
22
|
-
#
|
|
23
|
-
# rubocop:disable Metrics/ClassLength
|
|
24
21
|
class Configuration
|
|
25
22
|
include Dry::Configurable
|
|
26
23
|
|
|
24
|
+
setting :root, constructor: ->(path) { Pathname(path) if path }
|
|
25
|
+
|
|
26
|
+
setting :no_auto_register_paths, default: %w[entities]
|
|
27
|
+
|
|
28
|
+
setting :inflector, default: Dry::Inflector.new
|
|
29
|
+
|
|
30
|
+
setting :settings_store, default: Hanami::Settings::DotenvStore
|
|
31
|
+
|
|
32
|
+
setting :slices do
|
|
33
|
+
setting :shared_component_keys, default: %w[
|
|
34
|
+
inflector
|
|
35
|
+
logger
|
|
36
|
+
notifications
|
|
37
|
+
rack.monitor
|
|
38
|
+
routes
|
|
39
|
+
settings
|
|
40
|
+
]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
setting :base_url, default: "http://0.0.0.0:2300", constructor: ->(url) { URI(url) }
|
|
44
|
+
|
|
45
|
+
setting :sessions, default: :null, constructor: ->(*args) { Sessions.new(*args) }
|
|
46
|
+
|
|
47
|
+
setting :logger, cloneable: true
|
|
48
|
+
|
|
27
49
|
DEFAULT_ENVIRONMENTS = Concurrent::Hash.new { |h, k| h[k] = Concurrent::Array.new }
|
|
28
50
|
private_constant :DEFAULT_ENVIRONMENTS
|
|
29
51
|
|
|
52
|
+
# @return [Symbol] The name of the application
|
|
53
|
+
#
|
|
54
|
+
# @api public
|
|
55
|
+
attr_reader :app_name
|
|
56
|
+
|
|
57
|
+
# @return [String] The current environment
|
|
58
|
+
#
|
|
59
|
+
# @api public
|
|
30
60
|
attr_reader :env
|
|
31
61
|
|
|
62
|
+
# @return [Hanami::Configuration::Actions]
|
|
63
|
+
#
|
|
64
|
+
# @api public
|
|
32
65
|
attr_reader :actions
|
|
66
|
+
|
|
67
|
+
# @return [Hanami::Slice::Routing::Middleware::Stack]
|
|
68
|
+
#
|
|
69
|
+
# @api public
|
|
33
70
|
attr_reader :middleware
|
|
71
|
+
|
|
72
|
+
# @api private
|
|
73
|
+
alias_method :middleware_stack, :middleware
|
|
74
|
+
|
|
75
|
+
# @return [Hanami::Configuration::Router]
|
|
76
|
+
#
|
|
77
|
+
# @api public
|
|
34
78
|
attr_reader :router
|
|
35
|
-
attr_reader :views, :assets
|
|
36
79
|
|
|
80
|
+
# @return [Hanami::Configuration::Views]
|
|
81
|
+
#
|
|
82
|
+
# @api public
|
|
83
|
+
attr_reader :views
|
|
84
|
+
|
|
85
|
+
# @return [Hanami::Assets::AppConfiguration]
|
|
86
|
+
#
|
|
87
|
+
# @api public
|
|
88
|
+
attr_reader :assets
|
|
89
|
+
|
|
90
|
+
# @return [Concurrent::Hash] A hash of default environments
|
|
91
|
+
#
|
|
92
|
+
# @api private
|
|
37
93
|
attr_reader :environments
|
|
38
94
|
private :environments
|
|
39
95
|
|
|
40
|
-
|
|
41
|
-
|
|
96
|
+
# @api private
|
|
97
|
+
def initialize(app_name:, env:)
|
|
98
|
+
@app_name = app_name
|
|
42
99
|
|
|
43
100
|
@environments = DEFAULT_ENVIRONMENTS.clone
|
|
44
101
|
@env = env
|
|
45
102
|
|
|
46
103
|
# Some default setting values must be assigned at initialize-time to ensure they
|
|
47
|
-
# have appropriate values for the current
|
|
104
|
+
# have appropriate values for the current app
|
|
48
105
|
self.root = Dir.pwd
|
|
49
|
-
self.settings_store =
|
|
50
|
-
|
|
51
|
-
config.logger = Configuration::Logger.new(env: env, application_name: method(:application_name))
|
|
52
|
-
|
|
53
|
-
@assets = begin
|
|
54
|
-
require_path = "hanami/assets/application_configuration"
|
|
55
|
-
require require_path
|
|
56
|
-
Hanami::Assets::ApplicationConfiguration.new
|
|
57
|
-
rescue LoadError => e
|
|
58
|
-
raise e unless e.path == require_path
|
|
59
|
-
require_relative "configuration/null_configuration"
|
|
60
|
-
NullConfiguration.new
|
|
61
|
-
end
|
|
106
|
+
self.settings_store = Hanami::Settings::DotenvStore.new.with_dotenv_loaded
|
|
62
107
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
@
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
end
|
|
108
|
+
config.logger = Configuration::Logger.new(env: env, app_name: app_name)
|
|
109
|
+
|
|
110
|
+
@assets = load_dependent_config("hanami/assets/app_configuration") {
|
|
111
|
+
Hanami::Assets::AppConfiguration.new
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@actions = load_dependent_config("hanami/action") {
|
|
115
|
+
require_relative "configuration/actions"
|
|
116
|
+
Actions.new
|
|
117
|
+
}
|
|
74
118
|
|
|
75
|
-
@middleware = Middleware.new
|
|
119
|
+
@middleware = Slice::Routing::Middleware::Stack.new
|
|
76
120
|
|
|
77
121
|
@router = Router.new(self)
|
|
78
122
|
|
|
79
|
-
@views =
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
rescue LoadError => e
|
|
84
|
-
raise e unless e.path == require_path
|
|
85
|
-
require_relative "configuration/null_configuration"
|
|
86
|
-
NullConfiguration.new
|
|
87
|
-
end
|
|
123
|
+
@views = load_dependent_config("hanami/view") {
|
|
124
|
+
require_relative "configuration/views"
|
|
125
|
+
Views.new
|
|
126
|
+
}
|
|
88
127
|
|
|
89
128
|
yield self if block_given?
|
|
90
129
|
end
|
|
91
130
|
|
|
131
|
+
# Apply configuration for the given environment
|
|
132
|
+
#
|
|
133
|
+
# @param env [String] the environment name
|
|
134
|
+
#
|
|
135
|
+
# @return [Hanami::Configuration]
|
|
136
|
+
#
|
|
137
|
+
# @api public
|
|
92
138
|
def environment(env_name, &block)
|
|
93
139
|
environments[env_name] << block
|
|
94
140
|
apply_env_config
|
|
@@ -96,6 +142,34 @@ module Hanami
|
|
|
96
142
|
self
|
|
97
143
|
end
|
|
98
144
|
|
|
145
|
+
# Configure application's inflections
|
|
146
|
+
#
|
|
147
|
+
# @see https://dry-rb.org/gems/dry-inflector
|
|
148
|
+
#
|
|
149
|
+
# @return [Dry::Inflector]
|
|
150
|
+
#
|
|
151
|
+
# @api public
|
|
152
|
+
def inflections(&block)
|
|
153
|
+
self.inflector = Dry::Inflector.new(&block)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# @api private
|
|
157
|
+
def initialize_copy(source)
|
|
158
|
+
super
|
|
159
|
+
|
|
160
|
+
@app_name = app_name.dup
|
|
161
|
+
@environments = environments.dup
|
|
162
|
+
|
|
163
|
+
@assets = source.assets.dup
|
|
164
|
+
@actions = source.actions.dup
|
|
165
|
+
@middleware = source.middleware.dup
|
|
166
|
+
@router = source.router.dup.tap do |router|
|
|
167
|
+
router.instance_variable_set(:@base_configuration, self)
|
|
168
|
+
end
|
|
169
|
+
@views = source.views.dup
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# @api private
|
|
99
173
|
def finalize!
|
|
100
174
|
apply_env_config
|
|
101
175
|
|
|
@@ -109,59 +183,41 @@ module Hanami
|
|
|
109
183
|
super
|
|
110
184
|
end
|
|
111
185
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
def application_name
|
|
117
|
-
inflector.underscore(@namespace).to_sym
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
setting :root, constructor: -> path { Pathname(path) }
|
|
121
|
-
|
|
122
|
-
setting :inflector, default: Dry::Inflector.new
|
|
123
|
-
|
|
124
|
-
def inflections(&block)
|
|
125
|
-
self.inflector = Dry::Inflector.new(&block)
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
setting :logger, cloneable: true
|
|
129
|
-
|
|
186
|
+
# Set a default global logger instance
|
|
187
|
+
#
|
|
188
|
+
# @api public
|
|
130
189
|
def logger=(logger_instance)
|
|
131
190
|
@logger_instance = logger_instance
|
|
132
191
|
end
|
|
133
192
|
|
|
193
|
+
# Return configured logger instance
|
|
194
|
+
#
|
|
195
|
+
# @api public
|
|
134
196
|
def logger_instance
|
|
135
197
|
@logger_instance || logger.instance
|
|
136
198
|
end
|
|
137
199
|
|
|
138
|
-
setting :settings_path, default: File.join("config", "settings")
|
|
139
|
-
|
|
140
|
-
setting :settings_class_name, default: "Settings"
|
|
141
|
-
|
|
142
|
-
setting :settings_store, default: Application::Settings::DotenvStore
|
|
143
|
-
|
|
144
|
-
setting :source_dirs, default: Configuration::SourceDirs.new, cloneable: true
|
|
145
|
-
|
|
146
|
-
setting :base_url, default: "http://0.0.0.0:2300", constructor: -> url { URI(url) }
|
|
147
|
-
|
|
148
|
-
def for_each_middleware(&blk)
|
|
149
|
-
stack = middleware.stack.dup
|
|
150
|
-
stack += sessions.middleware if sessions.enabled?
|
|
151
|
-
|
|
152
|
-
stack.each(&blk)
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
setting :sessions, default: :null, constructor: -> *args { Sessions.new(*args) }
|
|
156
|
-
|
|
157
200
|
private
|
|
158
201
|
|
|
202
|
+
# @api private
|
|
159
203
|
def apply_env_config(env = self.env)
|
|
160
204
|
environments[env].each do |block|
|
|
161
205
|
instance_eval(&block)
|
|
162
206
|
end
|
|
163
207
|
end
|
|
164
208
|
|
|
209
|
+
# @api private
|
|
210
|
+
def load_dependent_config(require_path, &block)
|
|
211
|
+
require require_path
|
|
212
|
+
yield
|
|
213
|
+
rescue LoadError => e
|
|
214
|
+
raise e unless e.path == require_path
|
|
215
|
+
|
|
216
|
+
require_relative "configuration/null_configuration"
|
|
217
|
+
NullConfiguration.new
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# @api private
|
|
165
221
|
def method_missing(name, *args, &block)
|
|
166
222
|
if config.respond_to?(name)
|
|
167
223
|
config.public_send(name, *args, &block)
|
|
@@ -170,6 +226,7 @@ module Hanami
|
|
|
170
226
|
end
|
|
171
227
|
end
|
|
172
228
|
|
|
229
|
+
# @api private
|
|
173
230
|
def respond_to_missing?(name, _incude_all = false)
|
|
174
231
|
config.respond_to?(name) || super
|
|
175
232
|
end
|
data/lib/hanami/constants.rb
CHANGED
|
@@ -1,22 +1,50 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Hanami
|
|
4
|
+
# @api private
|
|
5
|
+
CONTAINER_KEY_DELIMITER = "."
|
|
6
|
+
private_constant :CONTAINER_KEY_DELIMITER
|
|
7
|
+
|
|
4
8
|
# @api private
|
|
5
9
|
MODULE_DELIMITER = "::"
|
|
6
10
|
private_constant :MODULE_DELIMITER
|
|
7
11
|
|
|
12
|
+
# @api private
|
|
13
|
+
PATH_DELIMITER = "/"
|
|
14
|
+
private_constant :PATH_DELIMITER
|
|
15
|
+
|
|
8
16
|
# @api private
|
|
9
17
|
CONFIG_DIR = "config"
|
|
10
18
|
private_constant :CONFIG_DIR
|
|
11
19
|
|
|
12
20
|
# @api private
|
|
13
|
-
|
|
14
|
-
private_constant :
|
|
21
|
+
APP_DIR = "app"
|
|
22
|
+
private_constant :APP_DIR
|
|
15
23
|
|
|
16
24
|
# @api private
|
|
17
25
|
LIB_DIR = "lib"
|
|
18
26
|
private_constant :LIB_DIR
|
|
19
27
|
|
|
28
|
+
# @api private
|
|
29
|
+
SLICES_DIR = "slices"
|
|
30
|
+
private_constant :SLICES_DIR
|
|
31
|
+
|
|
32
|
+
# @api private
|
|
33
|
+
ROUTES_PATH = File.join(CONFIG_DIR, "routes")
|
|
34
|
+
private_constant :ROUTES_PATH
|
|
35
|
+
|
|
36
|
+
# @api private
|
|
37
|
+
ROUTES_CLASS_NAME = "Routes"
|
|
38
|
+
private_constant :ROUTES_CLASS_NAME
|
|
39
|
+
|
|
40
|
+
# @api private
|
|
41
|
+
SETTINGS_PATH = File.join(CONFIG_DIR, "settings")
|
|
42
|
+
private_constant :SETTINGS_PATH
|
|
43
|
+
|
|
44
|
+
# @api private
|
|
45
|
+
SETTINGS_CLASS_NAME = "Settings"
|
|
46
|
+
private_constant :SETTINGS_CLASS_NAME
|
|
47
|
+
|
|
20
48
|
# @api private
|
|
21
49
|
RB_EXT = ".rb"
|
|
22
50
|
private_constant :RB_EXT
|
data/lib/hanami/errors.rb
CHANGED
|
@@ -5,8 +5,11 @@ module Hanami
|
|
|
5
5
|
Error = Class.new(StandardError)
|
|
6
6
|
|
|
7
7
|
# @since 2.0.0
|
|
8
|
-
|
|
8
|
+
AppLoadError = Class.new(Error)
|
|
9
9
|
|
|
10
10
|
# @since 2.0.0
|
|
11
11
|
SliceLoadError = Class.new(Error)
|
|
12
|
+
|
|
13
|
+
# @since 2.0.0
|
|
14
|
+
ComponentLoadError = Class.new(Error)
|
|
12
15
|
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "hanami/action"
|
|
4
|
+
|
|
5
|
+
module Hanami
|
|
6
|
+
module Extensions
|
|
7
|
+
module Action
|
|
8
|
+
# Provides slice-specific configuration and behavior for any action class defined
|
|
9
|
+
# within a slice's module namespace.
|
|
10
|
+
#
|
|
11
|
+
# @api private
|
|
12
|
+
# @since 2.0.0
|
|
13
|
+
class SliceConfiguredAction < Module
|
|
14
|
+
attr_reader :slice
|
|
15
|
+
|
|
16
|
+
def initialize(slice)
|
|
17
|
+
super()
|
|
18
|
+
@slice = slice
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def extended(action_class)
|
|
22
|
+
configure_action(action_class)
|
|
23
|
+
extend_behavior(action_class)
|
|
24
|
+
define_new
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def inspect
|
|
28
|
+
"#<#{self.class.name}[#{slice.name}]>"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
# @see Hanami::Extensions::Action::InstanceMethods#initialize
|
|
34
|
+
def define_new
|
|
35
|
+
resolve_view = method(:resolve_paired_view)
|
|
36
|
+
resolve_view_context = method(:resolve_view_context)
|
|
37
|
+
resolve_routes = method(:resolve_routes)
|
|
38
|
+
|
|
39
|
+
define_method(:new) do |**kwargs|
|
|
40
|
+
super(
|
|
41
|
+
view: kwargs.fetch(:view) { resolve_view.(self) },
|
|
42
|
+
view_context: kwargs.fetch(:view_context) { resolve_view_context.() },
|
|
43
|
+
routes: kwargs.fetch(:routes) { resolve_routes.() },
|
|
44
|
+
**kwargs,
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def configure_action(action_class)
|
|
50
|
+
action_class.config.settings.each do |setting|
|
|
51
|
+
action_class.config.public_send :"#{setting}=", actions_config.public_send(:"#{setting}")
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def extend_behavior(action_class)
|
|
56
|
+
if actions_config.sessions.enabled?
|
|
57
|
+
require "hanami/action/session"
|
|
58
|
+
action_class.include Hanami::Action::Session
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
if actions_config.csrf_protection
|
|
62
|
+
require "hanami/action/csrf_protection"
|
|
63
|
+
action_class.include Hanami::Action::CSRFProtection
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
if actions_config.cookies.enabled?
|
|
67
|
+
require "hanami/action/cookies"
|
|
68
|
+
action_class.include Hanami::Action::Cookies
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def resolve_paired_view(action_class)
|
|
73
|
+
view_identifiers = actions_config.view_name_inferrer.call(
|
|
74
|
+
action_class_name: action_class.name,
|
|
75
|
+
slice: slice,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
view_identifiers.detect do |identifier|
|
|
79
|
+
break slice[identifier] if slice.key?(identifier)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def resolve_view_context
|
|
84
|
+
identifier = actions_config.view_context_identifier
|
|
85
|
+
|
|
86
|
+
if slice.key?(identifier)
|
|
87
|
+
slice[identifier]
|
|
88
|
+
elsif slice.app.key?(identifier)
|
|
89
|
+
slice.app[identifier]
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def resolve_routes
|
|
94
|
+
slice.app["routes"] if slice.app.key?("routes")
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def actions_config
|
|
98
|
+
slice.config.actions
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "hanami/action"
|
|
4
|
+
require_relative "../slice_configurable"
|
|
5
|
+
require_relative "action/slice_configured_action"
|
|
6
|
+
|
|
7
|
+
module Hanami
|
|
8
|
+
module Extensions
|
|
9
|
+
# Extended behavior for actions intended for use within an Hanami app.
|
|
10
|
+
#
|
|
11
|
+
# @see Hanami::Action
|
|
12
|
+
#
|
|
13
|
+
# @api public
|
|
14
|
+
# @since 2.0.0
|
|
15
|
+
module Action
|
|
16
|
+
def self.included(action_class)
|
|
17
|
+
super
|
|
18
|
+
|
|
19
|
+
action_class.extend(Hanami::SliceConfigurable)
|
|
20
|
+
action_class.extend(ClassMethods)
|
|
21
|
+
action_class.prepend(InstanceMethods)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
module ClassMethods
|
|
25
|
+
def configure_for_slice(slice)
|
|
26
|
+
extend SliceConfiguredAction.new(slice)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
module InstanceMethods
|
|
31
|
+
attr_reader :view, :view_context, :routes
|
|
32
|
+
|
|
33
|
+
def initialize(view: nil, view_context: nil, routes: nil, **kwargs)
|
|
34
|
+
@view = view
|
|
35
|
+
@view_context = view_context
|
|
36
|
+
@routes = routes
|
|
37
|
+
|
|
38
|
+
super(**kwargs)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def build_response(**options)
|
|
44
|
+
options = options.merge(view_options: method(:view_options))
|
|
45
|
+
super(**options)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def finish(req, res, halted)
|
|
49
|
+
res.render(view, **req.params) if !halted && auto_render?(res)
|
|
50
|
+
super
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def view_options(req, res)
|
|
54
|
+
{context: view_context&.with(**view_context_options(req, res))}.compact
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def view_context_options(req, res)
|
|
58
|
+
{request: req, response: res}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Returns true if a view should automatically be rendered onto the response body.
|
|
62
|
+
#
|
|
63
|
+
# This may be overridden to enable/disable automatic rendering.
|
|
64
|
+
#
|
|
65
|
+
# @param res [Hanami::Action::Response]
|
|
66
|
+
#
|
|
67
|
+
# @return [Boolean]
|
|
68
|
+
#
|
|
69
|
+
# @since 2.0.0
|
|
70
|
+
# @api public
|
|
71
|
+
def auto_render?(res)
|
|
72
|
+
view && res.body.empty?
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
Hanami::Action.include(Hanami::Extensions::Action)
|