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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -0
  3. data/hanami.gemspec +8 -7
  4. data/lib/hanami/app.rb +47 -36
  5. data/lib/hanami/assets/app_config.rb +7 -15
  6. data/lib/hanami/assets/config.rb +5 -6
  7. data/lib/hanami/config/actions/content_security_policy.rb +1 -1
  8. data/lib/hanami/config/actions/cookies.rb +27 -0
  9. data/lib/hanami/config/actions/sessions.rb +42 -5
  10. data/lib/hanami/config/actions.rb +81 -17
  11. data/lib/hanami/config/logger.rb +112 -23
  12. data/lib/hanami/config/router.rb +0 -1
  13. data/lib/hanami/config/views.rb +6 -10
  14. data/lib/hanami/config.rb +235 -73
  15. data/lib/hanami/constants.rb +4 -0
  16. data/lib/hanami/errors.rb +17 -0
  17. data/lib/hanami/extensions/action/slice_configured_action.rb +9 -5
  18. data/lib/hanami/extensions/action.rb +59 -7
  19. data/lib/hanami/extensions/view/context.rb +3 -4
  20. data/lib/hanami/extensions/view/slice_configured_view.rb +4 -4
  21. data/lib/hanami/extensions/view.rb +7 -5
  22. data/lib/hanami/providers/inflector.rb +6 -0
  23. data/lib/hanami/providers/logger.rb +8 -0
  24. data/lib/hanami/providers/rack.rb +12 -0
  25. data/lib/hanami/providers/routes.rb +14 -4
  26. data/lib/hanami/routes.rb +36 -1
  27. data/lib/hanami/settings/env_store.rb +1 -1
  28. data/lib/hanami/settings.rb +102 -36
  29. data/lib/hanami/slice/router.rb +38 -16
  30. data/lib/hanami/slice/routing/middleware/stack.rb +66 -42
  31. data/lib/hanami/slice/routing/resolver.rb +10 -17
  32. data/lib/hanami/slice/view_name_inferrer.rb +1 -1
  33. data/lib/hanami/slice.rb +553 -14
  34. data/lib/hanami/slice_registrar.rb +20 -15
  35. data/lib/hanami/version.rb +2 -3
  36. data/lib/hanami/web/rack_logger.rb +14 -4
  37. data/lib/hanami.rb +122 -23
  38. data/spec/integration/action/csrf_protection_spec.rb +1 -1
  39. data/spec/integration/container/application_routes_helper_spec.rb +3 -1
  40. data/spec/integration/container/provider_lifecycle_spec.rb +61 -0
  41. data/spec/integration/container/standard_providers/rack_provider_spec.rb +44 -0
  42. data/spec/integration/container/{standard_bootable_components_spec.rb → standard_providers_spec.rb} +3 -3
  43. data/spec/integration/rack_app/body_parser_spec.rb +3 -0
  44. data/spec/integration/rack_app/middleware_spec.rb +427 -3
  45. data/spec/integration/rack_app/non_booted_rack_app_spec.rb +2 -1
  46. data/spec/integration/rack_app/rack_app_spec.rb +39 -11
  47. data/spec/integration/setup_spec.rb +4 -4
  48. data/spec/integration/slices/external_slice_spec.rb +2 -1
  49. data/spec/integration/slices/slice_configuration_spec.rb +3 -1
  50. data/spec/integration/slices/slice_loading_spec.rb +4 -4
  51. data/spec/integration/slices/slice_routing_spec.rb +4 -3
  52. data/spec/integration/slices_spec.rb +100 -0
  53. data/spec/isolation/hanami/boot/success_spec.rb +1 -1
  54. data/spec/support/app_integration.rb +2 -10
  55. data/spec/unit/hanami/config/actions/content_security_policy_spec.rb +7 -7
  56. data/spec/unit/hanami/config/actions/default_values_spec.rb +1 -1
  57. data/spec/unit/hanami/config/actions/sessions_spec.rb +1 -3
  58. data/spec/unit/hanami/config/actions_spec.rb +1 -12
  59. data/spec/unit/hanami/config/logger_spec.rb +38 -55
  60. data/spec/unit/hanami/config/router_spec.rb +1 -1
  61. data/spec/unit/hanami/config/views_spec.rb +3 -13
  62. data/spec/unit/hanami/settings_spec.rb +1 -1
  63. data/spec/unit/hanami/slice_configurable_spec.rb +5 -5
  64. data/spec/unit/hanami/slice_spec.rb +32 -0
  65. data/spec/unit/hanami/version_spec.rb +1 -1
  66. data/spec/unit/hanami/web/rack_logger_spec.rb +13 -2
  67. metadata +54 -45
  68. data/lib/hanami/config/sessions.rb +0 -50
  69. 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
- attr_reader :parent, :autoloader, :container
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
- # A slice's config is copied from the app config at time of first access. The app should have
61
- # its config completed before slices are loaded.
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
- # Remove specific values from app that will not apply to this slice
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