hanami 2.0.0.beta4 → 2.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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.rb
CHANGED
@@ -3,12 +3,8 @@
|
|
3
3
|
require "zeitwerk"
|
4
4
|
require "dry/system"
|
5
5
|
|
6
|
-
require_relative "../hanami"
|
7
6
|
require_relative "constants"
|
8
7
|
require_relative "errors"
|
9
|
-
require_relative "settings"
|
10
|
-
require_relative "slice_name"
|
11
|
-
require_relative "slice_registrar"
|
12
8
|
|
13
9
|
module Hanami
|
14
10
|
# A slice represents any distinct area of concern within an Hanami app.
|
@@ -35,6 +31,7 @@ module Hanami
|
|
35
31
|
class Slice
|
36
32
|
@_mutex = Mutex.new
|
37
33
|
|
34
|
+
# @api private
|
38
35
|
def self.inherited(subclass)
|
39
36
|
super
|
40
37
|
|
@@ -51,29 +48,146 @@ module Hanami
|
|
51
48
|
|
52
49
|
# rubocop:disable Metrics/ModuleLength
|
53
50
|
module ClassMethods
|
54
|
-
|
55
|
-
|
51
|
+
# Returns the slice's parent.
|
52
|
+
#
|
53
|
+
# For top-level slices defined in `slices/` or `config/slices/`, this will be the Hanami app
|
54
|
+
# itself (`Hanami.app`). For nested slices, this will be the slice in which they were
|
55
|
+
# registered.
|
56
|
+
#
|
57
|
+
# @return [Hanami::Slice]
|
58
|
+
#
|
59
|
+
# @see #register_slice
|
60
|
+
#
|
61
|
+
# @api public
|
62
|
+
# @since 2.0.0
|
63
|
+
attr_reader :parent
|
64
|
+
|
65
|
+
# Returns the slice's autoloader.
|
66
|
+
#
|
67
|
+
# Each slice has its own `Zeitwerk::Loader` autoloader instance, which is setup when the slice
|
68
|
+
# is {#prepare prepared}.
|
69
|
+
#
|
70
|
+
# @return [Zeitwerk::Loader]
|
71
|
+
#
|
72
|
+
# @see https://github.com/fxn/zeitwerk
|
73
|
+
#
|
74
|
+
# @api public
|
75
|
+
# @since 2.0.0
|
76
|
+
attr_reader :autoloader
|
77
|
+
|
78
|
+
# Returns the slice's container.
|
79
|
+
#
|
80
|
+
# This is a `Dry::System::Container` that is already configured for the slice.
|
81
|
+
#
|
82
|
+
# In ordinary usage, you shouldn't need direct access the container at all, since the slice
|
83
|
+
# provides its own methods for interacting with the container (such as {#[]}, {#keys}, {#key?}
|
84
|
+
# {#register}, {#register_provider}, {#prepare}, {#start}, {#stop}).
|
85
|
+
#
|
86
|
+
# If you need to configure the container directly, use {#prepare_container}.
|
87
|
+
#
|
88
|
+
# @see https://dry-rb.org/gems/dry-system
|
89
|
+
#
|
90
|
+
# @api public
|
91
|
+
# @since 2.0.0
|
92
|
+
attr_reader :container
|
93
|
+
|
94
|
+
# Returns the Hanami app.
|
95
|
+
#
|
96
|
+
# @return [Hanami::App]
|
97
|
+
#
|
98
|
+
# @api public
|
99
|
+
# @since 2.0.0
|
56
100
|
def app
|
57
101
|
Hanami.app
|
58
102
|
end
|
59
103
|
|
60
|
-
#
|
61
|
-
#
|
104
|
+
# Returns the slice's config.
|
105
|
+
#
|
106
|
+
# A slice's config is copied from the app config at time of first access.
|
107
|
+
#
|
108
|
+
# @return [Hanami::Config]
|
109
|
+
#
|
110
|
+
# @see App::ClassMethods.config
|
111
|
+
#
|
112
|
+
# @api public
|
113
|
+
# @since 2.0.0
|
62
114
|
def config
|
63
115
|
@config ||= app.config.dup.tap do |slice_config|
|
64
|
-
#
|
116
|
+
# Unset config from app that does not apply to ordinary slices
|
65
117
|
slice_config.root = nil
|
66
118
|
end
|
67
119
|
end
|
68
120
|
|
121
|
+
# Evaluates the block for a given app environment only.
|
122
|
+
#
|
123
|
+
# If the given `env_name` matches {Hanami.env}, then the block will be evaluated in the
|
124
|
+
# context of `self` (the slice) via `instance_eval`. The slice is also passed as the block's
|
125
|
+
# optional argument.
|
126
|
+
#
|
127
|
+
# If the env does not match, then the block is not evaluated at all.
|
128
|
+
#
|
129
|
+
# @example
|
130
|
+
# module MySlice
|
131
|
+
# class Slice < Hanami::Slice
|
132
|
+
# environment(:test) do
|
133
|
+
# config.logger.level = :info
|
134
|
+
# end
|
135
|
+
# end
|
136
|
+
# end
|
137
|
+
#
|
138
|
+
# @overload environment(env_name)
|
139
|
+
# @param env_name [Symbol] the environment name
|
140
|
+
#
|
141
|
+
# @overload environment(env_name)
|
142
|
+
# @param env_name [Symbol] the environment name
|
143
|
+
# @yieldparam slice [self] the slice
|
144
|
+
#
|
145
|
+
# @return [self]
|
146
|
+
#
|
147
|
+
# @see Hanami.env
|
148
|
+
#
|
149
|
+
# @api public
|
150
|
+
# @since 2.0.0
|
151
|
+
def environment(env_name, &block)
|
152
|
+
instance_eval(&block) if env_name == config.env
|
153
|
+
self
|
154
|
+
end
|
155
|
+
|
156
|
+
# Returns a {SliceName} for the slice, an object with methods returning the name of the slice
|
157
|
+
# in various formats.
|
158
|
+
#
|
159
|
+
# @return [SliceName]
|
160
|
+
#
|
161
|
+
# @api public
|
162
|
+
# @since 2.0.0
|
69
163
|
def slice_name
|
70
164
|
@slice_name ||= SliceName.new(self, inflector: method(:inflector))
|
71
165
|
end
|
72
166
|
|
167
|
+
# Returns the constant for the slice's module namespace.
|
168
|
+
#
|
169
|
+
# @example
|
170
|
+
# MySlice::Slice.namespace # => MySlice
|
171
|
+
#
|
172
|
+
# @return [Module] the namespace module constant
|
173
|
+
#
|
174
|
+
# @see SliceName#namespace
|
175
|
+
#
|
176
|
+
# @api public
|
177
|
+
# @since 2.0.0
|
73
178
|
def namespace
|
74
179
|
slice_name.namespace
|
75
180
|
end
|
76
181
|
|
182
|
+
# Returns the slice's root, either the root as explicitly configured, or a default fallback of
|
183
|
+
# the slice's name within the app's `slices/` dir.
|
184
|
+
#
|
185
|
+
# @return [Pathname]
|
186
|
+
#
|
187
|
+
# @see Config#root
|
188
|
+
#
|
189
|
+
# @api public
|
190
|
+
# @since 2.0.0
|
77
191
|
def root
|
78
192
|
# Provide a best guess for a root when it is not yet configured.
|
79
193
|
#
|
@@ -89,23 +203,105 @@ module Hanami
|
|
89
203
|
config.root || app.root.join(SLICES_DIR, slice_name.to_s)
|
90
204
|
end
|
91
205
|
|
206
|
+
# Returns the slice's configured inflector.
|
207
|
+
#
|
208
|
+
# Unless explicitly re-configured for the slice, this will be the app's inflector.
|
209
|
+
#
|
210
|
+
# @return [Dry::Inflector]
|
211
|
+
#
|
212
|
+
# @see Config#inflector
|
213
|
+
# @see Config#inflections
|
214
|
+
#
|
215
|
+
# @api public
|
216
|
+
# @since 2.0.0
|
92
217
|
def inflector
|
93
218
|
config.inflector
|
94
219
|
end
|
95
220
|
|
221
|
+
# @overload prepare
|
222
|
+
# Prepares the slice.
|
223
|
+
#
|
224
|
+
# This will define the slice's `Slice` and `Deps` constants, make all Ruby source files
|
225
|
+
# inside the slice's root dir autoloadable, as well as lazily loadable as container
|
226
|
+
# components.
|
227
|
+
#
|
228
|
+
# Call `prepare` when you want to access particular components within the slice while still
|
229
|
+
# minimizing load time. Preparing slices is the approach taken when loading the Hanami
|
230
|
+
# console or when running tests.
|
231
|
+
#
|
232
|
+
# @return [self]
|
233
|
+
#
|
234
|
+
# @see #boot
|
235
|
+
#
|
236
|
+
# @api public
|
237
|
+
# @since 2.0.0
|
238
|
+
#
|
239
|
+
# @overload prepare(provider_name)
|
240
|
+
# Prepares a provider.
|
241
|
+
#
|
242
|
+
# This triggers the provider's `prepare` lifecycle step.
|
243
|
+
#
|
244
|
+
# @param provider_name [Symbol] the name of the provider to start
|
245
|
+
#
|
246
|
+
# @return [self]
|
247
|
+
#
|
248
|
+
# @api public
|
249
|
+
# @since 2.0.0
|
96
250
|
def prepare(provider_name = nil)
|
97
251
|
if provider_name
|
98
252
|
container.prepare(provider_name)
|
99
|
-
self
|
100
253
|
else
|
101
254
|
prepare_slice
|
102
255
|
end
|
256
|
+
|
257
|
+
self
|
103
258
|
end
|
104
259
|
|
260
|
+
# Captures the given block to be called with the slice's container during the slice's
|
261
|
+
# `prepare` step, after the slice has already configured the container.
|
262
|
+
#
|
263
|
+
# This is intended for advanced usage only and should not be needed for ordinary slice
|
264
|
+
# configuration and usage.
|
265
|
+
#
|
266
|
+
# @example
|
267
|
+
# module MySlice
|
268
|
+
# class Sliice < Hanami::Slice
|
269
|
+
# prepare_container do |container|
|
270
|
+
# # ...
|
271
|
+
# end
|
272
|
+
# end
|
273
|
+
# end
|
274
|
+
#
|
275
|
+
# @yieldparam container [Dry::System::Container] the slice's container
|
276
|
+
#
|
277
|
+
# @return [self]
|
278
|
+
#
|
279
|
+
# @see #prepare
|
280
|
+
#
|
281
|
+
# @api public
|
282
|
+
# @since 2.0.0
|
105
283
|
def prepare_container(&block)
|
106
284
|
@prepare_container_block = block
|
285
|
+
self
|
107
286
|
end
|
108
287
|
|
288
|
+
# Boots the slice.
|
289
|
+
#
|
290
|
+
# This will prepare the slice (if not already prepared), start each of its providers, register
|
291
|
+
# all the slice's components from its Ruby source files, and import components from any other
|
292
|
+
# slices. It will also boot any of the slice's own registered nested slices. It will then
|
293
|
+
# freeze its container so no further components can be registered.
|
294
|
+
#
|
295
|
+
# Call `boot` if you want to fully load a slice and incur all load time up front, such as when
|
296
|
+
# preparing an app to serve web requests. Booting slices is the approach taken when running
|
297
|
+
# Hanami's standard Puma setup (see `config.ru`).
|
298
|
+
#
|
299
|
+
# @return [self]
|
300
|
+
#
|
301
|
+
# @see #prepare
|
302
|
+
#
|
303
|
+
# @api public
|
304
|
+
# @since 2.0.0
|
109
305
|
def boot
|
110
306
|
return self if booted?
|
111
307
|
|
@@ -119,64 +315,346 @@ module Hanami
|
|
119
315
|
self
|
120
316
|
end
|
121
317
|
|
318
|
+
# Shuts down the slice's providers, as well as the providers in any nested slices.
|
319
|
+
#
|
320
|
+
# @return [self]
|
321
|
+
#
|
322
|
+
# @api public
|
323
|
+
# @since 2.0.0
|
122
324
|
def shutdown
|
123
325
|
slices.each(&:shutdown)
|
124
326
|
container.shutdown!
|
125
327
|
self
|
126
328
|
end
|
127
329
|
|
330
|
+
# Returns true if the slice has been prepared.
|
331
|
+
#
|
332
|
+
# @return [Boolean]
|
333
|
+
#
|
334
|
+
# @see #prepare
|
335
|
+
#
|
336
|
+
# @api public
|
337
|
+
# @since 2.0.0
|
128
338
|
def prepared?
|
129
339
|
!!@prepared
|
130
340
|
end
|
131
341
|
|
342
|
+
# Returns true if the slice has been booted.
|
343
|
+
#
|
344
|
+
# @return [Boolean]
|
345
|
+
#
|
346
|
+
# @see #boot
|
347
|
+
#
|
348
|
+
# @api public
|
349
|
+
# @since 2.0.0
|
132
350
|
def booted?
|
133
351
|
!!@booted
|
134
352
|
end
|
135
353
|
|
354
|
+
# Returns the slice's collection of nested slices.
|
355
|
+
#
|
356
|
+
# @return [SliceRegistrar]
|
357
|
+
#
|
358
|
+
# @see #register_slice
|
359
|
+
#
|
360
|
+
# @api public
|
361
|
+
# @since 2.0.0
|
136
362
|
def slices
|
137
363
|
@slices ||= SliceRegistrar.new(self)
|
138
364
|
end
|
139
365
|
|
366
|
+
# @overload register_slice(name, &block)
|
367
|
+
# Registers a nested slice with the given name.
|
368
|
+
#
|
369
|
+
# This will define a new {Slice} subclass for the slice. If a block is given, it is passed
|
370
|
+
# the class object, and will be evaluated in the context of the class like `class_eval`.
|
371
|
+
#
|
372
|
+
# @example
|
373
|
+
# MySlice::Slice.register_slice do
|
374
|
+
# # Configure the slice or do other class-level things here
|
375
|
+
# end
|
376
|
+
#
|
377
|
+
# @param name [Symbol] the identifier for the slice to be registered
|
378
|
+
# @yieldparam slice [Hanami::Slice] the newly defined slice class
|
379
|
+
#
|
380
|
+
# @overload register_slice(name, slice_class)
|
381
|
+
# Registers a nested slice with the given name.
|
382
|
+
#
|
383
|
+
# The given `slice_class` will be registered as the slice. It must be a subclass of {Slice}.
|
384
|
+
#
|
385
|
+
# @param name [Symbol] the identifier for the slice to be registered
|
386
|
+
# @param slice_class [Hanami::Slice]
|
387
|
+
#
|
388
|
+
# @return [slices]
|
389
|
+
#
|
390
|
+
# @see SliceRegistrar#register
|
391
|
+
#
|
392
|
+
# @api public
|
393
|
+
# @since 2.0.0
|
140
394
|
def register_slice(...)
|
141
395
|
slices.register(...)
|
142
396
|
end
|
143
397
|
|
398
|
+
# Registers a component in the slice's container.
|
399
|
+
#
|
400
|
+
# @overload register(key, object)
|
401
|
+
# Registers the given object as the component. This same object will be returned whenever
|
402
|
+
# the component is resolved.
|
403
|
+
#
|
404
|
+
# @param key [String] the component's key
|
405
|
+
# @param object [Object] the object to register as the component
|
406
|
+
#
|
407
|
+
# @overload reigster(key, memoize: false, &block)
|
408
|
+
# Registers the given block as the component. When the component is resolved, the return
|
409
|
+
# value of the block will be returned.
|
410
|
+
#
|
411
|
+
# Since the block is not called until resolution-time, this is a useful way to register
|
412
|
+
# components that have dependencies on other components in the container, which as yet may
|
413
|
+
# be unavailable at the time of registration.
|
414
|
+
#
|
415
|
+
# All auto-registered components are registered in block form.
|
416
|
+
#
|
417
|
+
# When `memoize` is true, the component will be memoized upon first resolution and the same
|
418
|
+
# object returned on all subsequent resolutions, meaning the block is only called once.
|
419
|
+
# Otherwise, the block will be called and a new object returned on every resolution.
|
420
|
+
#
|
421
|
+
# @param key [String] the component's key
|
422
|
+
# @param memoize [Boolean]
|
423
|
+
# @yieldreturn [Object] the object to register as the component
|
424
|
+
#
|
425
|
+
# @overload reigster(key, call: true, &block)
|
426
|
+
# Registers the given block as the component. When `call: false` is given, then the block
|
427
|
+
# itself will become the component.
|
428
|
+
#
|
429
|
+
# When such a component is resolved, the block will not be called, and instead the `Proc`
|
430
|
+
# object for that block will be returned.
|
431
|
+
#
|
432
|
+
# @param key [String] the component's key
|
433
|
+
# @param call [Booelan]
|
434
|
+
#
|
435
|
+
# @return [container]
|
436
|
+
#
|
437
|
+
# @see #[]
|
438
|
+
# @see #resolve
|
439
|
+
#
|
440
|
+
# @api public
|
441
|
+
# @since 2.0.0
|
144
442
|
def register(...)
|
145
443
|
container.register(...)
|
146
444
|
end
|
147
445
|
|
446
|
+
# @overload register_provider(name, namespace: nil, from: nil, source: nil, if: true, &block)
|
447
|
+
# Registers a provider and its lifecycle hooks.
|
448
|
+
#
|
449
|
+
# In most cases, you should call this from a dedicated file for the provider in your app or
|
450
|
+
# slice's `config/providers/` dir. This allows the provider to be loaded when individual
|
451
|
+
# matching components are resolved (for prepared slices) or when slices are booted.
|
452
|
+
#
|
453
|
+
# @example Simple provider
|
454
|
+
# # config/providers/db.rb
|
455
|
+
# Hanami.app.register_provider(:db) do
|
456
|
+
# start do
|
457
|
+
# require "db"
|
458
|
+
# register("db", DB.new)
|
459
|
+
# end
|
460
|
+
# end
|
461
|
+
#
|
462
|
+
# @example Provider with lifecycle steps, also using dependencies from the target container
|
463
|
+
# # config/providers/db.rb
|
464
|
+
# Hanami.app.register_provider(:db) do
|
465
|
+
# prepare do
|
466
|
+
# require "db"
|
467
|
+
# db = DB.new(target_container["settings"].database_url)
|
468
|
+
# register("db", db)
|
469
|
+
# end
|
470
|
+
#
|
471
|
+
# start do
|
472
|
+
# container["db"].establish_connection
|
473
|
+
# end
|
474
|
+
#
|
475
|
+
# stop do
|
476
|
+
# container["db"].close_connection
|
477
|
+
# end
|
478
|
+
# end
|
479
|
+
#
|
480
|
+
# @example Probvider registration under a namespace
|
481
|
+
# # config/providers/db.rb
|
482
|
+
# Hanami.app.register_provider(:persistence, namespace: true) do
|
483
|
+
# start do
|
484
|
+
# require "db"
|
485
|
+
#
|
486
|
+
# # Namespace option above means this will be registered as "persistence.db"
|
487
|
+
# register("db", DB.new)
|
488
|
+
# end
|
489
|
+
# end
|
490
|
+
#
|
491
|
+
# @param name [Symbol] the unique name for the provider
|
492
|
+
# @param namespace [Boolean, String, nil] register components from the provider with given
|
493
|
+
# namespace. May be an explicit string, or `true` for the namespace to be the provider's
|
494
|
+
# name
|
495
|
+
# @param from [Symbol, nil] the group for an external provider source to use, with the
|
496
|
+
# provider source name inferred from `name` or passsed explicitly as `source:`
|
497
|
+
# @param source [Symbol, nil] the name of the external provider source to use, if different
|
498
|
+
# from the value provided as `name`
|
499
|
+
# @param if [Boolean] a boolean-returning expression to determine whether to register the
|
500
|
+
# provider
|
501
|
+
#
|
502
|
+
# @return [container]
|
503
|
+
#
|
504
|
+
# @api public
|
505
|
+
# @since 2.0.0
|
148
506
|
def register_provider(...)
|
149
507
|
container.register_provider(...)
|
150
508
|
end
|
151
509
|
|
510
|
+
# @overload start(provider_name)
|
511
|
+
# Starts a provider.
|
512
|
+
#
|
513
|
+
# This triggers the provider's `prepare` and `start` lifecycle steps.
|
514
|
+
#
|
515
|
+
# @example
|
516
|
+
# MySlice::Slice.start(:persistence)
|
517
|
+
#
|
518
|
+
# @param provider_name [Symbol] the name of the provider to start
|
519
|
+
#
|
520
|
+
# @return [container]
|
521
|
+
#
|
522
|
+
# @api public
|
523
|
+
# @since 2.0.0
|
152
524
|
def start(...)
|
153
525
|
container.start(...)
|
154
526
|
end
|
155
527
|
|
528
|
+
# @overload stop(provider_name)
|
529
|
+
# Stops a provider.
|
530
|
+
#
|
531
|
+
# This triggers the provider's `stop` lifecycle hook.
|
532
|
+
#
|
533
|
+
# @example
|
534
|
+
# MySlice::Slice.stop(:persistence)
|
535
|
+
#
|
536
|
+
# @param provider_name [Symbol] the name of the provider to start
|
537
|
+
#
|
538
|
+
# @return [container]
|
539
|
+
#
|
540
|
+
# @api public
|
541
|
+
# @since 2.0.0
|
542
|
+
def stop(...)
|
543
|
+
container.stop(...)
|
544
|
+
end
|
545
|
+
|
546
|
+
# @overload key?(key)
|
547
|
+
# Returns true if the component with the given key is registered in the container.
|
548
|
+
#
|
549
|
+
# For a prepared slice, calling `key?` will also try to load the component if not loaded
|
550
|
+
# already.
|
551
|
+
#
|
552
|
+
# @param key [String, Symbol] the component key
|
553
|
+
#
|
554
|
+
# @return [Boolean]
|
555
|
+
#
|
556
|
+
# @api public
|
557
|
+
# @since 2.0.0
|
156
558
|
def key?(...)
|
157
559
|
container.key?(...)
|
158
560
|
end
|
159
561
|
|
562
|
+
# Returns an array of keys for all currently registered components in the container.
|
563
|
+
#
|
564
|
+
# For a prepared slice, this will be the set of components that have been previously resolved.
|
565
|
+
# For a booted slice, this will be all components available for the slice.
|
566
|
+
#
|
567
|
+
# @return [Array<String>]
|
568
|
+
#
|
569
|
+
# @api public
|
570
|
+
# @since 2.0.0
|
160
571
|
def keys
|
161
572
|
container.keys
|
162
573
|
end
|
163
574
|
|
575
|
+
# @overload [](key)
|
576
|
+
# Resolves the component with the given key from the container.
|
577
|
+
#
|
578
|
+
# For a prepared slice, this will attempt to load and register the matching component if it
|
579
|
+
# is not loaded already. For a booted slice, this will return from already registered
|
580
|
+
# components only.
|
581
|
+
#
|
582
|
+
# @return [Object] the resolved component's object
|
583
|
+
#
|
584
|
+
# @raise Dry::Container::KeyError if the component could not be found or loaded
|
585
|
+
#
|
586
|
+
# @see #resolve
|
587
|
+
#
|
588
|
+
# @api public
|
589
|
+
# @since 2.0.0
|
164
590
|
def [](...)
|
165
591
|
container.[](...)
|
166
592
|
end
|
167
593
|
|
594
|
+
# @see #[]
|
595
|
+
#
|
596
|
+
# @api public
|
597
|
+
# @since 2.0.0
|
168
598
|
def resolve(...)
|
169
599
|
container.resolve(...)
|
170
600
|
end
|
171
601
|
|
602
|
+
# Specifies the components to export from the slice.
|
603
|
+
#
|
604
|
+
# Slices importing from this slice can import the specified components only.
|
605
|
+
#
|
606
|
+
# @example
|
607
|
+
# module MySlice
|
608
|
+
# class Slice < Hanami::Slice
|
609
|
+
# export ["search", "index_entity"]
|
610
|
+
# end
|
611
|
+
# end
|
612
|
+
#
|
613
|
+
# @param keys [Array<String>] the component keys to export
|
614
|
+
#
|
615
|
+
# @return [self]
|
616
|
+
#
|
617
|
+
# @api public
|
618
|
+
# @since 2.0.0
|
172
619
|
def export(keys)
|
173
620
|
container.config.exports = keys
|
621
|
+
self
|
174
622
|
end
|
175
623
|
|
624
|
+
# @overload import(from:, as: nil, keys: nil)
|
625
|
+
# Specifies components to import from another slice.
|
626
|
+
#
|
627
|
+
# Booting a slice will register all imported components. For a prepared slice, these
|
628
|
+
# components will be be imported automatically when resolved.
|
629
|
+
#
|
630
|
+
# @example
|
631
|
+
# module MySlice
|
632
|
+
# class Slice < Hanami:Slice
|
633
|
+
# # Component from Search::Slice will import as "search.index_entity"
|
634
|
+
# import keys: ["index_entity"], from: :search
|
635
|
+
# end
|
636
|
+
# end
|
637
|
+
#
|
638
|
+
# @example Other import variations
|
639
|
+
# # Different key namespace: component will be "search_backend.index_entity"
|
640
|
+
# import keys: ["index_entity"], from: :search, as: "search_backend"
|
641
|
+
#
|
642
|
+
# # Import to root key namespace: component will be "index_entity"
|
643
|
+
# import keys: ["index_entity"], from: :search, as: nil
|
644
|
+
#
|
645
|
+
# # Import all components
|
646
|
+
# import from: :search
|
647
|
+
#
|
648
|
+
# @param keys [Array<String>, nil] Array of component keys to import. To import all
|
649
|
+
# available components, omit this argument.
|
650
|
+
# @param from [Symbol] name of the slice to import from
|
651
|
+
# @param as [Symbol, String, nil]
|
652
|
+
#
|
653
|
+
# @see #export
|
654
|
+
#
|
655
|
+
# @api public
|
656
|
+
# @since 2.0.0
|
176
657
|
def import(from:, **kwargs)
|
177
|
-
# TODO: This should be handled via dry-system (see dry-rb/dry-system#228)
|
178
|
-
raise "Cannot import after booting" if booted?
|
179
|
-
|
180
658
|
slice = self
|
181
659
|
|
182
660
|
container.after(:configure) do
|
@@ -191,16 +669,51 @@ module Hanami
|
|
191
669
|
end
|
192
670
|
end
|
193
671
|
|
672
|
+
# Returns the slice's settings, or nil if no settings are defined.
|
673
|
+
#
|
674
|
+
# You can define your settings in `config/settings.rb`.
|
675
|
+
#
|
676
|
+
# @return [Hanami::Settings, nil]
|
677
|
+
#
|
678
|
+
# @see Hanami::Settings
|
679
|
+
#
|
680
|
+
# @api public
|
681
|
+
# @since 2.0.0
|
194
682
|
def settings
|
195
683
|
return @settings if instance_variable_defined?(:@settings)
|
196
684
|
|
197
685
|
@settings = Settings.load_for_slice(self)
|
198
686
|
end
|
199
687
|
|
688
|
+
# Returns the slice's routes, or nil if no routes are defined.
|
689
|
+
#
|
690
|
+
# You can define your routes in `config/routes.rb`.
|
691
|
+
#
|
692
|
+
# @return [Hanami::Routes, nil]
|
693
|
+
#
|
694
|
+
# @see Hanami::Routes
|
695
|
+
#
|
696
|
+
# @api public
|
697
|
+
# @since 2.0.0
|
200
698
|
def routes
|
201
699
|
@routes ||= load_routes
|
202
700
|
end
|
203
701
|
|
702
|
+
# Returns the slice's router, if or nil if no routes are defined.
|
703
|
+
#
|
704
|
+
# An optional `inspector`, implementing the `Hanami::Router::Inspector` interface, may be
|
705
|
+
# provided at first call (the router is then memoized for subsequent accesses). An inspector
|
706
|
+
# is used by the `hanami routes` CLI comment to provide a list of available routes.
|
707
|
+
#
|
708
|
+
# The returned router is a {Slice::Router}, which provides all `Hanami::Router` functionality,
|
709
|
+
# with the addition of support for slice mounting with the {Slice::Router#slice}.
|
710
|
+
#
|
711
|
+
# @param inspector [Hanami::Router::Inspector, nil] an optional routes inspector
|
712
|
+
#
|
713
|
+
# @return [Hanami::Slice::Router, nil]
|
714
|
+
#
|
715
|
+
# @api public
|
716
|
+
# @since 2.0.0
|
204
717
|
def router(inspector: nil)
|
205
718
|
raise SliceLoadError, "#{self} must be prepared before loading the router" unless prepared?
|
206
719
|
|
@@ -209,12 +722,38 @@ module Hanami
|
|
209
722
|
end
|
210
723
|
end
|
211
724
|
|
725
|
+
# Returns a [Rack][rack] app for the slice, or nil if no routes are defined.
|
726
|
+
#
|
727
|
+
# The rack app will be memoized on first access.
|
728
|
+
#
|
729
|
+
# [rack]: https://github.com/rack/rack
|
730
|
+
#
|
731
|
+
# @return [#call, nil] the rack app, or nil if no routes are defined
|
732
|
+
#
|
733
|
+
# @see #routes
|
734
|
+
# @see #router
|
735
|
+
#
|
736
|
+
# @api public
|
737
|
+
# @since 2.0.0
|
212
738
|
def rack_app
|
213
739
|
return unless router
|
214
740
|
|
215
741
|
@rack_app ||= router.to_rack_app
|
216
742
|
end
|
217
743
|
|
744
|
+
# @overload call(rack_env)
|
745
|
+
# Calls the slice's [Rack][rack] app and returns a Rack-compatible response object
|
746
|
+
#
|
747
|
+
# [rack]: https://github.com/rack/rack
|
748
|
+
#
|
749
|
+
# @param rack_env [Hash] the Rack environment for the request
|
750
|
+
#
|
751
|
+
# @return [Array] the three-element Rack response array
|
752
|
+
#
|
753
|
+
# @see #rack_app
|
754
|
+
#
|
755
|
+
# @api public
|
756
|
+
# @since 2.0.0
|
218
757
|
def call(...)
|
219
758
|
rack_app.call(...)
|
220
759
|
end
|
@@ -418,7 +957,7 @@ module Hanami
|
|
418
957
|
**config.router.options
|
419
958
|
) do
|
420
959
|
use(rack_monitor)
|
421
|
-
use(*config.sessions.middleware) if config.sessions.enabled?
|
960
|
+
use(*config.actions.sessions.middleware) if config.actions.sessions.enabled?
|
422
961
|
|
423
962
|
middleware_stack.update(config.middleware_stack)
|
424
963
|
end
|