hanami 2.0.0.beta4 → 2.0.0.rc1
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 +19 -0
- data/hanami.gemspec +8 -7
- data/lib/hanami/app.rb +47 -36
- data/lib/hanami/assets/app_config.rb +7 -15
- data/lib/hanami/assets/config.rb +5 -6
- data/lib/hanami/config/actions/content_security_policy.rb +1 -1
- data/lib/hanami/config/actions/cookies.rb +27 -0
- data/lib/hanami/config/actions/sessions.rb +42 -5
- data/lib/hanami/config/actions.rb +81 -17
- data/lib/hanami/config/logger.rb +112 -23
- data/lib/hanami/config/router.rb +0 -1
- data/lib/hanami/config/views.rb +6 -10
- data/lib/hanami/config.rb +235 -73
- data/lib/hanami/constants.rb +4 -0
- data/lib/hanami/errors.rb +17 -0
- data/lib/hanami/extensions/action/slice_configured_action.rb +9 -5
- data/lib/hanami/extensions/action.rb +59 -7
- data/lib/hanami/extensions/view/context.rb +3 -4
- data/lib/hanami/extensions/view/slice_configured_view.rb +4 -4
- data/lib/hanami/extensions/view.rb +7 -5
- data/lib/hanami/providers/inflector.rb +6 -0
- data/lib/hanami/providers/logger.rb +8 -0
- data/lib/hanami/providers/rack.rb +12 -0
- data/lib/hanami/providers/routes.rb +14 -4
- data/lib/hanami/routes.rb +36 -1
- data/lib/hanami/settings/env_store.rb +1 -1
- data/lib/hanami/settings.rb +102 -36
- data/lib/hanami/slice/router.rb +38 -16
- data/lib/hanami/slice/routing/middleware/stack.rb +66 -42
- data/lib/hanami/slice/routing/resolver.rb +10 -17
- data/lib/hanami/slice/view_name_inferrer.rb +1 -1
- data/lib/hanami/slice.rb +553 -14
- data/lib/hanami/slice_registrar.rb +20 -15
- data/lib/hanami/version.rb +2 -3
- data/lib/hanami/web/rack_logger.rb +14 -4
- data/lib/hanami.rb +122 -23
- data/spec/integration/action/csrf_protection_spec.rb +1 -1
- data/spec/integration/container/application_routes_helper_spec.rb +3 -1
- data/spec/integration/container/provider_lifecycle_spec.rb +61 -0
- data/spec/integration/container/standard_providers/rack_provider_spec.rb +44 -0
- data/spec/integration/container/{standard_bootable_components_spec.rb → standard_providers_spec.rb} +3 -3
- data/spec/integration/rack_app/body_parser_spec.rb +3 -0
- data/spec/integration/rack_app/middleware_spec.rb +427 -3
- data/spec/integration/rack_app/non_booted_rack_app_spec.rb +2 -1
- data/spec/integration/rack_app/rack_app_spec.rb +39 -11
- data/spec/integration/setup_spec.rb +4 -4
- data/spec/integration/slices/external_slice_spec.rb +2 -1
- data/spec/integration/slices/slice_configuration_spec.rb +3 -1
- data/spec/integration/slices/slice_loading_spec.rb +4 -4
- data/spec/integration/slices/slice_routing_spec.rb +4 -3
- data/spec/integration/slices_spec.rb +100 -0
- data/spec/isolation/hanami/boot/success_spec.rb +1 -1
- data/spec/support/app_integration.rb +2 -10
- data/spec/unit/hanami/config/actions/content_security_policy_spec.rb +7 -7
- data/spec/unit/hanami/config/actions/default_values_spec.rb +1 -1
- data/spec/unit/hanami/config/actions/sessions_spec.rb +1 -3
- data/spec/unit/hanami/config/actions_spec.rb +1 -12
- data/spec/unit/hanami/config/logger_spec.rb +38 -55
- data/spec/unit/hanami/config/router_spec.rb +1 -1
- data/spec/unit/hanami/config/views_spec.rb +3 -13
- data/spec/unit/hanami/settings_spec.rb +1 -1
- data/spec/unit/hanami/slice_configurable_spec.rb +5 -5
- data/spec/unit/hanami/slice_spec.rb +32 -0
- data/spec/unit/hanami/version_spec.rb +1 -1
- data/spec/unit/hanami/web/rack_logger_spec.rb +13 -2
- metadata +54 -45
- data/lib/hanami/config/sessions.rb +0 -50
- data/spec/unit/hanami/config_spec.rb +0 -43
data/lib/hanami/slice/router.rb
CHANGED
@@ -1,26 +1,36 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "hanami/router"
|
4
|
-
require_relative "routing/middleware/stack"
|
5
4
|
|
6
5
|
module Hanami
|
7
6
|
class Slice
|
8
|
-
# Hanami
|
7
|
+
# `Hanami::Router` subclass with enhancements for use within Hanami apps.
|
8
|
+
#
|
9
|
+
# This is loaded from Hanami apps and slices and made available as their
|
10
|
+
# {Hanami::Slice::ClassMethods#router router}.
|
11
|
+
#
|
12
|
+
# @api private
|
9
13
|
# @since 2.0.0
|
10
14
|
class Router < ::Hanami::Router
|
11
15
|
# @api private
|
16
|
+
# @since 2.0.0
|
12
17
|
attr_reader :middleware_stack
|
13
18
|
|
19
|
+
# @api private
|
14
20
|
# @since 2.0.0
|
21
|
+
attr_reader :path_prefix
|
22
|
+
|
15
23
|
# @api private
|
16
|
-
|
24
|
+
# @since 2.0.0
|
25
|
+
def initialize(routes:, middleware_stack: Routing::Middleware::Stack.new, prefix: ::Hanami::Router::DEFAULT_PREFIX, **kwargs, &blk)
|
26
|
+
@path_prefix = Hanami::Router::Prefix.new(prefix)
|
17
27
|
@middleware_stack = middleware_stack
|
18
28
|
instance_eval(&blk)
|
19
29
|
super(**kwargs, &routes)
|
20
30
|
end
|
21
31
|
|
22
|
-
# @since 2.0.0
|
23
32
|
# @api private
|
33
|
+
# @since 2.0.0
|
24
34
|
def freeze
|
25
35
|
return self if frozen?
|
26
36
|
|
@@ -28,20 +38,32 @@ module Hanami
|
|
28
38
|
super
|
29
39
|
end
|
30
40
|
|
31
|
-
# @since 2.0.0
|
32
41
|
# @api private
|
33
|
-
def use(...)
|
34
|
-
middleware_stack.use(...)
|
35
|
-
end
|
36
|
-
|
37
42
|
# @since 2.0.0
|
38
|
-
|
39
|
-
|
40
|
-
middleware_stack.with(args.first) do
|
41
|
-
super
|
42
|
-
end
|
43
|
+
def use(*args, **kwargs, &blk)
|
44
|
+
middleware_stack.use(*args, **kwargs.merge(path_prefix: path_prefix.to_s), &blk)
|
43
45
|
end
|
44
46
|
|
47
|
+
# Yields a block for routes to resolve their action components from the given slice.
|
48
|
+
#
|
49
|
+
# An optional URL prefix may be supplied with `at:`.
|
50
|
+
#
|
51
|
+
# @example
|
52
|
+
# # config/routes.rb
|
53
|
+
#
|
54
|
+
# module MyApp
|
55
|
+
# class Routes < Hanami::Routes
|
56
|
+
# slice :admin, at: "/admin" do
|
57
|
+
# # Will route to the "actions.posts.index" component in Admin::Slice
|
58
|
+
# get "posts", to: "posts.index"
|
59
|
+
# end
|
60
|
+
# end
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# @param slice_name [Symbol] the slice's name
|
64
|
+
# @param at [String, nil] optional URL prefix for the routes
|
65
|
+
#
|
66
|
+
# @api public
|
45
67
|
# @since 2.0.0
|
46
68
|
def slice(slice_name, at:, &blk)
|
47
69
|
blk ||= @resolver.find_slice(slice_name).routes
|
@@ -49,13 +71,13 @@ module Hanami
|
|
49
71
|
prev_resolver = @resolver
|
50
72
|
@resolver = @resolver.to_slice(slice_name)
|
51
73
|
|
52
|
-
scope(
|
74
|
+
scope(at, &blk)
|
53
75
|
ensure
|
54
76
|
@resolver = prev_resolver
|
55
77
|
end
|
56
78
|
|
57
|
-
# @since 2.0.0
|
58
79
|
# @api private
|
80
|
+
# @since 2.0.0
|
59
81
|
def to_rack_app
|
60
82
|
middleware_stack.to_rack_app(self)
|
61
83
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "hanami/router"
|
3
4
|
require "hanami/middleware"
|
5
|
+
require "hanami/middleware/app"
|
4
6
|
require "hanami/errors"
|
5
7
|
|
6
8
|
module Hanami
|
@@ -11,8 +13,8 @@ module Hanami
|
|
11
13
|
module Middleware
|
12
14
|
# Wraps a rack app with a middleware stack
|
13
15
|
#
|
14
|
-
# We use this class to add middlewares to the rack application generated
|
15
|
-
#
|
16
|
+
# We use this class to add middlewares to the rack application generated from
|
17
|
+
# {Hanami::Slice::Router}.
|
16
18
|
#
|
17
19
|
# ```
|
18
20
|
# stack = Hanami::Slice::Routing::Middleware::Stack.new
|
@@ -28,28 +30,31 @@ module Hanami
|
|
28
30
|
# end
|
29
31
|
# ```
|
30
32
|
#
|
33
|
+
# @see Hanami::Config#middleware
|
34
|
+
#
|
31
35
|
# @since 2.0.0
|
32
36
|
# @api private
|
33
37
|
class Stack
|
34
38
|
include Enumerable
|
35
39
|
|
36
|
-
# @since 2.0.0
|
37
|
-
# @api private
|
38
|
-
ROOT_PREFIX = "/"
|
39
|
-
private_constant :ROOT_PREFIX
|
40
|
-
|
41
40
|
# @since 2.0.0
|
42
41
|
# @api private
|
43
42
|
attr_reader :stack
|
44
43
|
|
45
|
-
#
|
44
|
+
# Returns an array of Ruby namespaces from which to load middleware classes specified by
|
45
|
+
# symbol names given to {#use}.
|
46
|
+
#
|
47
|
+
# Defaults to `[Hanami::Middleware]`.
|
48
|
+
#
|
49
|
+
# @return [Array<Object>]
|
50
|
+
#
|
46
51
|
# @api public
|
52
|
+
# @since 2.0.0
|
47
53
|
attr_reader :namespaces
|
48
54
|
|
49
55
|
# @since 2.0.0
|
50
56
|
# @api private
|
51
57
|
def initialize
|
52
|
-
@prefix = ROOT_PREFIX
|
53
58
|
@stack = Hash.new { |hash, key| hash[key] = [] }
|
54
59
|
@namespaces = [Hanami::Middleware]
|
55
60
|
end
|
@@ -58,23 +63,44 @@ module Hanami
|
|
58
63
|
# @api private
|
59
64
|
def initialize_copy(source)
|
60
65
|
super
|
61
|
-
@prefix = source.instance_variable_get(:@prefix).dup
|
62
66
|
@stack = stack.dup
|
63
67
|
@namespaces = namespaces.dup
|
64
68
|
end
|
65
69
|
|
70
|
+
# Adds a middleware to the stack.
|
71
|
+
#
|
72
|
+
# @example
|
73
|
+
# # Using a symbol name; adds Hanami::Middleware::BodyParser.new([:json])
|
74
|
+
# middleware.use :body_parser, :json
|
75
|
+
#
|
76
|
+
# # Using a class name
|
77
|
+
# middleware.use MyMiddleware
|
78
|
+
#
|
79
|
+
# # Adding a middleware before or after others
|
80
|
+
# middleware.use MyMiddleware, before: SomeMiddleware
|
81
|
+
# middleware.use MyMiddleware, after: OtherMiddleware
|
82
|
+
#
|
83
|
+
# @param spec [Symbol, Class] the middleware name or class name
|
84
|
+
# @param args [Array, nil] Arguments to pass to the middleware's `.new` method
|
85
|
+
# @param before [Class, nil] an optional (already added) middleware class to add the
|
86
|
+
# middleware before
|
87
|
+
# @param after [Class, nil] an optional (already added) middleware class to add the
|
88
|
+
# middleware after
|
89
|
+
#
|
90
|
+
# @return [self]
|
91
|
+
#
|
92
|
+
# @api public
|
66
93
|
# @since 2.0.0
|
67
|
-
|
68
|
-
def use(spec, *args, before: nil, after: nil, &blk)
|
94
|
+
def use(spec, *args, path_prefix: ::Hanami::Router::DEFAULT_PREFIX, before: nil, after: nil, &blk)
|
69
95
|
middleware = resolve_middleware_class(spec)
|
70
96
|
item = [middleware, args, blk]
|
71
97
|
|
72
98
|
if before
|
73
|
-
@stack[
|
99
|
+
@stack[path_prefix].insert((idx = index_of(before, path_prefix)).zero? ? 0 : idx - 1, item)
|
74
100
|
elsif after
|
75
|
-
@stack[
|
101
|
+
@stack[path_prefix].insert(index_of(after, path_prefix) + 1, item)
|
76
102
|
else
|
77
|
-
@stack[
|
103
|
+
@stack[path_prefix].push([middleware, args, blk])
|
78
104
|
end
|
79
105
|
|
80
106
|
self
|
@@ -83,22 +109,12 @@ module Hanami
|
|
83
109
|
# @since 2.0.0
|
84
110
|
# @api private
|
85
111
|
def update(other)
|
86
|
-
other.stack.each do |
|
87
|
-
stack[
|
112
|
+
other.stack.each do |path_prefix, items|
|
113
|
+
stack[path_prefix].concat(items)
|
88
114
|
end
|
89
115
|
self
|
90
116
|
end
|
91
117
|
|
92
|
-
# @since 2.0.0
|
93
|
-
# @api private
|
94
|
-
def with(path)
|
95
|
-
prefix = @prefix
|
96
|
-
@prefix = path
|
97
|
-
yield
|
98
|
-
ensure
|
99
|
-
@prefix = prefix
|
100
|
-
end
|
101
|
-
|
102
118
|
# @since 2.0.0
|
103
119
|
# @api private
|
104
120
|
def to_rack_app(app)
|
@@ -106,20 +122,17 @@ module Hanami
|
|
106
122
|
raise "Add \"rack\" to your `Gemfile` to run Hanami as a rack app"
|
107
123
|
end
|
108
124
|
|
109
|
-
|
110
|
-
|
111
|
-
s = self
|
125
|
+
mapping = to_hash
|
126
|
+
return app if mapping.empty?
|
112
127
|
|
113
|
-
|
114
|
-
|
115
|
-
s.mapped(self, prefix) do
|
116
|
-
stack.each do |middleware, args, blk|
|
117
|
-
use(middleware, *args, &blk)
|
118
|
-
end
|
119
|
-
end
|
128
|
+
Hanami::Middleware::App.new(app, mapping)
|
129
|
+
end
|
120
130
|
|
121
|
-
|
122
|
-
|
131
|
+
# @since 2.0.0
|
132
|
+
# @api private
|
133
|
+
def to_hash
|
134
|
+
@stack.each_with_object({}) do |(path, _), result|
|
135
|
+
result[path] = stack_for(path)
|
123
136
|
end
|
124
137
|
end
|
125
138
|
|
@@ -138,7 +151,7 @@ module Hanami
|
|
138
151
|
# @since 2.0.0
|
139
152
|
# @api private
|
140
153
|
def mapped(builder, prefix, &blk)
|
141
|
-
if prefix ==
|
154
|
+
if prefix == ::Hanami::Router::DEFAULT_PREFIX
|
142
155
|
builder.instance_eval(&blk)
|
143
156
|
else
|
144
157
|
builder.map(prefix, &blk)
|
@@ -148,8 +161,18 @@ module Hanami
|
|
148
161
|
private
|
149
162
|
|
150
163
|
# @since 2.0.0
|
151
|
-
def index_of(middleware)
|
152
|
-
@stack[
|
164
|
+
def index_of(middleware, path_prefix)
|
165
|
+
@stack[path_prefix].index { |(m, *)| m.equal?(middleware) }
|
166
|
+
end
|
167
|
+
|
168
|
+
# @since 2.0.0
|
169
|
+
# @api private
|
170
|
+
def stack_for(current_path)
|
171
|
+
@stack.each_with_object([]) do |(path, stack), result|
|
172
|
+
next unless current_path.start_with?(path)
|
173
|
+
|
174
|
+
result.push(stack)
|
175
|
+
end.flatten(1)
|
153
176
|
end
|
154
177
|
|
155
178
|
# @since 2.0.0
|
@@ -173,6 +196,7 @@ module Hanami
|
|
173
196
|
rescue LoadError # rubocop:disable Lint/SuppressedException
|
174
197
|
end
|
175
198
|
|
199
|
+
# FIXME: Classify must use App inflector
|
176
200
|
class_name = Hanami::Utils::String.classify(spec.to_s)
|
177
201
|
namespace = namespaces.detect { |ns| ns.const_defined?(class_name) }
|
178
202
|
|
@@ -1,24 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "../../routes"
|
4
|
+
|
3
5
|
module Hanami
|
4
6
|
class Slice
|
7
|
+
# @api private
|
5
8
|
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
9
|
# Hanami app router endpoint resolver
|
21
10
|
#
|
11
|
+
# This resolves endpoints objects from a slice container using the strings passed to `to:` as
|
12
|
+
# their container keys.
|
13
|
+
#
|
14
|
+
# @api private
|
22
15
|
# @since 2.0.0
|
23
16
|
class Resolver
|
24
17
|
SLICE_ACTIONS_KEY_NAMESPACE = "actions"
|
@@ -55,7 +48,7 @@ module Hanami
|
|
55
48
|
end
|
56
49
|
|
57
50
|
unless endpoint.respond_to?(:call)
|
58
|
-
raise NotCallableEndpointError.new(endpoint)
|
51
|
+
raise Routes::NotCallableEndpointError.new(endpoint)
|
59
52
|
end
|
60
53
|
|
61
54
|
endpoint
|
@@ -79,7 +72,7 @@ module Hanami
|
|
79
72
|
# concerns (which may not be fully loaded at the time of reading the routes)
|
80
73
|
-> (*args) {
|
81
74
|
action = slice.resolve(action_key) do
|
82
|
-
raise
|
75
|
+
raise Routes::MissingActionError.new(action_key, slice)
|
83
76
|
end
|
84
77
|
|
85
78
|
action.call(*args)
|
@@ -89,7 +82,7 @@ module Hanami
|
|
89
82
|
def ensure_action_in_slice(key)
|
90
83
|
return unless slice.booted?
|
91
84
|
|
92
|
-
raise
|
85
|
+
raise Routes::MissingActionError.new(key, slice) unless slice.key?(key)
|
93
86
|
end
|
94
87
|
end
|
95
88
|
end
|
@@ -23,7 +23,7 @@ module Hanami
|
|
23
23
|
# ViewNameInferrer.call(action_name: "Main::Actions::Posts::Create", slice: Main::Slice)
|
24
24
|
# # => ["views.posts.create", "views.posts.new"]
|
25
25
|
#
|
26
|
-
# @param
|
26
|
+
# @param action_class_name [String] action class name
|
27
27
|
# @param slice [Hanami::Slice, Hanami::Application] Hanami slice containing the action
|
28
28
|
#
|
29
29
|
# @return [Array<string>] array of paired view container keys
|