hanami 2.0.0.alpha7.1 → 2.0.0.alpha8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/lib/hanami/application/action/slice_configured_action.rb +103 -0
- data/lib/hanami/application/action.rb +72 -0
- data/lib/hanami/application/view/context.rb +95 -0
- data/lib/hanami/application/view/slice_configured_context.rb +71 -0
- data/lib/hanami/application/view/slice_configured_view.rb +101 -0
- data/lib/hanami/application/view.rb +24 -0
- data/lib/hanami/application/view_name_inferrer.rb +63 -0
- data/lib/hanami/application.rb +22 -48
- 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 +16 -11
- data/lib/hanami/configuration/logger.rb +11 -8
- data/lib/hanami/configuration/views.rb +81 -0
- data/lib/hanami/configuration.rb +25 -40
- data/lib/hanami/constants.rb +6 -0
- data/lib/hanami/errors.rb +3 -0
- data/lib/hanami/slice.rb +11 -14
- data/lib/hanami/slice_configurable.rb +75 -0
- data/lib/hanami/slice_name.rb +111 -0
- data/lib/hanami/version.rb +1 -1
- metadata +16 -4
- data/lib/hanami/boot/source_dirs.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 36c07c10545a327f0eab55e1a23e3a6f1b258dd7c4db890d16155d98a132bb90
|
4
|
+
data.tar.gz: 02a8dbd6f028e198dead1d972aef4a78b04246b3201e2c90f94e2827f4582906
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 938be86da6f4c1d5e797db8f0cc185feb2ac070c4d8ba10f48b6bbe922f8b1fd8b618c9871306a7f3d2d75c34a8fab857949d7f18dd04bb833be092fbb8ced27
|
7
|
+
data.tar.gz: 459f220765e02c024fe4b1a5e17ec7a13bba10e2cb3f1b64dfa059cd351bea4cffcd47be1ca5a1cd8b2c89757f20dbcaaa7e77fbfdacb05c9fc87345974e7ec0
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,21 @@
|
|
1
1
|
# Hanami
|
2
2
|
The web, with simplicity.
|
3
3
|
|
4
|
+
## v2.0.0.alpha8 - 2020-05-19
|
5
|
+
|
6
|
+
## Added
|
7
|
+
- [Tim Riley] Introduced `Hanami::Application::Action` as base class for actions that integrate with Hanami applications. Base action classes in Hanami applications should now inherit from this.
|
8
|
+
- [Tim Riley] Introduced `Hanami::Application::View` and `Hanami::Application::View::Context` as base classes for views and view contexts that integrate with Hanami applications. Base view classes in Hanami applications should now inherit from these.
|
9
|
+
- [Tim Riley] Introduced `Hanami::Application.application_name`, which returns an `Hanami::SliceName` instance, with methods for representing the application name in various formats.
|
10
|
+
|
11
|
+
## Fixed
|
12
|
+
- [Andrew Croome] When a request is halted, do not attempt to automatically render any view paired with an `Hanami::Application::Action`
|
13
|
+
|
14
|
+
## Changed
|
15
|
+
- [Tim Riley] `Hanami::Application.namespace_name`, `.namespace_path` have been removed. These can now be accessed from the `.application_name`.
|
16
|
+
- [Tim Riley] `Hanami::Slice.slice_name` now returns an `Hanami::SliceName` instance instead of a Symbol
|
17
|
+
- [Tim Riley] `Hanami::Slice.namespace_path` has been removed. This can now be accessed from the `.slice_name`.
|
18
|
+
|
4
19
|
## v2.0.0.alpha7.1 - 2020-03-09
|
5
20
|
|
6
21
|
## Fixed
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "hanami/action"
|
4
|
+
|
5
|
+
module Hanami
|
6
|
+
class Application
|
7
|
+
class Action < Hanami::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::Application::Action#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.(self) },
|
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(_action_class)
|
84
|
+
identifier = actions_config.view_context_identifier
|
85
|
+
|
86
|
+
if slice.key?(identifier)
|
87
|
+
slice[identifier]
|
88
|
+
elsif slice.application.key?(identifier)
|
89
|
+
slice.application[identifier]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def resolve_routes
|
94
|
+
slice.application[:routes_helper] if slice.application.key?(:routes_helper)
|
95
|
+
end
|
96
|
+
|
97
|
+
def actions_config
|
98
|
+
slice.application.config.actions
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "hanami/action"
|
4
|
+
require "hanami/slice_configurable"
|
5
|
+
require_relative "action/slice_configured_action"
|
6
|
+
|
7
|
+
module Hanami
|
8
|
+
class Application
|
9
|
+
# Superclass for actions intended for use within an Hanami application.
|
10
|
+
#
|
11
|
+
# @see Hanami::Action
|
12
|
+
#
|
13
|
+
# @api public
|
14
|
+
# @since 2.0.0
|
15
|
+
class Action < Hanami::Action
|
16
|
+
extend Hanami::SliceConfigurable
|
17
|
+
|
18
|
+
class << self
|
19
|
+
# @api private
|
20
|
+
def configure_for_slice(slice)
|
21
|
+
extend SliceConfiguredAction.new(slice)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :view, :view_context, :routes
|
26
|
+
|
27
|
+
# @see SliceConfiguredAction#define_new
|
28
|
+
# @api public
|
29
|
+
def initialize(view: nil, view_context: nil, routes: nil, **kwargs)
|
30
|
+
@view = view
|
31
|
+
@view_context = view_context
|
32
|
+
@routes = routes
|
33
|
+
|
34
|
+
super(**kwargs)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def build_response(**options)
|
40
|
+
options = options.merge(view_options: method(:view_options))
|
41
|
+
super(**options)
|
42
|
+
end
|
43
|
+
|
44
|
+
def view_options(req, res)
|
45
|
+
{context: view_context&.with(**view_context_options(req, res))}.compact
|
46
|
+
end
|
47
|
+
|
48
|
+
def view_context_options(req, res)
|
49
|
+
{request: req, response: res}
|
50
|
+
end
|
51
|
+
|
52
|
+
def finish(req, res, halted)
|
53
|
+
res.render(view, **req.params) if !halted && auto_render?(res)
|
54
|
+
super
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns true if a view should automatically be rendered onto the response body.
|
58
|
+
#
|
59
|
+
# This may be overridden to enable/disable automatic rendering.
|
60
|
+
#
|
61
|
+
# @param res [Hanami::Action::Response]
|
62
|
+
#
|
63
|
+
# @return [Boolean]
|
64
|
+
#
|
65
|
+
# @since 2.0.0
|
66
|
+
# @api public
|
67
|
+
def auto_render?(res)
|
68
|
+
view && res.body.empty?
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,95 @@
|
|
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
|
+
class Application
|
11
|
+
class View < Hanami::View
|
12
|
+
# View context for views in Hanami applications.
|
13
|
+
#
|
14
|
+
# @api public
|
15
|
+
# @since 2.0.0
|
16
|
+
class Context < Hanami::View::Context
|
17
|
+
extend Hanami::SliceConfigurable
|
18
|
+
|
19
|
+
# @api private
|
20
|
+
def self.configure_for_slice(slice)
|
21
|
+
extend SliceConfiguredContext.new(slice)
|
22
|
+
end
|
23
|
+
|
24
|
+
# @see SliceConfiguredContext#define_new
|
25
|
+
def initialize(**kwargs)
|
26
|
+
defaults = {content: {}}
|
27
|
+
|
28
|
+
super(**kwargs, **defaults)
|
29
|
+
end
|
30
|
+
|
31
|
+
def inflector
|
32
|
+
_options.fetch(:inflector)
|
33
|
+
end
|
34
|
+
|
35
|
+
def routes
|
36
|
+
_options.fetch(:routes)
|
37
|
+
end
|
38
|
+
|
39
|
+
def settings
|
40
|
+
_options.fetch(:settings)
|
41
|
+
end
|
42
|
+
|
43
|
+
def assets
|
44
|
+
unless _options[:assets]
|
45
|
+
raise Hanami::ComponentLoadError, "hanami-assets gem is required to access assets"
|
46
|
+
end
|
47
|
+
|
48
|
+
_options[:assets]
|
49
|
+
end
|
50
|
+
|
51
|
+
def content_for(key, value = nil, &block)
|
52
|
+
content = _options[:content]
|
53
|
+
output = nil
|
54
|
+
|
55
|
+
if block
|
56
|
+
content[key] = yield
|
57
|
+
elsif value
|
58
|
+
content[key] = value
|
59
|
+
else
|
60
|
+
output = content[key]
|
61
|
+
end
|
62
|
+
|
63
|
+
output
|
64
|
+
end
|
65
|
+
|
66
|
+
def current_path
|
67
|
+
request.fullpath
|
68
|
+
end
|
69
|
+
|
70
|
+
def csrf_token
|
71
|
+
request.session[Hanami::Action::CSRFProtection::CSRF_TOKEN]
|
72
|
+
end
|
73
|
+
|
74
|
+
def request
|
75
|
+
_options.fetch(:request)
|
76
|
+
end
|
77
|
+
|
78
|
+
def session
|
79
|
+
request.session
|
80
|
+
end
|
81
|
+
|
82
|
+
def flash
|
83
|
+
response.flash
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
# TODO: create `Request#flash` so we no longer need the `response`
|
89
|
+
def response
|
90
|
+
_options.fetch(:response)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "hanami/view"
|
4
|
+
|
5
|
+
module Hanami
|
6
|
+
class Application
|
7
|
+
class View < Hanami::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 application container and provides them to {#initialize} as injected
|
33
|
+
# dependencies.
|
34
|
+
#
|
35
|
+
# This includes the following application components:
|
36
|
+
#
|
37
|
+
# - the configured inflector as `inflector`
|
38
|
+
# - "settings" from the application container as `settings`
|
39
|
+
# - "routes" from the application container as `routes`
|
40
|
+
# - "assets" from the application 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.application[:settings] if slice.application.key?(:settings)
|
59
|
+
end
|
60
|
+
|
61
|
+
def resolve_routes
|
62
|
+
slice.application[:routes_helper] if slice.application.key?(:routes_helper)
|
63
|
+
end
|
64
|
+
|
65
|
+
def resolve_assets
|
66
|
+
slice.application[:assets] if slice.application.key?(:assets)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "hanami/view"
|
4
|
+
|
5
|
+
module Hanami
|
6
|
+
class Application
|
7
|
+
class View < Hanami::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.application.config.views.respond_to?(:"#{setting}")
|
36
|
+
view_class.config.public_send(
|
37
|
+
:"#{setting}=",
|
38
|
+
slice.application.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.application.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
|
+
slice.root.join(path.dir)
|
66
|
+
else
|
67
|
+
path
|
68
|
+
end
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
def namespace_from_path(path)
|
73
|
+
path = "#{slice.slice_name.path}/#{path}"
|
74
|
+
|
75
|
+
begin
|
76
|
+
require path
|
77
|
+
rescue LoadError => exception
|
78
|
+
raise exception unless exception.path == path
|
79
|
+
end
|
80
|
+
|
81
|
+
begin
|
82
|
+
inflector.constantize(inflector.camelize(path))
|
83
|
+
rescue NameError => exception
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def template_name(view_class)
|
88
|
+
slice
|
89
|
+
.inflector
|
90
|
+
.underscore(view_class.name)
|
91
|
+
.sub(/^#{slice.slice_name.path}\//, "")
|
92
|
+
.sub(/^#{view_class.config.template_inference_base}\//, "")
|
93
|
+
end
|
94
|
+
|
95
|
+
def inflector
|
96
|
+
slice.inflector
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,24 @@
|
|
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
|
+
class Application
|
9
|
+
# Superclass for views intended for use within an Hanami application.
|
10
|
+
#
|
11
|
+
# @see Hanami::View
|
12
|
+
#
|
13
|
+
# @api public
|
14
|
+
# @since 2.0.0
|
15
|
+
class View < Hanami::View
|
16
|
+
extend Hanami::SliceConfigurable
|
17
|
+
|
18
|
+
# @api private
|
19
|
+
def self.configure_for_slice(slice)
|
20
|
+
extend SliceConfiguredView.new(slice)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../constants"
|
4
|
+
|
5
|
+
module Hanami
|
6
|
+
class Application
|
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.application.config.actions.name_inference_base
|
32
|
+
view_key_base = slice.application.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
|
data/lib/hanami/application.rb
CHANGED
@@ -7,6 +7,7 @@ require "rack"
|
|
7
7
|
require "zeitwerk"
|
8
8
|
require_relative "constants"
|
9
9
|
require_relative "slice"
|
10
|
+
require_relative "slice_name"
|
10
11
|
require_relative "application/slice_registrar"
|
11
12
|
|
12
13
|
module Hanami
|
@@ -17,21 +18,25 @@ module Hanami
|
|
17
18
|
@_mutex = Mutex.new
|
18
19
|
|
19
20
|
class << self
|
20
|
-
def inherited(
|
21
|
+
def inherited(subclass)
|
21
22
|
super
|
23
|
+
|
22
24
|
@_mutex.synchronize do
|
23
|
-
|
25
|
+
subclass.class_eval do
|
24
26
|
@_mutex = Mutex.new
|
25
|
-
@
|
27
|
+
@application_name = SliceName.new(subclass, inflector: -> { subclass.inflector })
|
28
|
+
@configuration = Hanami::Configuration.new(application_name: @application_name, env: Hanami.env)
|
26
29
|
@autoloader = Zeitwerk::Loader.new
|
27
30
|
@container = Class.new(Dry::System::Container)
|
28
31
|
|
32
|
+
@prepared = @booted = false
|
33
|
+
|
29
34
|
extend ClassMethods
|
30
35
|
end
|
31
36
|
|
32
|
-
|
37
|
+
subclass.send :prepare_base_load_path
|
33
38
|
|
34
|
-
Hanami.application =
|
39
|
+
Hanami.application = subclass
|
35
40
|
end
|
36
41
|
end
|
37
42
|
end
|
@@ -40,20 +45,16 @@ module Hanami
|
|
40
45
|
#
|
41
46
|
# rubocop:disable Metrics/ModuleLength
|
42
47
|
module ClassMethods
|
43
|
-
attr_reader :autoloader, :container
|
44
|
-
|
45
|
-
def self.extended(klass)
|
46
|
-
klass.class_eval do
|
47
|
-
@prepared = @booted = false
|
48
|
-
end
|
49
|
-
end
|
48
|
+
attr_reader :application_name, :configuration, :autoloader, :container
|
50
49
|
|
51
|
-
|
52
|
-
@_configuration
|
53
|
-
end
|
50
|
+
alias_method :slice_name, :application_name
|
54
51
|
|
55
52
|
alias_method :config, :configuration
|
56
53
|
|
54
|
+
def application
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
57
58
|
def prepare(provider_name = nil)
|
58
59
|
container.prepare(provider_name) and return self if provider_name
|
59
60
|
|
@@ -147,19 +148,7 @@ module Hanami
|
|
147
148
|
end
|
148
149
|
|
149
150
|
def namespace
|
150
|
-
|
151
|
-
end
|
152
|
-
|
153
|
-
def namespace_name
|
154
|
-
namespace.name
|
155
|
-
end
|
156
|
-
|
157
|
-
def namespace_path
|
158
|
-
inflector.underscore(namespace)
|
159
|
-
end
|
160
|
-
|
161
|
-
def application_name
|
162
|
-
configuration.application_name
|
151
|
+
application_name.namespace
|
163
152
|
end
|
164
153
|
|
165
154
|
def root
|
@@ -170,21 +159,6 @@ module Hanami
|
|
170
159
|
configuration.inflector
|
171
160
|
end
|
172
161
|
|
173
|
-
# @api private
|
174
|
-
def component_provider(component)
|
175
|
-
raise "Hanami.application must be prepared before detecting providers" unless prepared?
|
176
|
-
|
177
|
-
# e.g. [Admin, Main, MyApp]
|
178
|
-
providers = slices.to_a + [self]
|
179
|
-
|
180
|
-
component_class = component.is_a?(Class) ? component : component.class
|
181
|
-
component_name = component_class.name
|
182
|
-
|
183
|
-
return unless component_name
|
184
|
-
|
185
|
-
providers.detect { |provider| component_name.include?(provider.namespace.to_s) }
|
186
|
-
end
|
187
|
-
|
188
162
|
private
|
189
163
|
|
190
164
|
def prepare_base_load_path
|
@@ -222,8 +196,8 @@ module Hanami
|
|
222
196
|
|
223
197
|
def prepare_autoload_paths
|
224
198
|
# Autoload classes defined in lib/[app_namespace]/
|
225
|
-
if root.join("lib",
|
226
|
-
autoloader.push_dir(root.join("lib",
|
199
|
+
if root.join("lib", application_name.name).directory?
|
200
|
+
autoloader.push_dir(root.join("lib", application_name.name), namespace: namespace)
|
227
201
|
end
|
228
202
|
end
|
229
203
|
|
@@ -239,8 +213,8 @@ module Hanami
|
|
239
213
|
|
240
214
|
def prepare_autoloader
|
241
215
|
# Autoload classes defined in lib/[app_namespace]/
|
242
|
-
if root.join("lib",
|
243
|
-
autoloader.push_dir(root.join("lib",
|
216
|
+
if root.join("lib", application_name.name).directory?
|
217
|
+
autoloader.push_dir(root.join("lib", application_name.name), namespace: namespace)
|
244
218
|
end
|
245
219
|
|
246
220
|
autoloader.setup
|
@@ -258,7 +232,7 @@ module Hanami
|
|
258
232
|
end
|
259
233
|
|
260
234
|
def autodiscover_application_constant(constants)
|
261
|
-
inflector.constantize([namespace_name, *constants].join(MODULE_DELIMITER))
|
235
|
+
inflector.constantize([application_name.namespace_name, *constants].join(MODULE_DELIMITER))
|
262
236
|
end
|
263
237
|
|
264
238
|
def load_router
|