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,106 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "hanami/view"
|
|
4
|
+
require "hanami/view/context"
|
|
5
|
+
require_relative "../../errors"
|
|
6
|
+
require_relative "../../slice_configurable"
|
|
7
|
+
require_relative "slice_configured_context"
|
|
8
|
+
|
|
9
|
+
module Hanami
|
|
10
|
+
module Extensions
|
|
11
|
+
module View
|
|
12
|
+
# View context for views in Hanami apps.
|
|
13
|
+
#
|
|
14
|
+
# @api public
|
|
15
|
+
# @since 2.0.0
|
|
16
|
+
module Context
|
|
17
|
+
def self.included(context_class)
|
|
18
|
+
super
|
|
19
|
+
|
|
20
|
+
context_class.extend(Hanami::SliceConfigurable)
|
|
21
|
+
context_class.extend(ClassMethods)
|
|
22
|
+
context_class.prepend(InstanceMethods)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
module ClassMethods
|
|
26
|
+
def configure_for_slice(slice)
|
|
27
|
+
extend SliceConfiguredContext.new(slice)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
module InstanceMethods
|
|
32
|
+
# @see SliceConfiguredContext#define_new
|
|
33
|
+
def initialize(**kwargs)
|
|
34
|
+
defaults = {content: {}}
|
|
35
|
+
|
|
36
|
+
super(**kwargs, **defaults)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def inflector
|
|
40
|
+
_options.fetch(:inflector)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def routes
|
|
44
|
+
_options.fetch(:routes)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def settings
|
|
48
|
+
_options.fetch(:settings)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def assets
|
|
52
|
+
unless _options[:assets]
|
|
53
|
+
raise Hanami::ComponentLoadError, "hanami-assets gem is required to access assets"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
_options[:assets]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def content_for(key, value = nil, &block)
|
|
60
|
+
content = _options[:content]
|
|
61
|
+
output = nil
|
|
62
|
+
|
|
63
|
+
if block
|
|
64
|
+
content[key] = yield
|
|
65
|
+
elsif value
|
|
66
|
+
content[key] = value
|
|
67
|
+
else
|
|
68
|
+
output = content[key]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
output
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def current_path
|
|
75
|
+
request.fullpath
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def csrf_token
|
|
79
|
+
request.session[Hanami::Action::CSRFProtection::CSRF_TOKEN]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def request
|
|
83
|
+
_options.fetch(:request)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def session
|
|
87
|
+
request.session
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def flash
|
|
91
|
+
response.flash
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
|
|
96
|
+
# TODO: create `Request#flash` so we no longer need the `response`
|
|
97
|
+
def response
|
|
98
|
+
_options.fetch(:response)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
Hanami::View::Context.include(Hanami::Extensions::View::Context)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "hanami/view"
|
|
4
|
+
|
|
5
|
+
module Hanami
|
|
6
|
+
module Extensions
|
|
7
|
+
module View
|
|
8
|
+
# Provides slice-specific configuration and behavior for any view context class
|
|
9
|
+
# defined within a slice's module namespace.
|
|
10
|
+
#
|
|
11
|
+
# @api private
|
|
12
|
+
# @since 2.0.0
|
|
13
|
+
class SliceConfiguredContext < Module
|
|
14
|
+
attr_reader :slice
|
|
15
|
+
|
|
16
|
+
def initialize(slice)
|
|
17
|
+
super()
|
|
18
|
+
@slice = slice
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def extended(_context_class)
|
|
22
|
+
define_new
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def inspect
|
|
26
|
+
"#<#{self.class.name}[#{slice.name}]>"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
# Defines a {.new} method on the context class that resolves key components from
|
|
32
|
+
# the app container and provides them to {#initialize} as injected
|
|
33
|
+
# dependencies.
|
|
34
|
+
#
|
|
35
|
+
# This includes the following app components:
|
|
36
|
+
#
|
|
37
|
+
# - the configured inflector as `inflector`
|
|
38
|
+
# - "settings" from the app container as `settings`
|
|
39
|
+
# - "routes" from the app container as `routes`
|
|
40
|
+
# - "assets" from the app container as `assets`
|
|
41
|
+
def define_new
|
|
42
|
+
inflector = slice.inflector
|
|
43
|
+
resolve_settings = method(:resolve_settings)
|
|
44
|
+
resolve_routes = method(:resolve_routes)
|
|
45
|
+
resolve_assets = method(:resolve_assets)
|
|
46
|
+
|
|
47
|
+
define_method :new do |**kwargs|
|
|
48
|
+
kwargs[:inflector] ||= inflector
|
|
49
|
+
kwargs[:settings] ||= resolve_settings.()
|
|
50
|
+
kwargs[:routes] ||= resolve_routes.()
|
|
51
|
+
kwargs[:assets] ||= resolve_assets.()
|
|
52
|
+
|
|
53
|
+
super(**kwargs)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def resolve_settings
|
|
58
|
+
slice["settings"] if slice.key?("settings")
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def resolve_routes
|
|
62
|
+
slice["routes"] if slice.key?("routes")
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def resolve_assets
|
|
66
|
+
slice["assets"] if slice.key?("assets")
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "hanami/view"
|
|
4
|
+
|
|
5
|
+
module Hanami
|
|
6
|
+
module Extensions
|
|
7
|
+
module View
|
|
8
|
+
# Provides slice-specific configuration and behavior for any view class defined
|
|
9
|
+
# within a slice's module namespace.
|
|
10
|
+
#
|
|
11
|
+
# @api private
|
|
12
|
+
# @since 2.0.0
|
|
13
|
+
class SliceConfiguredView < Module
|
|
14
|
+
attr_reader :slice
|
|
15
|
+
|
|
16
|
+
def initialize(slice)
|
|
17
|
+
super()
|
|
18
|
+
@slice = slice
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def extended(view_class)
|
|
22
|
+
configure_view(view_class)
|
|
23
|
+
define_inherited
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def inspect
|
|
27
|
+
"#<#{self.class.name}[#{slice.name}]>"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
# rubocop:disable Metrics/AbcSize
|
|
33
|
+
def configure_view(view_class)
|
|
34
|
+
view_class.settings.each do |setting|
|
|
35
|
+
if slice.config.views.respond_to?(:"#{setting}")
|
|
36
|
+
view_class.config.public_send(
|
|
37
|
+
:"#{setting}=",
|
|
38
|
+
slice.config.views.public_send(:"#{setting}")
|
|
39
|
+
)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
view_class.config.inflector = inflector
|
|
44
|
+
view_class.config.paths = prepare_paths(slice, view_class.config.paths)
|
|
45
|
+
view_class.config.template = template_name(view_class)
|
|
46
|
+
|
|
47
|
+
if (part_namespace = namespace_from_path(slice.config.views.parts_path))
|
|
48
|
+
view_class.config.part_namespace = part_namespace
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
# rubocop:enable Metrics/AbcSize
|
|
52
|
+
|
|
53
|
+
def define_inherited
|
|
54
|
+
template_name = method(:template_name)
|
|
55
|
+
|
|
56
|
+
define_method(:inherited) do |subclass|
|
|
57
|
+
super(subclass)
|
|
58
|
+
subclass.config.template = template_name.(subclass)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def prepare_paths(slice, configured_paths)
|
|
63
|
+
configured_paths.map { |path|
|
|
64
|
+
if path.dir.relative?
|
|
65
|
+
if slice.app.equal?(slice)
|
|
66
|
+
# App-level templates are in app/
|
|
67
|
+
slice.root.join(APP_DIR, path.dir)
|
|
68
|
+
else
|
|
69
|
+
# Other slice templates are in the root slice dir
|
|
70
|
+
slice.root.join(path.dir)
|
|
71
|
+
end
|
|
72
|
+
else
|
|
73
|
+
path
|
|
74
|
+
end
|
|
75
|
+
}
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def namespace_from_path(path)
|
|
79
|
+
path = "#{slice.slice_name.path}/#{path}"
|
|
80
|
+
|
|
81
|
+
begin
|
|
82
|
+
require path
|
|
83
|
+
rescue LoadError => exception
|
|
84
|
+
raise exception unless exception.path == path
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
begin
|
|
88
|
+
inflector.constantize(inflector.camelize(path))
|
|
89
|
+
rescue NameError => exception
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def template_name(view_class)
|
|
94
|
+
slice
|
|
95
|
+
.inflector
|
|
96
|
+
.underscore(view_class.name)
|
|
97
|
+
.sub(/^#{slice.slice_name.path}\//, "")
|
|
98
|
+
.sub(/^#{view_class.config.template_inference_base}\//, "")
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def inflector
|
|
102
|
+
slice.inflector
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "hanami/view"
|
|
4
|
+
require_relative "../slice_configurable"
|
|
5
|
+
require_relative "view/slice_configured_view"
|
|
6
|
+
|
|
7
|
+
module Hanami
|
|
8
|
+
module Extensions
|
|
9
|
+
# Extended behavior for actions intended for use within an Hanami app.
|
|
10
|
+
#
|
|
11
|
+
# @see Hanami::View
|
|
12
|
+
#
|
|
13
|
+
# @api public
|
|
14
|
+
# @since 2.0.0
|
|
15
|
+
module View
|
|
16
|
+
def self.included(view_class)
|
|
17
|
+
super
|
|
18
|
+
|
|
19
|
+
view_class.extend(Hanami::SliceConfigurable)
|
|
20
|
+
view_class.extend(ClassMethods)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
module ClassMethods
|
|
24
|
+
# @api private
|
|
25
|
+
def configure_for_slice(slice)
|
|
26
|
+
extend SliceConfiguredView.new(slice)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
Hanami::View.include(Hanami::Extensions::View)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dry/system/provider/source"
|
|
4
|
+
|
|
5
|
+
module Hanami
|
|
6
|
+
module Providers
|
|
7
|
+
class Logger < Dry::System::Provider::Source
|
|
8
|
+
def start
|
|
9
|
+
register :logger, Hanami.app.configuration.logger_instance
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dry/system/provider/source"
|
|
4
|
+
|
|
5
|
+
module Hanami
|
|
6
|
+
module Providers
|
|
7
|
+
class Rack < Dry::System::Provider::Source
|
|
8
|
+
def prepare
|
|
9
|
+
require "dry/monitor"
|
|
10
|
+
require "hanami/web/rack_logger"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def start
|
|
14
|
+
target.start :logger
|
|
15
|
+
|
|
16
|
+
notifications = target[:notifications]
|
|
17
|
+
|
|
18
|
+
monitor_middleware = Dry::Monitor::Rack::Middleware.new(notifications)
|
|
19
|
+
|
|
20
|
+
rack_logger = Hanami::Web::RackLogger.new(target[:logger])
|
|
21
|
+
rack_logger.attach(monitor_middleware)
|
|
22
|
+
|
|
23
|
+
register "monitor", monitor_middleware
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dry/system/provider/source"
|
|
4
|
+
|
|
5
|
+
module Hanami
|
|
6
|
+
module Providers
|
|
7
|
+
class Routes < Dry::System::Provider::Source
|
|
8
|
+
def self.for_slice(slice)
|
|
9
|
+
Class.new(self) do |klass|
|
|
10
|
+
klass.instance_variable_set(:@slice, slice)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.slice
|
|
15
|
+
@slice || Hanami.app
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def prepare
|
|
19
|
+
require "hanami/slice/routes_helper"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def start
|
|
23
|
+
# Register a lazy instance of RoutesHelper to ensure we don't load prematurely
|
|
24
|
+
# load the router during the process of booting. This ensures the router's
|
|
25
|
+
# resolver can run strict action key checks once when it runs on a fully booted
|
|
26
|
+
# slice.
|
|
27
|
+
register :routes do
|
|
28
|
+
Hanami::Slice::RoutesHelper.new(self.class.slice.router)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dry/system/provider/source"
|
|
4
|
+
|
|
5
|
+
module Hanami
|
|
6
|
+
module Providers
|
|
7
|
+
class Settings < Dry::System::Provider::Source
|
|
8
|
+
def self.for_slice(slice)
|
|
9
|
+
Class.new(self) do |klass|
|
|
10
|
+
klass.instance_variable_set(:@slice, slice)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.slice
|
|
15
|
+
@slice || Hanami.app
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def start
|
|
19
|
+
register :settings, self.class.slice.settings
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "hanami/cli/rake_tasks"
|
|
4
|
+
require "hanami/cli/command_line"
|
|
5
|
+
|
|
6
|
+
Hanami::CLI::RakeTasks.register_tasks do
|
|
7
|
+
@_hanami_command_line = Hanami::CLI::CommandLine.new
|
|
8
|
+
|
|
9
|
+
desc "Load the app environment"
|
|
10
|
+
task :environment do
|
|
11
|
+
require "hanami/prepare"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Ruby ecosystem compatibility
|
|
15
|
+
#
|
|
16
|
+
# Most of the SaaS automatic tasks are designed after Ruby on Rails.
|
|
17
|
+
# They expect the following Rake tasks to be present:
|
|
18
|
+
#
|
|
19
|
+
# * db:migrate
|
|
20
|
+
# * assets:precompile
|
|
21
|
+
#
|
|
22
|
+
# See https://github.com/heroku/heroku-buildpack-ruby/issues/442
|
|
23
|
+
#
|
|
24
|
+
# ===
|
|
25
|
+
#
|
|
26
|
+
# These Rake tasks aren't listed when someone runs `rake -T`, because we
|
|
27
|
+
# want to encourage developers to use `hanami` commands.
|
|
28
|
+
#
|
|
29
|
+
# In order to migrate the database or precompile assets a developer should
|
|
30
|
+
# use:
|
|
31
|
+
#
|
|
32
|
+
# * hanami db migrate
|
|
33
|
+
# * hanami assets precompile
|
|
34
|
+
#
|
|
35
|
+
# This is the preferred way to run Hanami command line tasks.
|
|
36
|
+
# Please use them when you're in control of your deployment environment.
|
|
37
|
+
#
|
|
38
|
+
# If you're not in control and your deployment requires these "standard"
|
|
39
|
+
# Rake tasks, they are here to solve this only specific problem.
|
|
40
|
+
namespace :db do
|
|
41
|
+
task :migrate do
|
|
42
|
+
# TODO(@jodosha): Enable when we'll integrate with ROM
|
|
43
|
+
# run_hanami_command("db migrate")
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
namespace :assets do
|
|
48
|
+
task :precompile do
|
|
49
|
+
# TODO(@jodosha): Enable when we'll integrate with hanami-assets
|
|
50
|
+
# run_hanami_command("assets precompile")
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def run_hanami_command(command)
|
|
57
|
+
@_hanami_command_line.call(command)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
Hanami::CLI::RakeTasks.install_tasks
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hanami
|
|
4
|
+
# App routes
|
|
5
|
+
#
|
|
6
|
+
# Users are expected to inherit from this class to define their app
|
|
7
|
+
# routes.
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
# # config/routes.rb
|
|
11
|
+
# # frozen_string_literal: true
|
|
12
|
+
#
|
|
13
|
+
# require "hanami/routes"
|
|
14
|
+
#
|
|
15
|
+
# module MyApp
|
|
16
|
+
# class Routes < Hanami::Routes
|
|
17
|
+
# define do
|
|
18
|
+
# root to: "home.show"
|
|
19
|
+
# end
|
|
20
|
+
# end
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# See {Hanami::Slice::Router} for the syntax allowed within the
|
|
24
|
+
# `define` block.
|
|
25
|
+
#
|
|
26
|
+
# @see Hanami::Slice::Router
|
|
27
|
+
# @since 2.0.0
|
|
28
|
+
class Routes
|
|
29
|
+
# Defines app routes
|
|
30
|
+
#
|
|
31
|
+
# @yield DSL syntax to define app routes executed in the context
|
|
32
|
+
# of {Hanami::Slice::Router}
|
|
33
|
+
#
|
|
34
|
+
# @return [Proc]
|
|
35
|
+
def self.define(&block)
|
|
36
|
+
@_routes = block
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @api private
|
|
40
|
+
def self.routes
|
|
41
|
+
@_routes || raise(<<~MSG)
|
|
42
|
+
Routes need to be defined before being able to fetch them. E.g.,
|
|
43
|
+
define do
|
|
44
|
+
slice :main, at: "/" do
|
|
45
|
+
root to: "home.show"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
MSG
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
data/lib/hanami/server.rb
CHANGED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dry/core/constants"
|
|
4
|
+
|
|
5
|
+
module Hanami
|
|
6
|
+
class Settings
|
|
7
|
+
# Default app settings store.
|
|
8
|
+
#
|
|
9
|
+
# Uses [dotenv](https://github.com/bkeepers/dotenv) (if available) to load
|
|
10
|
+
# .env files and then loads settings from ENV. For a given `HANAMI_ENV`
|
|
11
|
+
# environment, the following `.env` files are looked up in the following order:
|
|
12
|
+
#
|
|
13
|
+
# - .env.{environment}.local
|
|
14
|
+
# - .env.local (except if the environment is `test`)
|
|
15
|
+
# - .env.{environment}
|
|
16
|
+
# - .env
|
|
17
|
+
#
|
|
18
|
+
# @since 2.0.0
|
|
19
|
+
# @api private
|
|
20
|
+
class DotenvStore
|
|
21
|
+
Undefined = Dry::Core::Constants::Undefined
|
|
22
|
+
|
|
23
|
+
attr_reader :store,
|
|
24
|
+
:hanami_env
|
|
25
|
+
|
|
26
|
+
def initialize(store: ENV, hanami_env: Hanami.env)
|
|
27
|
+
@store = store
|
|
28
|
+
@hanami_env = hanami_env
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def fetch(name, default_value = Undefined, &block)
|
|
32
|
+
name = name.to_s.upcase
|
|
33
|
+
args = (default_value == Undefined) ? [name] : [name, default_value]
|
|
34
|
+
|
|
35
|
+
store.fetch(*args, &block)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def with_dotenv_loaded
|
|
39
|
+
require "dotenv"
|
|
40
|
+
Dotenv.load(*dotenv_files) if defined?(Dotenv)
|
|
41
|
+
self
|
|
42
|
+
rescue LoadError
|
|
43
|
+
self
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def dotenv_files
|
|
49
|
+
[
|
|
50
|
+
".env.#{hanami_env}.local",
|
|
51
|
+
(".env.local" unless hanami_env == :test),
|
|
52
|
+
".env.#{hanami_env}",
|
|
53
|
+
".env"
|
|
54
|
+
].compact
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|