hanami 2.0.0.alpha4 → 2.0.0.alpha5
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 +120 -0
- data/README.md +1 -1
- data/hanami.gemspec +1 -1
- data/lib/hanami/application/container/boot/rack_logger.rb +1 -1
- data/lib/hanami/application/router.rb +7 -7
- data/lib/hanami/application/routing/router.rb +36 -0
- data/lib/hanami/application.rb +68 -79
- data/lib/hanami/boot/source_dirs.rb +44 -0
- data/lib/hanami/configuration/logger.rb +49 -5
- data/lib/hanami/configuration/source_dirs.rb +42 -0
- data/lib/hanami/configuration.rb +20 -6
- data/lib/hanami/slice.rb +46 -24
- data/lib/hanami/version.rb +1 -1
- data/lib/hanami.rb +4 -22
- metadata +10 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9c8875d3320057cffe3af1a7bb2ff781cd8ad2145c446fc9e9190d344a4a48e6
|
4
|
+
data.tar.gz: c003bc2117815e10f2c15f458fb3bc6d94b480dfe9f2ec98e6458804f8a0d06d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7b133de3c728132ef6255480b10068482d58cf1e2708df395f00cc5981cdccac70cbecdb2c8325cd822298d7c92c0ee0253ab1f8f9d95ddf84b0d6de556e7f3f
|
7
|
+
data.tar.gz: 42b525e3163e7bb73938b5e2fa444ccc15cc38def3e74225086f0e90bb0d805979e0a88a47703fcc73956d68598260ab366a1c155eb94b7114515b8ffc56671e
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,126 @@
|
|
1
1
|
# Hanami
|
2
2
|
The web, with simplicity.
|
3
3
|
|
4
|
+
## v2.0.0.alpha5 - 2022-01-12
|
5
|
+
### Changed
|
6
|
+
- [Luca Guidi] Sensible default configuration for application logger, with per-environment defaults:
|
7
|
+
|
8
|
+
The defaults are:
|
9
|
+
|
10
|
+
- In **production**, log for level `info`, send logs to `$stdout` in JSON format without colours
|
11
|
+
- In **development**, log for level `debug`, send logs to `$stdout` in single-line format with colours
|
12
|
+
- In **test**, log for level `debug`, send logs to `log/test.log` in single-line format without colours
|
13
|
+
|
14
|
+
To configure the logger:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
module MyApp
|
18
|
+
class Application < Hanami::Application
|
19
|
+
config.logger.level = :info
|
20
|
+
|
21
|
+
config.logger.stream = $stdout
|
22
|
+
config.logger.stream = "/path/to/file"
|
23
|
+
config.logger.stream = StringIO.new
|
24
|
+
|
25
|
+
config.logger.format = :json
|
26
|
+
config.logger.format = MyCustomFormatter.new
|
27
|
+
|
28
|
+
config.logger.color = false # disable coloring
|
29
|
+
config.logger.color = MyCustomColorizer.new
|
30
|
+
|
31
|
+
config.logger.filters << "secret" # add
|
32
|
+
config.logger.filters += ["yet", "another"] # add
|
33
|
+
config.logger.filters = ["foo"] # replace
|
34
|
+
|
35
|
+
# See https://ruby-doc.org/stdlib/libdoc/logger/rdoc/Logger.html
|
36
|
+
config.logger.options = ["daily"] # time based log rotation
|
37
|
+
config.logger.options = [0, 1048576] # size based log rotation
|
38
|
+
end
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
To configure the logger for specific environments:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
module MyApp
|
46
|
+
class Application < Hanami::Application
|
47
|
+
config.environment(:staging) do
|
48
|
+
config.logger.level = :info
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
To assign a custom replacement logger object:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
module MyApp
|
58
|
+
class Application < Hanami::Application
|
59
|
+
config.logger = MyCustomLogger.new
|
60
|
+
end
|
61
|
+
end
|
62
|
+
```
|
63
|
+
- [Tim Riley] Comprehensive `config.source_dirs` setting
|
64
|
+
|
65
|
+
This replaces the previous `component_dir_paths` setting, and contains two nested settings:
|
66
|
+
|
67
|
+
- `config.source_dirs.component_dirs` (backed by `Dry::System::Config::ComponentDirs`), for directories of source files intended to be registered as components
|
68
|
+
- `config.source_dirs.autoload_paths`, for directories of source files not intended for registration as components, but still to be made accessible by the autoloader
|
69
|
+
|
70
|
+
To add and configure your own additional component dirs:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
module MyApp
|
74
|
+
class Application < Hanami::Application
|
75
|
+
# Adding a simple component dir
|
76
|
+
config.source_dirs.component_dirs.add "serializers"
|
77
|
+
|
78
|
+
# Adding a component dir with custom configuration
|
79
|
+
config.source_dirs.component_dirs.add "serializers" do |dir|
|
80
|
+
dir.auto_register = proc { |component|
|
81
|
+
!component.identifier.start_with?("structs")
|
82
|
+
}
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
```
|
87
|
+
|
88
|
+
To customize the configuration of the default component dirs ("lib", "actions", "repositories", "views"):
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
module MyApp
|
92
|
+
class Application < Hanami::Application
|
93
|
+
# Customising a default component dir
|
94
|
+
config.source_dirs.component_dirs.dir("lib").auto_register = proc { |component|
|
95
|
+
!component.identifier.start_with?("structs")
|
96
|
+
}
|
97
|
+
|
98
|
+
# Setting default config to apply to all component dirs
|
99
|
+
config.source_dirs.component_dirs.auto_register = proc { |component|
|
100
|
+
!component.identifier.start_with?("entities")
|
101
|
+
}
|
102
|
+
|
103
|
+
# Removing a default component dir
|
104
|
+
config.source_dirs.component_dirs.delete("views")
|
105
|
+
end
|
106
|
+
end
|
107
|
+
```
|
108
|
+
|
109
|
+
To configure the autoload paths (defaulting to `["entities"]`):
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
module MyApp
|
113
|
+
class Application < Hanami::Application
|
114
|
+
# Adding your own autoload paths
|
115
|
+
config.source_dirs.autoload_paths << "structs"
|
116
|
+
|
117
|
+
# Or providing a full replacement
|
118
|
+
config.source_dirs.autoload_paths = ["structs"]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
```
|
122
|
+
- [Tim Riley] Application router is lazy loaded (not requiring application to be fully booted) and now available via `Hanami.rack_app` or `Hanami.application.rack_app`, instead of the previous `Hanami.app` (which required the app to be booted first).
|
123
|
+
|
4
124
|
## v2.0.0.alpha4 - 2021-12-07
|
5
125
|
### Added
|
6
126
|
- [Luca Guidi] Manage Content Security Policy (CSP) with "zero-defaults" policy. New API to change CSP values and to disable the feature.
|
data/README.md
CHANGED
@@ -58,7 +58,7 @@ You can give back to Open Source, by supporting Hanami development via a [donati
|
|
58
58
|
|
59
59
|
### Supporters
|
60
60
|
|
61
|
-
* [Trung Lê](https://github.com/
|
61
|
+
* [Trung Lê](https://github.com/runlevel5)
|
62
62
|
* [James Carlson](https://github.com/jxxcarlson)
|
63
63
|
* [Creditas](https://www.creditas.com.br/)
|
64
64
|
|
data/hanami.gemspec
CHANGED
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
|
|
26
26
|
spec.add_dependency "dry-core", "~> 0.4"
|
27
27
|
spec.add_dependency "dry-inflector", "~> 0.2", ">= 0.2.1"
|
28
28
|
spec.add_dependency "dry-monitor"
|
29
|
-
spec.add_dependency "dry-system", "~> 0.
|
29
|
+
spec.add_dependency "dry-system", "~> 0.22", ">= 0.22.0"
|
30
30
|
spec.add_dependency "hanami-cli", "~> 2.0.alpha"
|
31
31
|
spec.add_dependency "hanami-utils", "~> 2.0.alpha"
|
32
32
|
spec.add_dependency "zeitwerk", "~> 2.4"
|
@@ -9,7 +9,7 @@ Hanami.application.register_bootable :rack_logger do |container|
|
|
9
9
|
|
10
10
|
rack_logger = Hanami::Web::RackLogger.new(
|
11
11
|
container[:logger],
|
12
|
-
filter_params: Hanami.application.configuration.logger.
|
12
|
+
filter_params: Hanami.application.configuration.logger.filters
|
13
13
|
)
|
14
14
|
|
15
15
|
rack_logger.attach container[:rack_monitor]
|
@@ -10,8 +10,8 @@ module Hanami
|
|
10
10
|
class Router < ::Hanami::Router
|
11
11
|
# @since 2.0.0
|
12
12
|
# @api private
|
13
|
-
def initialize(routes:,
|
14
|
-
@
|
13
|
+
def initialize(routes:, middleware_stack: Routing::Middleware::Stack.new, **kwargs, &blk)
|
14
|
+
@middleware_stack = middleware_stack
|
15
15
|
instance_eval(&blk)
|
16
16
|
super(**kwargs, &routes)
|
17
17
|
end
|
@@ -21,20 +21,20 @@ module Hanami
|
|
21
21
|
def freeze
|
22
22
|
return self if frozen?
|
23
23
|
|
24
|
-
remove_instance_variable(:@
|
24
|
+
remove_instance_variable(:@middleware_stack)
|
25
25
|
super
|
26
26
|
end
|
27
27
|
|
28
28
|
# @since 2.0.0
|
29
29
|
# @api private
|
30
30
|
def use(middleware, *args, &blk)
|
31
|
-
@
|
31
|
+
@middleware_stack.use(middleware, *args, &blk)
|
32
32
|
end
|
33
33
|
|
34
34
|
# @since 2.0.0
|
35
35
|
# @api private
|
36
36
|
def scope(*args, &blk)
|
37
|
-
@
|
37
|
+
@middleware_stack.with(args.first) do
|
38
38
|
super
|
39
39
|
end
|
40
40
|
end
|
@@ -50,9 +50,9 @@ module Hanami
|
|
50
50
|
# @since 2.0.0
|
51
51
|
# @api private
|
52
52
|
def to_rack_app
|
53
|
-
return self if @
|
53
|
+
return self if @middleware_stack.empty?
|
54
54
|
|
55
|
-
@
|
55
|
+
@middleware_stack.to_rack_app(self)
|
56
56
|
end
|
57
57
|
end
|
58
58
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# # frozen_string_literal: true
|
2
|
+
|
3
|
+
# require "hanami/application/router"
|
4
|
+
|
5
|
+
# Hanami.application.register_bootable :router do
|
6
|
+
# start do
|
7
|
+
# configuration = Hanami.application.configuration
|
8
|
+
|
9
|
+
# routes = begin
|
10
|
+
# require File.join(configuration.root, configuration.router.routes_path)
|
11
|
+
# routes_class = Hanami.application.send(:autodiscover_application_constant, configuration.router.routes_class_name) # WIP private
|
12
|
+
# routes_class.routes
|
13
|
+
# rescue LoadError
|
14
|
+
# proc {}
|
15
|
+
# end
|
16
|
+
|
17
|
+
# resolver = configuration.router.resolver.new(
|
18
|
+
# slices: Hanami.application.slices,
|
19
|
+
# inflector: Hanami.application.inflector # TODO: use container[:inflector]?
|
20
|
+
# )
|
21
|
+
|
22
|
+
# router = Hanami::Application::Router.new(
|
23
|
+
# routes: routes,
|
24
|
+
# resolver: resolver,
|
25
|
+
# **configuration.router.options,
|
26
|
+
# ) do
|
27
|
+
# use Hanami.application[:rack_monitor]
|
28
|
+
|
29
|
+
# Hanami.application.config.for_each_middleware do |m, *args, &block|
|
30
|
+
# use(m, *args, &block)
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
|
34
|
+
# register :router, router
|
35
|
+
# end
|
36
|
+
# end
|
data/lib/hanami/application.rb
CHANGED
@@ -8,9 +8,6 @@ require "rack"
|
|
8
8
|
require "zeitwerk"
|
9
9
|
require_relative "slice"
|
10
10
|
require_relative "application/autoloader/inflector_adapter"
|
11
|
-
require_relative "application/router"
|
12
|
-
require_relative "application/routes"
|
13
|
-
require_relative "application/settings"
|
14
11
|
|
15
12
|
module Hanami
|
16
13
|
# Hanami application class
|
@@ -24,10 +21,9 @@ module Hanami
|
|
24
21
|
@_mutex.synchronize do
|
25
22
|
klass.class_eval do
|
26
23
|
@_mutex = Mutex.new
|
27
|
-
@_configuration = Hanami::Configuration.new(env: Hanami.env)
|
24
|
+
@_configuration = Hanami::Configuration.new(application_name: name, env: Hanami.env)
|
28
25
|
|
29
26
|
extend ClassMethods
|
30
|
-
include InstanceMethods
|
31
27
|
end
|
32
28
|
|
33
29
|
klass.send :prepare_base_load_path
|
@@ -76,10 +72,31 @@ module Hanami
|
|
76
72
|
self
|
77
73
|
end
|
78
74
|
|
75
|
+
def boot(&block)
|
76
|
+
return self if booted?
|
77
|
+
|
78
|
+
init
|
79
|
+
|
80
|
+
container.finalize!(&block)
|
81
|
+
|
82
|
+
slices.values.each(&:boot)
|
83
|
+
|
84
|
+
@booted = true
|
85
|
+
self
|
86
|
+
end
|
87
|
+
|
88
|
+
def shutdown
|
89
|
+
container.shutdown!
|
90
|
+
end
|
91
|
+
|
79
92
|
def inited?
|
80
93
|
@inited
|
81
94
|
end
|
82
95
|
|
96
|
+
def booted?
|
97
|
+
@booted
|
98
|
+
end
|
99
|
+
|
83
100
|
def autoloader
|
84
101
|
raise "Application not init'ed" unless defined?(@autoloader)
|
85
102
|
|
@@ -98,6 +115,18 @@ module Hanami
|
|
98
115
|
@deps_module
|
99
116
|
end
|
100
117
|
|
118
|
+
def router
|
119
|
+
raise "Application not init'ed" unless inited?
|
120
|
+
|
121
|
+
@_mutex.synchronize do
|
122
|
+
@_router ||= load_router
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def rack_app
|
127
|
+
@rack_app ||= router.to_rack_app
|
128
|
+
end
|
129
|
+
|
101
130
|
def slices
|
102
131
|
@slices ||= {}
|
103
132
|
end
|
@@ -142,38 +171,12 @@ module Hanami
|
|
142
171
|
container.resolve(*args)
|
143
172
|
end
|
144
173
|
|
145
|
-
def boot(&block)
|
146
|
-
return self if booted?
|
147
|
-
|
148
|
-
init
|
149
|
-
|
150
|
-
load_router
|
151
|
-
|
152
|
-
container.finalize!(&block)
|
153
|
-
|
154
|
-
slices.values.each(&:boot)
|
155
|
-
|
156
|
-
@booted = true
|
157
|
-
self
|
158
|
-
end
|
159
|
-
|
160
|
-
def booted?
|
161
|
-
@booted
|
162
|
-
end
|
163
|
-
|
164
|
-
def shutdown
|
165
|
-
container.shutdown!
|
166
|
-
end
|
167
|
-
|
168
174
|
def settings
|
169
175
|
@_settings ||= load_settings
|
170
176
|
end
|
171
177
|
|
172
|
-
MODULE_DELIMITER = "::"
|
173
|
-
private_constant :MODULE_DELIMITER
|
174
|
-
|
175
178
|
def namespace
|
176
|
-
|
179
|
+
configuration.namespace
|
177
180
|
end
|
178
181
|
|
179
182
|
def namespace_name
|
@@ -185,7 +188,7 @@ module Hanami
|
|
185
188
|
end
|
186
189
|
|
187
190
|
def application_name
|
188
|
-
|
191
|
+
configuration.application_name
|
189
192
|
end
|
190
193
|
|
191
194
|
def root
|
@@ -211,41 +214,6 @@ module Hanami
|
|
211
214
|
providers.detect { |provider| component_name.include?(provider.namespace.to_s) }
|
212
215
|
end
|
213
216
|
|
214
|
-
def router
|
215
|
-
@_mutex.synchronize do
|
216
|
-
@_router ||= load_router
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
def load_router
|
221
|
-
Router.new(
|
222
|
-
routes: routes,
|
223
|
-
resolver: resolver,
|
224
|
-
**configuration.router.options,
|
225
|
-
) do
|
226
|
-
use Hanami.application[:rack_monitor]
|
227
|
-
|
228
|
-
Hanami.application.config.for_each_middleware do |m, *args, &block|
|
229
|
-
use(m, *args, &block)
|
230
|
-
end
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
def routes
|
235
|
-
require File.join(configuration.root, configuration.router.routes_path)
|
236
|
-
routes_class = autodiscover_application_constant(configuration.router.routes_class_name)
|
237
|
-
routes_class.routes
|
238
|
-
rescue LoadError
|
239
|
-
proc {}
|
240
|
-
end
|
241
|
-
|
242
|
-
def resolver
|
243
|
-
config.router.resolver.new(
|
244
|
-
slices: slices,
|
245
|
-
inflector: inflector
|
246
|
-
)
|
247
|
-
end
|
248
|
-
|
249
217
|
private
|
250
218
|
|
251
219
|
def prepare_base_load_path
|
@@ -343,6 +311,8 @@ module Hanami
|
|
343
311
|
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
344
312
|
|
345
313
|
def load_settings
|
314
|
+
require_relative "application/settings"
|
315
|
+
|
346
316
|
prepare_base_load_path
|
347
317
|
require File.join(configuration.root, configuration.settings_path)
|
348
318
|
settings_class = autodiscover_application_constant(configuration.settings_class_name)
|
@@ -351,27 +321,46 @@ module Hanami
|
|
351
321
|
Settings.new
|
352
322
|
end
|
353
323
|
|
324
|
+
MODULE_DELIMITER = "::"
|
325
|
+
private_constant :MODULE_DELIMITER
|
326
|
+
|
354
327
|
def autodiscover_application_constant(constants)
|
355
328
|
inflector.constantize([namespace_name, *constants].join(MODULE_DELIMITER))
|
356
329
|
end
|
357
|
-
end
|
358
|
-
# rubocop:enable Metrics/ModuleLength
|
359
330
|
|
360
|
-
|
361
|
-
module InstanceMethods
|
362
|
-
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
363
|
-
def initialize(application = self.class)
|
331
|
+
def load_router
|
364
332
|
require_relative "application/router"
|
365
333
|
|
366
|
-
|
334
|
+
Router.new(
|
335
|
+
routes: load_routes,
|
336
|
+
resolver: router_resolver,
|
337
|
+
**configuration.router.options,
|
338
|
+
) do
|
339
|
+
use Hanami.application[:rack_monitor]
|
367
340
|
|
368
|
-
|
341
|
+
Hanami.application.config.for_each_middleware do |m, *args, &block|
|
342
|
+
use(m, *args, &block)
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
def load_routes
|
348
|
+
require_relative "application/routes"
|
349
|
+
|
350
|
+
require File.join(configuration.root, configuration.router.routes_path)
|
351
|
+
routes_class = autodiscover_application_constant(configuration.router.routes_class_name)
|
352
|
+
routes_class.routes
|
353
|
+
rescue LoadError
|
354
|
+
proc {}
|
369
355
|
end
|
370
|
-
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
371
356
|
|
372
|
-
def
|
373
|
-
|
357
|
+
def router_resolver
|
358
|
+
config.router.resolver.new(
|
359
|
+
slices: slices,
|
360
|
+
inflector: inflector
|
361
|
+
)
|
374
362
|
end
|
375
363
|
end
|
364
|
+
# rubocop:enable Metrics/ModuleLength
|
376
365
|
end
|
377
366
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Hanami
|
2
|
+
module Boot
|
3
|
+
module SourceDirs
|
4
|
+
def self.setup_component_dir!(component_dir, slice, container)
|
5
|
+
# TODO: this `== "lib"` check should be codified into a method somewhere
|
6
|
+
if component_dir.path == "lib"
|
7
|
+
# Expect component files in the root of the lib
|
8
|
+
# component dir to define classes inside the slice's namespace.
|
9
|
+
#
|
10
|
+
# e.g. "lib/foo.rb" should define SliceNamespace::Foo, and will be
|
11
|
+
# registered as "foo"
|
12
|
+
component_dir.namespaces.root(key: nil, const: slice.namespace_path)
|
13
|
+
|
14
|
+
slice.application.autoloader.push_dir(slice.root.join("lib"), namespace: slice.namespace)
|
15
|
+
|
16
|
+
container.config.component_dirs.add(component_dir)
|
17
|
+
else
|
18
|
+
# Expect component files in the root of these component dirs to define
|
19
|
+
# classes inside a namespace matching the dir.
|
20
|
+
#
|
21
|
+
# e.g. "actions/foo.rb" should define SliceNamespace::Actions::Foo, and
|
22
|
+
# will be registered as "actions.foo"
|
23
|
+
|
24
|
+
dir_namespace_path = File.join(slice.namespace_path, component_dir.path)
|
25
|
+
|
26
|
+
autoloader_namespace = begin
|
27
|
+
slice.inflector.constantize(slice.inflector.camelize(dir_namespace_path))
|
28
|
+
rescue NameError
|
29
|
+
slice.namespace.const_set(slice.inflector.camelize(component_dir.path), Module.new)
|
30
|
+
end
|
31
|
+
|
32
|
+
# TODO: do we need to do something special to clear out any previously configured root namespace here?
|
33
|
+
component_dir.namespaces.root(const: dir_namespace_path, key: component_dir.path) # TODO: do we need to swap path delimiters for key delimiters here?
|
34
|
+
container.config.component_dirs.add(component_dir)
|
35
|
+
|
36
|
+
slice.application.autoloader.push_dir(
|
37
|
+
slice.root.join(component_dir.path),
|
38
|
+
namespace: autoloader_namespace
|
39
|
+
)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -13,14 +13,58 @@ module Hanami
|
|
13
13
|
|
14
14
|
protected :config
|
15
15
|
|
16
|
+
setting :application_name
|
17
|
+
|
18
|
+
setting :level
|
19
|
+
|
20
|
+
setting :stream
|
21
|
+
|
22
|
+
setting :formatter
|
23
|
+
|
24
|
+
setting :colors
|
25
|
+
|
26
|
+
setting :filters, default: %w[_csrf password password_confirmation].freeze
|
27
|
+
|
28
|
+
setting :options, default: [], constructor: ->(value) { Array(value).flatten }, cloneable: true
|
29
|
+
|
16
30
|
setting :logger_class, default: Hanami::Logger
|
17
31
|
|
18
|
-
|
32
|
+
def initialize(env:, application_name:)
|
33
|
+
@env = env
|
34
|
+
@application_name = application_name
|
35
|
+
|
36
|
+
config.level = case env
|
37
|
+
when :production
|
38
|
+
:info
|
39
|
+
else
|
40
|
+
:debug
|
41
|
+
end
|
19
42
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
43
|
+
config.stream = case env
|
44
|
+
when :test
|
45
|
+
File.join("log", "#{env}.log")
|
46
|
+
else
|
47
|
+
$stdout
|
48
|
+
end
|
49
|
+
|
50
|
+
config.formatter = case env
|
51
|
+
when :production
|
52
|
+
:json
|
53
|
+
end
|
54
|
+
|
55
|
+
config.colors = case env
|
56
|
+
when :production, :test
|
57
|
+
false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def finalize!
|
62
|
+
config.application_name = @application_name.call
|
63
|
+
end
|
64
|
+
|
65
|
+
def instance
|
66
|
+
logger_class.new(application_name, *options, stream: stream, level: level, formatter: formatter, filter: filters, colorizer: colors)
|
67
|
+
end
|
24
68
|
|
25
69
|
private
|
26
70
|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/configurable"
|
4
|
+
require "dry/system/config/component_dirs"
|
5
|
+
|
6
|
+
module Hanami
|
7
|
+
class Configuration
|
8
|
+
# Configuration for slice source dirs
|
9
|
+
#
|
10
|
+
# @since 2.0.0
|
11
|
+
class SourceDirs
|
12
|
+
DEFAULT_COMPONENT_DIR_PATHS = %w[lib actions repositories views].freeze
|
13
|
+
private_constant :DEFAULT_COMPONENT_DIR_PATHS
|
14
|
+
|
15
|
+
include Dry::Configurable
|
16
|
+
|
17
|
+
setting :component_dirs,
|
18
|
+
default: Dry::System::Config::ComponentDirs.new.tap { |dirs|
|
19
|
+
DEFAULT_COMPONENT_DIR_PATHS.each do |path|
|
20
|
+
dirs.add path
|
21
|
+
end
|
22
|
+
},
|
23
|
+
cloneable: true
|
24
|
+
|
25
|
+
setting :autoload_paths, default: %w[entities]
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def method_missing(name, *args, &block)
|
30
|
+
if config.respond_to?(name)
|
31
|
+
config.public_send(name, *args, &block)
|
32
|
+
else
|
33
|
+
super
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def respond_to_missing?(name, _include_all = false)
|
38
|
+
config.respond_to?(name) || super
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/hanami/configuration.rb
CHANGED
@@ -12,6 +12,7 @@ require_relative "configuration/logger"
|
|
12
12
|
require_relative "configuration/middleware"
|
13
13
|
require_relative "configuration/router"
|
14
14
|
require_relative "configuration/sessions"
|
15
|
+
require_relative "configuration/source_dirs"
|
15
16
|
|
16
17
|
module Hanami
|
17
18
|
# Hanami application configuration
|
@@ -25,6 +26,9 @@ module Hanami
|
|
25
26
|
DEFAULT_ENVIRONMENTS = Concurrent::Hash.new { |h, k| h[k] = Concurrent::Array.new }
|
26
27
|
private_constant :DEFAULT_ENVIRONMENTS
|
27
28
|
|
29
|
+
MODULE_DELIMITER = "::"
|
30
|
+
private_constant :MODULE_DELIMITER
|
31
|
+
|
28
32
|
attr_reader :actions
|
29
33
|
attr_reader :middleware
|
30
34
|
attr_reader :router
|
@@ -33,7 +37,9 @@ module Hanami
|
|
33
37
|
attr_reader :environments
|
34
38
|
private :environments
|
35
39
|
|
36
|
-
def initialize(env:)
|
40
|
+
def initialize(application_name:, env:)
|
41
|
+
@namespace = application_name.split(MODULE_DELIMITER)[0..-2].join(MODULE_DELIMITER)
|
42
|
+
|
37
43
|
@environments = DEFAULT_ENVIRONMENTS.clone
|
38
44
|
config.env = env
|
39
45
|
|
@@ -42,6 +48,8 @@ module Hanami
|
|
42
48
|
self.root = Dir.pwd
|
43
49
|
self.settings_store = Application::Settings::DotenvStore.new.with_dotenv_loaded
|
44
50
|
|
51
|
+
config.logger = Configuration::Logger.new(env: env, application_name: method(:application_name))
|
52
|
+
|
45
53
|
@assets = begin
|
46
54
|
require_path = "hanami/assets/application_configuration"
|
47
55
|
require require_path
|
@@ -101,6 +109,14 @@ module Hanami
|
|
101
109
|
super
|
102
110
|
end
|
103
111
|
|
112
|
+
def namespace
|
113
|
+
inflector.constantize(@namespace)
|
114
|
+
end
|
115
|
+
|
116
|
+
def application_name
|
117
|
+
inflector.underscore(@namespace).to_sym
|
118
|
+
end
|
119
|
+
|
104
120
|
setting :env
|
105
121
|
|
106
122
|
def env=(new_env)
|
@@ -116,14 +132,14 @@ module Hanami
|
|
116
132
|
self.inflector = Dry::Inflector.new(&block)
|
117
133
|
end
|
118
134
|
|
119
|
-
setting :logger,
|
135
|
+
setting :logger, cloneable: true
|
120
136
|
|
121
137
|
def logger=(logger_instance)
|
122
138
|
@logger_instance = logger_instance
|
123
139
|
end
|
124
140
|
|
125
141
|
def logger_instance
|
126
|
-
@logger_instance || logger.
|
142
|
+
@logger_instance || logger.instance
|
127
143
|
end
|
128
144
|
|
129
145
|
setting :settings_path, default: File.join("config", "settings")
|
@@ -140,9 +156,7 @@ module Hanami
|
|
140
156
|
# slice, etc.
|
141
157
|
setting :slices, default: {}, constructor: :dup.to_proc
|
142
158
|
|
143
|
-
|
144
|
-
# of container component loading as an opt in behvior
|
145
|
-
setting :component_dir_paths, default: %w[actions repositories views]
|
159
|
+
setting :source_dirs, default: Configuration::SourceDirs.new, cloneable: true
|
146
160
|
|
147
161
|
def slice(slice_name, &block)
|
148
162
|
slices[slice_name] = block
|
data/lib/hanami/slice.rb
CHANGED
@@ -111,47 +111,69 @@ module Hanami
|
|
111
111
|
config.root = root
|
112
112
|
config.bootable_dirs = ["config/boot"]
|
113
113
|
|
114
|
-
# Add
|
115
|
-
|
116
|
-
|
117
|
-
# Expect component files in the root of the lib
|
118
|
-
# component dir to define classes inside the slice's namespace.
|
119
|
-
#
|
120
|
-
# e.g. "lib/foo.rb" should define SliceNamespace::Foo, and will be
|
121
|
-
# registered as "foo"
|
122
|
-
component_dir.namespaces.root(key: nil, const: namespace_path)
|
114
|
+
# Add component dirs for each configured component path
|
115
|
+
application.configuration.source_dirs.component_dirs.each do |component_dir|
|
116
|
+
next unless root.join(component_dir.path).directory?
|
123
117
|
|
124
|
-
|
125
|
-
end
|
126
|
-
end
|
118
|
+
component_dir = component_dir.dup
|
127
119
|
|
128
|
-
|
129
|
-
|
130
|
-
|
120
|
+
# TODO: this `== "lib"` check should be codified into a method somewhere
|
121
|
+
if component_dir.path == "lib"
|
122
|
+
# Expect component files in the root of the lib/ component dir to define
|
123
|
+
# classes inside the slice's namespace.
|
124
|
+
#
|
125
|
+
# e.g. "lib/foo.rb" should define SliceNamespace::Foo, to be registered as
|
126
|
+
# "foo"
|
127
|
+
component_dir.namespaces.delete_root
|
128
|
+
component_dir.namespaces.add_root(key: nil, const: namespace_path)
|
129
|
+
|
130
|
+
config.component_dirs.add(component_dir)
|
131
131
|
|
132
|
-
|
133
|
-
|
134
|
-
#
|
132
|
+
application.autoloader.push_dir(root.join("lib"), namespace: namespace)
|
133
|
+
else
|
134
|
+
# Expect component files in the root of non-lib/ component dirs to define
|
135
|
+
# classes inside a namespace matching that dir.
|
135
136
|
#
|
136
|
-
# e.g. "actions/foo.rb" should define SliceNamespace::Actions::Foo,
|
137
|
-
#
|
137
|
+
# e.g. "actions/foo.rb" should define SliceNamespace::Actions::Foo, to be
|
138
|
+
# registered as "actions.foo"
|
138
139
|
|
139
|
-
dir_namespace_path = File.join(namespace_path,
|
140
|
+
dir_namespace_path = File.join(namespace_path, component_dir.path)
|
140
141
|
|
141
142
|
autoloader_namespace = begin
|
142
143
|
inflector.constantize(inflector.camelize(dir_namespace_path))
|
143
144
|
rescue NameError
|
144
|
-
namespace.const_set(inflector.camelize(
|
145
|
+
namespace.const_set(inflector.camelize(component_dir.path), Module.new)
|
145
146
|
end
|
146
147
|
|
147
|
-
component_dir.namespaces.
|
148
|
+
component_dir.namespaces.delete_root
|
149
|
+
component_dir.namespaces.add_root(const: dir_namespace_path, key: component_dir.path) # TODO: do we need to swap path delimiters for key delimiters here?
|
150
|
+
|
151
|
+
config.component_dirs.add(component_dir)
|
148
152
|
|
149
153
|
application.autoloader.push_dir(
|
150
|
-
container.root.join(
|
154
|
+
container.root.join(component_dir.path),
|
151
155
|
namespace: autoloader_namespace
|
152
156
|
)
|
153
157
|
end
|
154
158
|
end
|
159
|
+
|
160
|
+
# Pass configured autoload dirs to the autoloader
|
161
|
+
application.configuration.source_dirs.autoload_paths.each do |autoload_path|
|
162
|
+
next unless root.join(autoload_path).directory?
|
163
|
+
|
164
|
+
dir_namespace_path = File.join(namespace_path, autoload_path)
|
165
|
+
|
166
|
+
autoloader_namespace = begin
|
167
|
+
inflector.constantize(inflector.camelize(dir_namespace_path))
|
168
|
+
rescue NameError
|
169
|
+
namespace.const_set(inflector.camelize(autoload_path), Module.new)
|
170
|
+
end
|
171
|
+
|
172
|
+
application.autoloader.push_dir(
|
173
|
+
container.root.join(autoload_path),
|
174
|
+
namespace: autoloader_namespace
|
175
|
+
)
|
176
|
+
end
|
155
177
|
end
|
156
178
|
end
|
157
179
|
|
data/lib/hanami/version.rb
CHANGED
data/lib/hanami.rb
CHANGED
@@ -31,20 +31,8 @@ module Hanami
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
def self.
|
35
|
-
|
36
|
-
raise "Hanami.app not configured" unless defined?(@_app)
|
37
|
-
|
38
|
-
@_app
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.app=(app)
|
43
|
-
@_mutex.synchronize do
|
44
|
-
raise "Hanami.app already configured" if defined?(@_app)
|
45
|
-
|
46
|
-
@_app = app
|
47
|
-
end
|
34
|
+
def self.rack_app
|
35
|
+
application.rack_app
|
48
36
|
end
|
49
37
|
|
50
38
|
def self.env
|
@@ -63,14 +51,8 @@ module Hanami
|
|
63
51
|
application.init
|
64
52
|
end
|
65
53
|
|
66
|
-
def self.boot
|
67
|
-
|
68
|
-
@_app
|
69
|
-
else
|
70
|
-
application.boot
|
71
|
-
|
72
|
-
@_app = application.new if web
|
73
|
-
end
|
54
|
+
def self.boot
|
55
|
+
application.boot
|
74
56
|
end
|
75
57
|
|
76
58
|
def self.shutdown
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hanami
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.
|
4
|
+
version: 2.0.0.alpha5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luca Guidi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-01-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -104,20 +104,20 @@ dependencies:
|
|
104
104
|
requirements:
|
105
105
|
- - "~>"
|
106
106
|
- !ruby/object:Gem::Version
|
107
|
-
version: '0.
|
107
|
+
version: '0.22'
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: 0.
|
110
|
+
version: 0.22.0
|
111
111
|
type: :runtime
|
112
112
|
prerelease: false
|
113
113
|
version_requirements: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: '0.
|
117
|
+
version: '0.22'
|
118
118
|
- - ">="
|
119
119
|
- !ruby/object:Gem::Version
|
120
|
-
version: 0.
|
120
|
+
version: 0.22.0
|
121
121
|
- !ruby/object:Gem::Dependency
|
122
122
|
name: hanami-cli
|
123
123
|
requirement: !ruby/object:Gem::Requirement
|
@@ -231,11 +231,13 @@ files:
|
|
231
231
|
- lib/hanami/application/routing/resolver.rb
|
232
232
|
- lib/hanami/application/routing/resolver/node.rb
|
233
233
|
- lib/hanami/application/routing/resolver/trie.rb
|
234
|
+
- lib/hanami/application/routing/router.rb
|
234
235
|
- lib/hanami/application/settings.rb
|
235
236
|
- lib/hanami/application/settings/dotenv_store.rb
|
236
237
|
- lib/hanami/assets/application_configuration.rb
|
237
238
|
- lib/hanami/assets/configuration.rb
|
238
239
|
- lib/hanami/boot.rb
|
240
|
+
- lib/hanami/boot/source_dirs.rb
|
239
241
|
- lib/hanami/cli/application/cli.rb
|
240
242
|
- lib/hanami/cli/application/command.rb
|
241
243
|
- lib/hanami/cli/application/commands.rb
|
@@ -250,6 +252,7 @@ files:
|
|
250
252
|
- lib/hanami/configuration/null_configuration.rb
|
251
253
|
- lib/hanami/configuration/router.rb
|
252
254
|
- lib/hanami/configuration/sessions.rb
|
255
|
+
- lib/hanami/configuration/source_dirs.rb
|
253
256
|
- lib/hanami/init.rb
|
254
257
|
- lib/hanami/server.rb
|
255
258
|
- lib/hanami/setup.rb
|
@@ -276,7 +279,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
276
279
|
- !ruby/object:Gem::Version
|
277
280
|
version: 1.3.1
|
278
281
|
requirements: []
|
279
|
-
rubygems_version: 3.2.
|
282
|
+
rubygems_version: 3.2.3
|
280
283
|
signing_key:
|
281
284
|
specification_version: 4
|
282
285
|
summary: The web, with simplicity
|