hanami 2.0.0.beta3 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +39 -0
  3. data/hanami.gemspec +9 -8
  4. data/lib/hanami/app.rb +50 -39
  5. data/lib/hanami/assets/app_config.rb +61 -0
  6. data/lib/hanami/assets/{configuration.rb → config.rb} +9 -10
  7. data/lib/hanami/{configuration → config}/actions/content_security_policy.rb +3 -3
  8. data/lib/hanami/config/actions/cookies.rb +57 -0
  9. data/lib/hanami/config/actions/sessions.rb +83 -0
  10. data/lib/hanami/config/actions.rb +164 -0
  11. data/lib/hanami/config/logger.rb +176 -0
  12. data/lib/hanami/config/null_config.rb +14 -0
  13. data/lib/hanami/{configuration → config}/router.rb +8 -9
  14. data/lib/hanami/{configuration → config}/views.rb +16 -20
  15. data/lib/hanami/config.rb +396 -0
  16. data/lib/hanami/constants.rb +4 -0
  17. data/lib/hanami/errors.rb +20 -0
  18. data/lib/hanami/extensions/action/slice_configured_action.rb +10 -6
  19. data/lib/hanami/extensions/action.rb +59 -7
  20. data/lib/hanami/extensions/view/context.rb +3 -4
  21. data/lib/hanami/extensions/view/slice_configured_view.rb +4 -4
  22. data/lib/hanami/extensions/view.rb +7 -5
  23. data/lib/hanami/providers/inflector.rb +6 -2
  24. data/lib/hanami/providers/logger.rb +9 -3
  25. data/lib/hanami/providers/rack.rb +12 -2
  26. data/lib/hanami/providers/routes.rb +14 -6
  27. data/lib/hanami/routes.rb +36 -1
  28. data/lib/hanami/settings/env_store.rb +4 -4
  29. data/lib/hanami/settings.rb +169 -21
  30. data/lib/hanami/slice/router.rb +38 -16
  31. data/lib/hanami/slice/routing/middleware/stack.rb +108 -40
  32. data/lib/hanami/slice/routing/resolver.rb +10 -17
  33. data/lib/hanami/slice/view_name_inferrer.rb +1 -1
  34. data/lib/hanami/slice.rb +605 -51
  35. data/lib/hanami/slice_configurable.rb +1 -1
  36. data/lib/hanami/slice_registrar.rb +25 -14
  37. data/lib/hanami/version.rb +2 -3
  38. data/lib/hanami/web/rack_logger.rb +14 -4
  39. data/lib/hanami.rb +122 -24
  40. data/spec/integration/action/csrf_protection_spec.rb +1 -1
  41. data/spec/integration/container/application_routes_helper_spec.rb +3 -1
  42. data/spec/integration/container/prepare_container_spec.rb +2 -0
  43. data/spec/integration/container/provider_lifecycle_spec.rb +61 -0
  44. data/spec/integration/container/standard_providers/rack_provider_spec.rb +44 -0
  45. data/spec/integration/container/{standard_bootable_components_spec.rb → standard_providers_spec.rb} +3 -3
  46. data/spec/integration/rack_app/body_parser_spec.rb +111 -0
  47. data/spec/integration/rack_app/middleware_spec.rb +455 -3
  48. data/spec/integration/rack_app/non_booted_rack_app_spec.rb +2 -1
  49. data/spec/integration/rack_app/rack_app_spec.rb +39 -11
  50. data/spec/integration/settings/access_in_slice_class_body_spec.rb +82 -0
  51. data/spec/integration/settings/access_to_constants_spec.rb +23 -146
  52. data/spec/integration/{slices/slice_settings_spec.rb → settings/slice_registration_spec.rb} +5 -1
  53. data/spec/integration/settings/using_types_spec.rb +4 -11
  54. data/spec/integration/setup_spec.rb +4 -4
  55. data/spec/integration/slices/external_slice_spec.rb +2 -1
  56. data/spec/integration/slices/slice_configuration_spec.rb +3 -1
  57. data/spec/integration/slices/slice_loading_spec.rb +4 -4
  58. data/spec/integration/slices/slice_routing_spec.rb +4 -3
  59. data/spec/integration/slices_spec.rb +100 -0
  60. data/spec/isolation/hanami/boot/success_spec.rb +1 -1
  61. data/spec/support/app_integration.rb +10 -15
  62. data/spec/unit/hanami/{configuration → config}/actions/content_security_policy_spec.rb +16 -16
  63. data/spec/unit/hanami/{configuration → config}/actions/cookies_spec.rb +6 -6
  64. data/spec/unit/hanami/{configuration → config}/actions/csrf_protection_spec.rb +12 -12
  65. data/spec/unit/hanami/config/actions/default_values_spec.rb +54 -0
  66. data/spec/unit/hanami/{configuration → config}/actions/sessions_spec.rb +6 -8
  67. data/spec/unit/hanami/{configuration → config}/actions_spec.rb +8 -20
  68. data/spec/unit/hanami/{configuration → config}/base_url_spec.rb +2 -2
  69. data/spec/unit/hanami/{configuration → config}/inflector_spec.rb +2 -2
  70. data/spec/unit/hanami/{configuration → config}/logger_spec.rb +42 -59
  71. data/spec/unit/hanami/{configuration → config}/router_spec.rb +7 -8
  72. data/spec/unit/hanami/{configuration → config}/slices_spec.rb +2 -2
  73. data/spec/unit/hanami/{configuration → config}/views_spec.rb +13 -24
  74. data/spec/unit/hanami/settings_spec.rb +65 -10
  75. data/spec/unit/hanami/slice_configurable_spec.rb +21 -2
  76. data/spec/unit/hanami/slice_spec.rb +32 -0
  77. data/spec/unit/hanami/version_spec.rb +1 -1
  78. data/spec/unit/hanami/web/rack_logger_spec.rb +13 -2
  79. metadata +100 -76
  80. data/lib/hanami/assets/app_configuration.rb +0 -69
  81. data/lib/hanami/configuration/actions/cookies.rb +0 -29
  82. data/lib/hanami/configuration/actions/sessions.rb +0 -46
  83. data/lib/hanami/configuration/actions.rb +0 -101
  84. data/lib/hanami/configuration/logger.rb +0 -87
  85. data/lib/hanami/configuration/null_configuration.rb +0 -14
  86. data/lib/hanami/configuration/sessions.rb +0 -50
  87. data/lib/hanami/configuration.rb +0 -234
  88. data/lib/hanami/providers/settings.rb +0 -98
  89. data/spec/unit/hanami/configuration/actions/default_values_spec.rb +0 -52
  90. data/spec/unit/hanami/configuration_spec.rb +0 -43
@@ -0,0 +1,176 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/configurable"
4
+ require "dry/logger"
5
+
6
+ module Hanami
7
+ class Config
8
+ # Hanami logger config
9
+ #
10
+ # @api public
11
+ # @since 2.0.0
12
+ class Logger
13
+ include Dry::Configurable
14
+
15
+ # @return [Hanami::SliceName]
16
+ #
17
+ # @api private
18
+ # @since 2.0.o
19
+ attr_reader :app_name
20
+
21
+ # @!attribute [rw] level
22
+ # Sets or returns the logger level.
23
+ #
24
+ # Defaults to `:info` for the production environment and `:debug` for all others.
25
+ #
26
+ # @return [Symbol]
27
+ #
28
+ # @api public
29
+ # @since 2.0.0
30
+ setting :level
31
+
32
+ # @!attribute [rw] stream
33
+ # Sets or returns the logger's stream.
34
+ #
35
+ # This can be a file path or an `IO`-like object for the logger to write to.
36
+ #
37
+ # Defaults to `"log/test.log"` for the test environment and `$stdout` for all others.
38
+ #
39
+ # @return [String, #write]
40
+ #
41
+ # @api public
42
+ # @since 2.0.0
43
+ setting :stream
44
+
45
+ # @!attribute [rw] formatter
46
+ # Sets or returns the logger's formatter.
47
+ #
48
+ # This may be a name that matches a formatter registered with `Dry::Logger`, which includes
49
+ # `:string`, `:rack` and `:json`.
50
+ #
51
+ # This may also be an instance of Ruby's built-in `::Logger::Formatter` or any compatible
52
+ # object.
53
+ #
54
+ # Defaults to `:json` for the production environment, and `:rack` for all others.
55
+ #
56
+ # @return [Symbol, ::Logger::Formatter]
57
+ #
58
+ # @api public
59
+ # @since 2.0.0
60
+ setting :formatter
61
+
62
+ # @!attribute [rw] template
63
+ # Sets or returns log entry string template
64
+ #
65
+ # Defaults to `false`.
66
+ #
67
+ # @return [Boolean]
68
+ #
69
+ # @api public
70
+ # @since 2.0.0
71
+ setting :template, default: "[%<progname>s] [%<severity>s] [%<time>s] %<message>s"
72
+
73
+ # @!attribute [rw] filters
74
+ # Sets or returns an array of attribute names to filter from logs.
75
+ #
76
+ # Defaults to `["_csrf", "password", "password_confirmation"]`. If you want to preserve
77
+ # these defaults, append to this array rather than reassigning it.
78
+ #
79
+ # @return [Array<String>]
80
+ #
81
+ # @api public
82
+ # @since 2.0.0
83
+ setting :filters, default: %w[_csrf password password_confirmation].freeze
84
+
85
+ # @!attribute [rw] logger_constructor
86
+ # Sets or returns the constructor proc to use for the logger instantiation.
87
+ #
88
+ # Defaults to `Dry.method(:Logger)`.
89
+ #
90
+ # @api public
91
+ # @since 2.0.0
92
+ setting :logger_constructor, default: Dry.method(:Logger)
93
+
94
+ # @!attribute [rw] options
95
+ # Sets or returns a hash of options to pass to the {logger_constructor} when initializing
96
+ # the logger.
97
+ #
98
+ # Defaults to `[]`
99
+ #
100
+ # @return [Hash]
101
+ #
102
+ # @api public
103
+ # @since 2.0.0
104
+ setting :options, default: {}
105
+
106
+ # Returns a new `Logger` config.
107
+ #
108
+ # You should not need to initialize this directly, instead use {Hanami::Config#logger}.
109
+ #
110
+ # @param env [Symbol] the Hanami env
111
+ # @param app_name [Hanami::SliceName]
112
+ #
113
+ # @api private
114
+ def initialize(env:, app_name:)
115
+ @app_name = app_name
116
+
117
+ config.level = case env
118
+ when :production
119
+ :info
120
+ else
121
+ :debug
122
+ end
123
+
124
+ config.stream = case env
125
+ when :test
126
+ File.join("log", "#{env}.log")
127
+ else
128
+ $stdout
129
+ end
130
+
131
+ config.formatter = case env
132
+ when :production
133
+ :json
134
+ else
135
+ :rack
136
+ end
137
+ end
138
+
139
+ # Returns a new instance of the logger.
140
+ #
141
+ # @return [logger_class]
142
+ #
143
+ # @api public
144
+ # @since 2.0.0
145
+ def instance
146
+ logger_constructor.call(app_name.name, **logger_constructor_opts)
147
+ end
148
+
149
+ private
150
+
151
+ # @api private
152
+ def logger_constructor_opts
153
+ {stream: stream,
154
+ level: level,
155
+ formatter: formatter,
156
+ filters: filters,
157
+ template: template,
158
+ **options}
159
+ end
160
+
161
+ # @api private
162
+ def method_missing(name, *args, &block)
163
+ if config.respond_to?(name)
164
+ config.public_send(name, *args, &block)
165
+ else
166
+ super
167
+ end
168
+ end
169
+
170
+ # @api private
171
+ def respond_to_missing?(name, _incude_all = false)
172
+ config.respond_to?(name) || super
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/configurable"
4
+
5
+ module Hanami
6
+ class Config
7
+ # NullConfig can serve as a fallback config object when out-of-gem config objects are not
8
+ # available (specifically, when the hanami-controller, hanami-router or hanami-view gems are not
9
+ # loaded)
10
+ class NullConfig
11
+ include Dry::Configurable
12
+ end
13
+ end
14
+ end
@@ -1,25 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "dry/configurable"
4
- require_relative "../slice/routing/resolver"
5
4
 
6
5
  module Hanami
7
- class Configuration
8
- # Hanami router configuration
6
+ class Config
7
+ # Hanami router config
9
8
  #
10
9
  # @since 2.0.0
11
10
  # @api private
12
11
  class Router
13
12
  include Dry::Configurable
14
13
 
15
- # Base configuration is provided so router config can include the `base_url`
16
- attr_reader :base_configuration
17
- private :base_configuration
14
+ # Base config is provided so router config can include the `base_url`
15
+ attr_reader :base_config
16
+ private :base_config
18
17
 
19
18
  # @api private
20
19
  # @since 2.0.0
21
- def initialize(base_configuration)
22
- @base_configuration = base_configuration
20
+ def initialize(base_config)
21
+ @base_config = base_config
23
22
  end
24
23
 
25
24
  setting :resolver, default: Slice::Routing::Resolver
@@ -27,7 +26,7 @@ module Hanami
27
26
  # @api private
28
27
  # @since 2.0.0
29
28
  def options
30
- {base_url: base_configuration.base_url}
29
+ {base_url: base_config.base_url}
31
30
  end
32
31
 
33
32
  private
@@ -4,45 +4,41 @@ require "dry/configurable"
4
4
  require "hanami/view"
5
5
 
6
6
  module Hanami
7
- class Configuration
8
- # Hanami actions configuration
7
+ class Config
8
+ # Hanami views config
9
9
  #
10
- # @since 2.0.0
10
+ # This is NOT RELEASED as of 2.0.0.
11
+ #
12
+ # @api private
11
13
  class Views
12
14
  include Dry::Configurable
13
15
 
14
16
  setting :parts_path, default: "views/parts"
15
17
 
16
- attr_reader :base_configuration
17
- protected :base_configuration
18
+ attr_reader :base_config
19
+ protected :base_config
18
20
 
21
+ # @api private
19
22
  def initialize(*)
20
23
  super
21
24
 
22
- @base_configuration = Hanami::View.config.dup
25
+ @base_config = Hanami::View.config.dup
23
26
 
24
27
  configure_defaults
25
28
  end
26
29
 
30
+ # @api private
27
31
  def initialize_copy(source)
28
32
  super
29
- @base_configuration = source.base_configuration.dup
33
+ @base_config = source.base_config.dup
30
34
  end
35
+ private :initialize_copy
31
36
 
32
- # Returns the list of available settings
33
- #
34
- # @return [Set]
35
- #
36
- # @since 2.0.0
37
37
  # @api private
38
- def settings
39
- self.class.settings + View.settings - NON_FORWARDABLE_METHODS
40
- end
41
-
42
38
  def finalize!
43
39
  return self if frozen?
44
40
 
45
- base_configuration.finalize!
41
+ base_config.finalize!
46
42
 
47
43
  super
48
44
  end
@@ -69,8 +65,8 @@ module Hanami
69
65
 
70
66
  if config.respond_to?(name)
71
67
  config.public_send(name, *args, &block)
72
- elsif base_configuration.respond_to?(name)
73
- base_configuration.public_send(name, *args, &block)
68
+ elsif base_config.respond_to?(name)
69
+ base_config.public_send(name, *args, &block)
74
70
  else
75
71
  super
76
72
  end
@@ -79,7 +75,7 @@ module Hanami
79
75
  def respond_to_missing?(name, _include_all = false)
80
76
  return false if NON_FORWARDABLE_METHODS.include?(name)
81
77
 
82
- config.respond_to?(name) || base_configuration.respond_to?(name) || super
78
+ config.respond_to?(name) || base_config.respond_to?(name) || super
83
79
  end
84
80
  end
85
81
  end
@@ -0,0 +1,396 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+ require "pathname"
5
+ require "dry/configurable"
6
+ require "dry/inflector"
7
+
8
+ require_relative "constants"
9
+
10
+ module Hanami
11
+ # Hanami app config
12
+ #
13
+ # @since 2.0.0
14
+ class Config
15
+ include Dry::Configurable
16
+
17
+ # @!attribute [rw] root
18
+ # Sets the root for the app or slice.
19
+ #
20
+ # For the app, this defaults to `Dir.pwd`. For slices detected in `slices/` `config/slices/`,
21
+ # this defaults to `slices/[slice_name]/`.
22
+ #
23
+ # Accepts a string path and will return a `Pathname`.
24
+ #
25
+ # @return [Pathname]
26
+ #
27
+ # @api public
28
+ # @since 2.0.0
29
+ setting :root, constructor: ->(path) { Pathname(path) if path }
30
+
31
+ # @!attribute [rw] inflector
32
+ # Sets the app's inflector.
33
+ #
34
+ # This expects a `Dry::Inflector` (or compatible) inflector instance.
35
+ #
36
+ # To configure custom inflection rules without having to assign a whole inflector, see
37
+ # {#inflections}.
38
+ #
39
+ # @return [Dry::Inflector]
40
+ #
41
+ # @see #inflections
42
+ #
43
+ # @api public
44
+ # @since 2.0.0
45
+ setting :inflector, default: Dry::Inflector.new
46
+
47
+ # @!attribute [rw] settings_store
48
+ # Sets the store used to retrieve {Hanami::Settings} values.
49
+ #
50
+ # Defaults to an instance of {Hanami::Settings::EnvStore}.
51
+ #
52
+ # @return [#fetch]
53
+ #
54
+ # @see Hanami::Settings
55
+ # @see Hanami::Settings::EnvStore#fetch
56
+ #
57
+ # @api public
58
+ # @since 2.0.0
59
+ setting :settings_store, default: Hanami::Settings::EnvStore.new
60
+
61
+ # @!attribute [rw] slices
62
+ # Sets the slices to load when the app is preared or booted.
63
+ #
64
+ # Defaults to `nil`, which will load all slices. Set this to an array of slice names to load
65
+ # only those slices.
66
+ #
67
+ # This attribute is also populated from the `HANAMI_SLICES` environment variable.
68
+ #
69
+ # @example
70
+ # config.slices = ["admin", "search"]
71
+ #
72
+ # @example
73
+ # ENV["HANAMI_SLICES"] # => "admin,search"
74
+ # config.slices # => ["admin", "search"]
75
+ #
76
+ # @return [Array<String>, nil]
77
+ #
78
+ # @api public
79
+ # @since 2.0.0
80
+ setting :slices
81
+
82
+ # @!attribute [rw] shared_app_component_keys
83
+ # Sets the keys for the components to be imported from the app into all other slices.
84
+ #
85
+ # You should append items to this array, since the default shared components are essential for
86
+ # slices to operate within the app.
87
+ #
88
+ # @example
89
+ # config.shared_app_component_keys += ["shared_component_a", "shared_component_b"]
90
+ #
91
+ # @return [Array<String>]
92
+ #
93
+ # @api public
94
+ # @since 2.0.0
95
+ setting :shared_app_component_keys, default: %w[
96
+ inflector
97
+ logger
98
+ notifications
99
+ rack.monitor
100
+ routes
101
+ settings
102
+ ]
103
+
104
+ # @!attribute [rw] no_auto_register_paths
105
+ # Sets the paths to skip from container auto-registration.
106
+ #
107
+ # Defaults to `["entities"]`.
108
+ #
109
+ # @return [Array<String>] array of relative paths
110
+ #
111
+ # @api public
112
+ # @since 2.0.0
113
+ setting :no_auto_register_paths, default: %w[entities]
114
+
115
+ # @!attribute [rw] base_url
116
+ # Sets the base URL for app's web server.
117
+ #
118
+ # This is passed to the {Slice::ClassMethods#router router} and used for generating links.
119
+ #
120
+ # Defaults to `"http://0.0.0.0:2300"`. String values passed are turned into `URI` instances.
121
+ #
122
+ # @return [URI]
123
+ #
124
+ # @see Slice::ClassMethods#router
125
+ #
126
+ # @api public
127
+ # @since 2.0.0
128
+ setting :base_url, default: "http://0.0.0.0:2300", constructor: ->(url) { URI(url) }
129
+
130
+ # Returns the app or slice's {Hanami::SliceName slice_name}.
131
+ #
132
+ # This is useful for default config values that depend on this name.
133
+ #
134
+ # @return [Hanami::SliceName]
135
+ #
136
+ # @api private
137
+ # @since 2.0.0
138
+ attr_reader :app_name
139
+
140
+ # Returns the app's environment.
141
+ #
142
+ # @example
143
+ # config.env # => :development
144
+ #
145
+ # @return [Symbol]
146
+ #
147
+ # @see #environment
148
+ #
149
+ # @api private
150
+ # @since 2.0.0
151
+ attr_reader :env
152
+
153
+ # Returns the app's actions config, or a null config if hanami-controller is not bundled.
154
+ #
155
+ # @example When hanami-controller is bundled
156
+ # config.actions.default_request_format # => :html
157
+ #
158
+ # @example When hanami-controller is not bundled
159
+ # config.actions.default_request_format # => NoMethodError
160
+ #
161
+ # @return [Hanami::Config::Actions, Hanami::Config::NullConfig]
162
+ #
163
+ # @api public
164
+ # @since 2.0.0
165
+ attr_reader :actions
166
+
167
+ # Returns the app's middleware stack, or nil if hanami-router is not bundled.
168
+ #
169
+ # Use this to configure middleware that should apply to all routes.
170
+ #
171
+ # @example
172
+ # config.middleware.use :body_parser, :json
173
+ # config.middleware.use MyCustomMiddleware
174
+ #
175
+ # @return [Hanami::Slice::Routing::Middleware::Stack, nil]
176
+ #
177
+ # @api public
178
+ # @since 2.0.0
179
+ attr_reader :middleware
180
+
181
+ # @api private
182
+ # @since 2.0.0
183
+ alias_method :middleware_stack, :middleware
184
+
185
+ # Returns the app's router config, or a null config if hanami-router is not bundled.
186
+ #
187
+ # @example When hanami-router is bundled
188
+ # config.router.resolver # => Hanami::Slice::Routing::Resolver
189
+ #
190
+ # @example When hanami-router is not bundled
191
+ # config.router.resolver # => NoMethodError
192
+ #
193
+ # @return [Hanami::Config::Router, Hanami::Config::NullConfig]
194
+ #
195
+ # @api public
196
+ # @since 2.0.0
197
+ attr_reader :router
198
+
199
+ # Returns the app's views config, or a null config if hanami-view is not bundled.
200
+ #
201
+ # This is NOT RELEASED as of 2.0.0.
202
+ #
203
+ # @api private
204
+ attr_reader :views
205
+
206
+ # Returns the app's assets config.
207
+ #
208
+ # This is NOT RELEASED as of 2.0.0.
209
+ #
210
+ # @api private
211
+ attr_reader :assets
212
+
213
+ # @api private
214
+ def initialize(app_name:, env:)
215
+ @app_name = app_name
216
+ @env = env
217
+
218
+ # Apply default values that are only knowable at initialize-time (vs require-time)
219
+ self.root = Dir.pwd
220
+ load_from_env
221
+
222
+ @logger = Config::Logger.new(env: env, app_name: app_name)
223
+
224
+ # TODO: Make assets config dependent
225
+ require "hanami/assets/app_config"
226
+ @assets = Hanami::Assets::AppConfig.new
227
+
228
+ @actions = load_dependent_config("hanami-controller") {
229
+ require_relative "config/actions"
230
+ Actions.new
231
+ }
232
+
233
+ @router = load_dependent_config("hanami-router") {
234
+ require_relative "config/router"
235
+ @middleware = Slice::Routing::Middleware::Stack.new
236
+ Router.new(self)
237
+ }
238
+
239
+ @views = load_dependent_config("hanami-view") {
240
+ require_relative "config/views"
241
+ Views.new
242
+ }
243
+
244
+ yield self if block_given?
245
+ end
246
+
247
+ # @api private
248
+ def initialize_copy(source)
249
+ super
250
+
251
+ @app_name = app_name.dup
252
+
253
+ @assets = source.assets.dup
254
+ @actions = source.actions.dup
255
+ @middleware = source.middleware.dup
256
+ @router = source.router.dup.tap do |router|
257
+ router.instance_variable_set(:@base_config, self)
258
+ end
259
+ @views = source.views.dup
260
+ end
261
+ private :initialize_copy
262
+
263
+ # Finalizes the config.
264
+ #
265
+ # This is called when the app or slice is prepared. After this, no further changes to config can
266
+ # be made.
267
+ #
268
+ # @api private
269
+ def finalize!
270
+ # Finalize nested configs
271
+ assets.finalize!
272
+ actions.finalize!
273
+ views.finalize!
274
+ logger.finalize!
275
+ router.finalize!
276
+
277
+ super
278
+ end
279
+
280
+ # Configures the app's custom inflections.
281
+ #
282
+ # You should call this one time only. Subsequent calls will override previously configured
283
+ # inflections.
284
+ #
285
+ # @example
286
+ # config.inflections do |inflections|
287
+ # inflections.acronym "WNBA"
288
+ # end
289
+ #
290
+ # @see https://dry-rb.org/gems/dry-inflector
291
+ #
292
+ # @return [Dry::Inflector] the configured inflector
293
+ #
294
+ # @api public
295
+ # @since 2.0.0
296
+ def inflections(&block)
297
+ self.inflector = Dry::Inflector.new(&block)
298
+ end
299
+
300
+ # Disabling this to permit distinct documentation for `#logger` vs `#logger=`
301
+ #
302
+ # rubocop:disable Style/TrivialAccessors
303
+
304
+ # Returns the logger config.
305
+ #
306
+ # Use this to configure various options for the default `Dry::Logger::Dispatcher` logger instance.
307
+ #
308
+ # @example
309
+ # config.logger.level = :debug
310
+ #
311
+ # @return [Hanami::Config::Logger]
312
+ #
313
+ # @see Hanami::Config::Logger
314
+ #
315
+ # @api public
316
+ # @since 2.0.0
317
+ def logger
318
+ @logger
319
+ end
320
+
321
+ # Sets the app's logger instance.
322
+ #
323
+ # This entirely replaces the default `Dry::Logger::Dispatcher` instance that would have been
324
+ #
325
+ # @see #logger_instance
326
+ #
327
+ # @api public
328
+ # @since 2.0.0
329
+ def logger=(logger_instance)
330
+ @logger_instance = logger_instance
331
+ end
332
+
333
+ # rubocop:enable Style/TrivialAccessors
334
+
335
+ # Returns the configured logger instance.
336
+ #
337
+ # Unless you've replaced the logger with {#logger=}, this returns a `Dry::Logger::Dispatcher` configured
338
+ # with the options configured through {#logger}.
339
+ #
340
+ # This configured logger is registered in all app and slice containers as `"logger"`. For
341
+ # typical usage, you should access the logger via this component, not directly from config.
342
+ #
343
+ # @example Accessing the logger component
344
+ # Hanami.app["logger"] # => #<Dry::Logger::Dispatcher>
345
+ #
346
+ # @example Injecting the logger as a dependency
347
+ # module MyApp
348
+ # class MyClass
349
+ # include Deps["logger"]
350
+ #
351
+ # def my_method
352
+ # logger.info("hello")
353
+ # end
354
+ # end
355
+ # end
356
+ #
357
+ # @return [Dry::Logger::Dispatcher]
358
+ #
359
+ # @see #logger
360
+ # @see Hanami::Config::Logger
361
+ #
362
+ # @api public
363
+ # @since 2.0.0
364
+ def logger_instance
365
+ @logger_instance || logger.instance
366
+ end
367
+
368
+ private
369
+
370
+ def load_from_env
371
+ self.slices = ENV["HANAMI_SLICES"]&.split(",")&.map(&:strip)
372
+ end
373
+
374
+ # @api private
375
+ def load_dependent_config(gem_name)
376
+ if Hanami.bundled?(gem_name)
377
+ yield
378
+ else
379
+ require_relative "config/null_config"
380
+ NullConfig.new
381
+ end
382
+ end
383
+
384
+ def method_missing(name, *args, &block)
385
+ if config.respond_to?(name)
386
+ config.public_send(name, *args, &block)
387
+ else
388
+ super
389
+ end
390
+ end
391
+
392
+ def respond_to_missing?(name, _incude_all = false)
393
+ config.respond_to?(name) || super
394
+ end
395
+ end
396
+ end
@@ -13,6 +13,10 @@ module Hanami
13
13
  PATH_DELIMITER = "/"
14
14
  private_constant :PATH_DELIMITER
15
15
 
16
+ # @api private
17
+ APP_PATH = "config/app.rb"
18
+ private_constant :APP_PATH
19
+
16
20
  # @api private
17
21
  CONFIG_DIR = "config"
18
22
  private_constant :CONFIG_DIR