hanami 2.0.0.alpha4 → 2.0.0.alpha5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2188bc3aee5a164b6610c6bc97fad9f0bba0384bf11a80be27228e7f19dad4e0
4
- data.tar.gz: 7fa39987132cf6bfda0b0986a36894d08297c1df06b31354cfbeae934d73a813
3
+ metadata.gz: 9c8875d3320057cffe3af1a7bb2ff781cd8ad2145c446fc9e9190d344a4a48e6
4
+ data.tar.gz: c003bc2117815e10f2c15f458fb3bc6d94b480dfe9f2ec98e6458804f8a0d06d
5
5
  SHA512:
6
- metadata.gz: f7b1aad0186fcdaa94593ba4ff5d01cf4f8d4431aaffba173c3c795c2c0c76993a27da3aa503b0ce59fd67467615c86c50a4ab227986e38dd0986e91c30766a5
7
- data.tar.gz: cd2d8b82bc7f98e906686fdab7299282b1c1be4b29278c9ee5b0f9b3cefbb7d31fa83013a840b2b9fa2b8e2b2f3f8c0582ca3587b35ced91f65db6f853d67cf7
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/joneslee85)
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.19", ">= 0.21.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.filter_params
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:, stack: Routing::Middleware::Stack.new, **kwargs, &blk)
14
- @stack = stack
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(:@stack)
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
- @stack.use(middleware, *args, &blk)
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
- @stack.with(args.first) do
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 @stack.empty?
53
+ return self if @middleware_stack.empty?
54
54
 
55
- @stack.to_rack_app(self)
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
@@ -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
- inflector.constantize(name.split(MODULE_DELIMITER)[0..-2].join(MODULE_DELIMITER))
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
- inflector.underscore(namespace).to_sym
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
- # Application instance interface
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
- application.boot
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
- @app = application.router.to_rack_app
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 call(env)
373
- @app.call(env)
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
- setting :options, default: {level: :debug}
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
- # Currently used for logging of Rack requests only.
21
- #
22
- # TODO: incorporate this into the standard logging some way or another
23
- setting :filter_params, default: %w[_csrf password password_confirmation].freeze
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
@@ -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, default: Configuration::Logger.new, cloneable: true
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.logger_class.new(**logger.options)
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
- # TODO: turn this into a richer "source dirs" setting that can support enabling
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 the "lib" component dir; all slices will load components from lib
115
- if root.join("lib").directory?
116
- config.component_dirs.add("lib") do |component_dir|
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
- application.autoloader.push_dir(root.join("lib"), namespace: namespace)
125
- end
126
- end
118
+ component_dir = component_dir.dup
127
119
 
128
- # Add component dirs for each configured component path
129
- application.configuration.component_dir_paths.each do |slice_dir|
130
- next unless root.join(slice_dir).directory?
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
- config.component_dirs.add(slice_dir) do |component_dir|
133
- # Expect component files in the root of these component dirs to define
134
- # classes inside a namespace matching the dir.
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, and
137
- # will be registered as "actions.foo"
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, slice_dir)
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(slice_dir), Module.new)
145
+ namespace.const_set(inflector.camelize(component_dir.path), Module.new)
145
146
  end
146
147
 
147
- component_dir.namespaces.root(const: dir_namespace_path, key: slice_dir)
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(slice_dir),
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
 
@@ -8,7 +8,7 @@ module Hanami
8
8
  module Version
9
9
  # @since 0.9.0
10
10
  # @api private
11
- VERSION = "2.0.0.alpha4"
11
+ VERSION = "2.0.0.alpha5"
12
12
 
13
13
  # @since 0.9.0
14
14
  # @api private
data/lib/hanami.rb CHANGED
@@ -31,20 +31,8 @@ module Hanami
31
31
  end
32
32
  end
33
33
 
34
- def self.app
35
- @_mutex.synchronize do
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(web: true)
67
- if defined?(@_app)
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.alpha4
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: 2021-12-07 00:00:00.000000000 Z
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.19'
107
+ version: '0.22'
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
- version: 0.21.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.19'
117
+ version: '0.22'
118
118
  - - ">="
119
119
  - !ruby/object:Gem::Version
120
- version: 0.21.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.29
282
+ rubygems_version: 3.2.3
280
283
  signing_key:
281
284
  specification_version: 4
282
285
  summary: The web, with simplicity