hanami 2.0.0.alpha5 → 2.0.0.alpha6

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: 9c8875d3320057cffe3af1a7bb2ff781cd8ad2145c446fc9e9190d344a4a48e6
4
- data.tar.gz: c003bc2117815e10f2c15f458fb3bc6d94b480dfe9f2ec98e6458804f8a0d06d
3
+ metadata.gz: 3fc76408b7d97db32194d24bf73739bde8405fbd13855b7e4ea744f634d0739e
4
+ data.tar.gz: 30d954f8332ea7579898a87187a89a0ae2a1b34b5d9f564a86b6f61c0844f2af
5
5
  SHA512:
6
- metadata.gz: 7b133de3c728132ef6255480b10068482d58cf1e2708df395f00cc5981cdccac70cbecdb2c8325cd822298d7c92c0ee0253ab1f8f9d95ddf84b0d6de556e7f3f
7
- data.tar.gz: 42b525e3163e7bb73938b5e2fa444ccc15cc38def3e74225086f0e90bb0d805979e0a88a47703fcc73956d68598260ab366a1c155eb94b7114515b8ffc56671e
6
+ metadata.gz: f64124d027449d451f5be703f4c00850c826e4d55ebef1e6c396be63dea59a9019cb74438f7844f1e68a187299ea45c7f89ba1e98267380e7d8e1b1f8666e4b9
7
+ data.tar.gz: 8ea32aae47f0fe9536726c977af03904fa23f7258ef747b2cdd1a3b324eb064466beccc9340b7dddfb46d3d6a49c8aba899b1b488c6016377581599efd594577
data/CHANGELOG.md CHANGED
@@ -1,6 +1,83 @@
1
1
  # Hanami
2
2
  The web, with simplicity.
3
3
 
4
+ ## v2.0.0.alpha6 - 2022-02-10
5
+ ### Added
6
+ - [Luca Guidi] Official support for Ruby: MRI 3.1
7
+ - [Tim Riley] Introduce partial Slice imports and exports. It allows to selectively export a functionality from a slice and import into another.
8
+
9
+ Import from `search` slice, uses `search` as the imported key namespace:
10
+
11
+ ```ruby
12
+ # config/application.rb
13
+
14
+ module MyApp
15
+ class Application < Hanami::Application
16
+ config.slice(:admin) do
17
+ import(from: :search)
18
+ end
19
+ end
20
+ end
21
+ ```
22
+
23
+ Import from `search` slice with custom namespace:
24
+
25
+ ```ruby
26
+ # config/application.rb
27
+
28
+ module MyApp
29
+ class Application < Hanami::Application
30
+ config.slice(:admin) do
31
+ import(from: :search, as: :search_engine)
32
+ end
33
+ end
34
+ end
35
+ ```
36
+
37
+ Import specific keys from `search` slice
38
+
39
+ ```ruby
40
+ # config/application.rb
41
+
42
+ module MyApp
43
+ class Application < Hanami::Application
44
+ config.slice(:admin) do
45
+ import(keys: ["run_query"], from: :search)
46
+ end
47
+ end
48
+ end
49
+ ```
50
+
51
+ Export only specific keys from `search` slice, and import them in `admin`
52
+
53
+ ```ruby
54
+ # config/application.rb
55
+
56
+ module MyApp
57
+ class Application < Hanami::Application
58
+ config.slice(:admin) do
59
+ import(from: :search)
60
+ end
61
+
62
+ config.slice(:search) do
63
+ container.config.exports = %w[run_query index_item]
64
+ end
65
+ end
66
+ end
67
+ ```
68
+
69
+ ### Fixed
70
+ - [Luca Guidi] Ensure request logger to respect logger formatter option.
71
+
72
+ ### Changed
73
+ - [Luca Guidi] Drop support for Ruby: MRI 2.6 and 2.7.
74
+ - [Tim Riley] `Hanami.init` => `Hanami.prepare` and `hanami/init` => `hanami/prepare`
75
+ - [Tim Riley] `Hanami.register_bootable` => `Hanami.register_provider`
76
+ - [Tim Riley] `Hanami.start_bootable` => `Hanami.start`
77
+ - [Tim Riley] `Hanami::Slice#init` => `Hanami::Slice#prepare`
78
+ - [Tim Riley] `Hanami::Slice#register_bootable` => `Hanami::Slice#register_provider`
79
+ - [Tim Riley] `Hanami::Slice#start_bootable` => `Hanami::Slice#start`
80
+
4
81
  ## v2.0.0.alpha5 - 2022-01-12
5
82
  ### Changed
6
83
  - [Luca Guidi] Sensible default configuration for application logger, with per-environment defaults:
data/README.md CHANGED
@@ -36,7 +36,7 @@ These components are designed to be used independently or together in a Hanami a
36
36
 
37
37
  ## Installation
38
38
 
39
- __Hanami__ supports Ruby (MRI) 2.6+
39
+ __Hanami__ supports Ruby (MRI) 3.0+
40
40
 
41
41
  ```shell
42
42
  gem install hanami
@@ -136,8 +136,4 @@ __Hanami__ uses [Semantic Versioning 2.0.0](http://semver.org)
136
136
 
137
137
  ## Copyright
138
138
 
139
- Released under MIT License.
140
-
141
- This project was formerly known as Lotus (`lotusrb`).
142
-
143
- Copyright © 2014-2021 Luca Guidi.
139
+ Copyright © 2014-2022 Hanami Team – Released under MIT License.
data/hanami.gemspec CHANGED
@@ -4,7 +4,7 @@ lib = File.expand_path("../lib", __FILE__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require "hanami/version"
6
6
 
7
- Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
7
+ Gem::Specification.new do |spec|
8
8
  spec.name = "hanami"
9
9
  spec.version = Hanami::VERSION
10
10
  spec.authors = ["Luca Guidi"]
@@ -14,10 +14,11 @@ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
14
14
  spec.homepage = "http://hanamirb.org"
15
15
  spec.license = "MIT"
16
16
 
17
- spec.files = `git ls-files -c -o --exclude-standard -z -- lib/* bin/* LICENSE.md README.md CODE_OF_CONDUCT.md CHANGELOG.md FEATURES.md hanami.gemspec`.split("\x0")
17
+ spec.files = `git ls-files -c -o --exclude-standard -z -- lib/* bin/* LICENSE.md README.md CODE_OF_CONDUCT.md CHANGELOG.md FEATURES.md hanami.gemspec`.split("\x0") # rubocop:disable Layout/LineLength
18
18
  spec.test_files = spec.files.grep(%r{^(test)/})
19
19
  spec.require_paths = ["lib"]
20
- spec.required_ruby_version = ">= 2.6.0"
20
+ spec.metadata["rubygems_mfa_required"] = "true"
21
+ spec.required_ruby_version = ">= 3.0"
21
22
 
22
23
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
23
24
 
@@ -26,7 +27,7 @@ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
26
27
  spec.add_dependency "dry-core", "~> 0.4"
27
28
  spec.add_dependency "dry-inflector", "~> 0.2", ">= 0.2.1"
28
29
  spec.add_dependency "dry-monitor"
29
- spec.add_dependency "dry-system", "~> 0.22", ">= 0.22.0"
30
+ spec.add_dependency "dry-system", "~> 0.23", ">= 0.23.0"
30
31
  spec.add_dependency "hanami-cli", "~> 2.0.alpha"
31
32
  spec.add_dependency "hanami-utils", "~> 2.0.alpha"
32
33
  spec.add_dependency "zeitwerk", "~> 2.4"
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Hanami.application.register_bootable :inflector do
3
+ Hanami.application.register_provider :inflector do
4
4
  start do
5
5
  register :inflector, Hanami.application.inflector
6
6
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Hanami.application.register_bootable :logger do
3
+ Hanami.application.register_provider :logger do
4
4
  start do
5
5
  register :logger, Hanami.application.configuration.logger_instance
6
6
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ Hanami.application.register_provider :rack_logger do
4
+ start do
5
+ require "hanami/web/rack_logger"
6
+
7
+ target.start :logger
8
+ target.start :rack_monitor
9
+
10
+ rack_logger = Hanami::Web::RackLogger.new(target[:logger])
11
+ rack_logger.attach target[:rack_monitor]
12
+
13
+ register :rack_logger, rack_logger
14
+ end
15
+ end
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Hanami.application.register_bootable :rack_monitor do |container|
3
+ Hanami.application.register_provider :rack_monitor do
4
4
  start do
5
5
  require "dry/monitor"
6
6
  require "dry/monitor/rack/middleware"
7
7
 
8
- middleware = Dry::Monitor::Rack::Middleware.new(container[:notifications])
8
+ middleware = Dry::Monitor::Rack::Middleware.new(target[:notifications])
9
9
 
10
10
  register :rack_monitor, middleware
11
11
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Hanami.application.register_bootable :routes_helper do
3
+ Hanami.application.register_provider :routes_helper do
4
4
  start do
5
5
  require "hanami/application/routes_helper"
6
6
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Hanami.application.register_bootable :settings do
3
+ Hanami.application.register_provider :settings do
4
4
  start do
5
5
  register :settings, Hanami.application.settings
6
6
  end
@@ -7,7 +7,6 @@ require "pathname"
7
7
  require "rack"
8
8
  require "zeitwerk"
9
9
  require_relative "slice"
10
- require_relative "application/autoloader/inflector_adapter"
11
10
 
12
11
  module Hanami
13
12
  # Hanami application class
@@ -18,6 +17,7 @@ module Hanami
18
17
 
19
18
  class << self
20
19
  def inherited(klass)
20
+ super
21
21
  @_mutex.synchronize do
22
22
  klass.class_eval do
23
23
  @_mutex = Mutex.new
@@ -39,7 +39,7 @@ module Hanami
39
39
  module ClassMethods
40
40
  def self.extended(klass)
41
41
  klass.class_eval do
42
- @inited = @booted = false
42
+ @prepared = @booted = false
43
43
  end
44
44
  end
45
45
 
@@ -47,35 +47,38 @@ module Hanami
47
47
  @_configuration
48
48
  end
49
49
 
50
- alias config configuration
50
+ alias_method :config, :configuration
51
51
 
52
- def init # rubocop:disable Metrics/MethodLength
53
- return self if inited?
52
+ def prepare(provider_name = nil)
53
+ if provider_name
54
+ container.prepare(provider_name)
55
+ return self
56
+ end
54
57
 
55
- configuration.finalize!
58
+ return self if prepared?
56
59
 
57
- @autoloader = Zeitwerk::Loader.new
58
- autoloader.inflector = Autoloader::InflectorAdapter.new(inflector)
60
+ configuration.finalize!
59
61
 
60
62
  load_settings
61
63
 
64
+ @autoloader = Zeitwerk::Loader.new
62
65
  @container = prepare_container
63
66
  @deps_module = prepare_deps_module
64
67
 
65
68
  load_slices
66
- slices.values.each(&:init)
69
+ slices.each_value(&:prepare)
67
70
  slices.freeze
68
71
 
69
- autoloader.setup
72
+ @autoloader.setup
70
73
 
71
- @inited = true
74
+ @prepared = true
72
75
  self
73
76
  end
74
77
 
75
78
  def boot(&block)
76
79
  return self if booted?
77
80
 
78
- init
81
+ prepare
79
82
 
80
83
  container.finalize!(&block)
81
84
 
@@ -89,8 +92,8 @@ module Hanami
89
92
  container.shutdown!
90
93
  end
91
94
 
92
- def inited?
93
- @inited
95
+ def prepared?
96
+ @prepared
94
97
  end
95
98
 
96
99
  def booted?
@@ -98,25 +101,25 @@ module Hanami
98
101
  end
99
102
 
100
103
  def autoloader
101
- raise "Application not init'ed" unless defined?(@autoloader)
104
+ raise "Application not yet prepared" unless defined?(@autoloader)
102
105
 
103
106
  @autoloader
104
107
  end
105
108
 
106
109
  def container
107
- raise "Application not init'ed" unless defined?(@container)
110
+ raise "Application not yet prepared" unless defined?(@container)
108
111
 
109
112
  @container
110
113
  end
111
114
 
112
115
  def deps
113
- raise "Application not init'ed" unless defined?(@deps_module)
116
+ raise "Application not yet prepared" unless defined?(@deps_module)
114
117
 
115
118
  @deps_module
116
119
  end
117
120
 
118
121
  def router
119
- raise "Application not init'ed" unless inited?
122
+ raise "Application not yet prepared" unless prepared?
120
123
 
121
124
  @_mutex.synchronize do
122
125
  @_router ||= load_router
@@ -139,36 +142,32 @@ module Hanami
139
142
  slices[name.to_sym] = slice
140
143
  end
141
144
 
142
- def register(*args, **opts, &block)
143
- container.register(*args, **opts, &block)
144
- end
145
-
146
- def register_bootable(*args, **opts, &block)
147
- container.boot(*args, **opts, &block)
145
+ def register(...)
146
+ container.register(...)
148
147
  end
149
148
 
150
- def init_bootable(*args)
151
- container.init(*args)
149
+ def register_provider(...)
150
+ container.register_provider(...)
152
151
  end
153
152
 
154
- def start_bootable(*args)
155
- container.start(*args)
153
+ def start(...)
154
+ container.start(...)
156
155
  end
157
156
 
158
- def key?(*args)
159
- container.key?(*args)
157
+ def key?(...)
158
+ container.key?(...)
160
159
  end
161
160
 
162
161
  def keys
163
162
  container.keys
164
163
  end
165
164
 
166
- def [](*args)
167
- container[*args]
165
+ def [](...)
166
+ container.[](...)
168
167
  end
169
168
 
170
- def resolve(*args)
171
- container.resolve(*args)
169
+ def resolve(...)
170
+ container.resolve(...)
172
171
  end
173
172
 
174
173
  def settings
@@ -201,7 +200,7 @@ module Hanami
201
200
 
202
201
  # @api private
203
202
  def component_provider(component)
204
- raise "Hanami.application must be inited before detecting providers" unless inited?
203
+ raise "Hanami.application must be prepared before detecting providers" unless prepared?
205
204
 
206
205
  # [Admin, Main, MyApp] or [MyApp::Admin, MyApp::Main, MyApp]
207
206
  providers = slices.values + [self]
@@ -221,53 +220,46 @@ module Hanami
221
220
  $LOAD_PATH.unshift base_path unless $LOAD_PATH.include?(base_path)
222
221
  end
223
222
 
223
+ # rubocop:disable Metrics/AbcSize
224
224
  def prepare_container
225
- define_container.tap do |container|
226
- configure_container container
227
- end
228
- end
229
-
230
- def prepare_deps_module
231
- define_deps_module
232
- end
233
-
234
- def define_container
235
- require "#{application_name}/container"
236
- namespace.const_get :Container
237
- rescue LoadError, NameError
238
- namespace.const_set :Container, Class.new(Dry::System::Container)
239
- end
225
+ container =
226
+ begin
227
+ require "#{application_name}/container"
228
+ namespace.const_get :Container
229
+ rescue LoadError, NameError
230
+ namespace.const_set :Container, Class.new(Dry::System::Container)
231
+ end
240
232
 
241
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
242
- def configure_container(container)
243
233
  container.use :env, inferrer: -> { Hanami.env }
234
+ container.use :zeitwerk, loader: autoloader, run_setup: false, eager_load: false
244
235
  container.use :notifications
245
236
 
246
- container.configure do |config|
247
- config.inflector = configuration.inflector
248
-
249
- config.root = configuration.root
250
- config.bootable_dirs = [
251
- "config/boot",
252
- Pathname(__dir__).join("application/container/boot").realpath,
253
- ]
237
+ container.config.root = configuration.root
238
+ container.config.inflector = configuration.inflector
254
239
 
255
- config.component_dirs.loader = Dry::System::Loader::Autoloading
256
- config.component_dirs.add_to_load_path = false
257
- end
240
+ container.config.provider_dirs = [
241
+ "config/providers",
242
+ Pathname(__dir__).join("application/container/providers").realpath,
243
+ ]
258
244
 
259
245
  # Autoload classes defined in lib/[app_namespace]/
260
246
  if root.join("lib", namespace_path).directory?
261
- autoloader.push_dir(root.join("lib", namespace_path), namespace: namespace)
247
+ container.autoloader.push_dir(root.join("lib", namespace_path), namespace: namespace)
262
248
  end
263
249
 
264
- # Add lib/ to to the $LOAD_PATH so other files there (outside the app namespace)
265
- # are require-able
250
+ # Add lib/ to to the $LOAD_PATH so any files there (outside the app namespace) can
251
+ # be required
266
252
  container.add_to_load_path!("lib") if root.join("lib").directory?
267
253
 
254
+ container.configured!
255
+
268
256
  container
269
257
  end
270
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
258
+ # rubocop:enable Metrics/AbcSize
259
+
260
+ def prepare_deps_module
261
+ define_deps_module
262
+ end
271
263
 
272
264
  def define_deps_module
273
265
  require "#{application_name}/deps"
@@ -286,7 +278,6 @@ module Hanami
286
278
  File.join(root, config.slices_dir)
287
279
  end
288
280
 
289
- # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
290
281
  def load_slice(slice_path)
291
282
  slice_path = Pathname(slice_path)
292
283
 
@@ -308,7 +299,6 @@ module Hanami
308
299
  root: slice_path.realpath
309
300
  )
310
301
  end
311
- # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
312
302
 
313
303
  def load_settings
314
304
  require_relative "application/settings"
@@ -26,7 +26,7 @@ module Hanami
26
26
  # of the boot process respect the provided env
27
27
  ENV["HANAMI_ENV"] = arguments[:env] if arguments[:env]
28
28
 
29
- require "hanami/init"
29
+ require "hanami/prepare"
30
30
  application = Hanami.application
31
31
 
32
32
  [command.with_application(application), arguments]
@@ -126,7 +126,7 @@ module Hanami
126
126
 
127
127
  setting :root, constructor: -> path { Pathname(path) }
128
128
 
129
- setting :inflector, default: Dry::Inflector.new, cloneable: true
129
+ setting :inflector, default: Dry::Inflector.new
130
130
 
131
131
  def inflections(&block)
132
132
  self.inflector = Dry::Inflector.new(&block)
@@ -2,4 +2,4 @@
2
2
 
3
3
  require_relative "setup"
4
4
 
5
- Hanami.init
5
+ Hanami.prepare
data/lib/hanami/slice.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "dry/system/container"
4
- require "dry/system/loader/autoloading"
5
4
  require "pathname"
6
5
 
7
6
  module Hanami
@@ -16,7 +15,7 @@ module Hanami
16
15
  @name = name.to_sym
17
16
  @namespace = namespace
18
17
  @root = root ? Pathname(root) : root
19
- @container = container || define_container
18
+ @container = container
20
19
  end
21
20
 
22
21
  def inflector
@@ -27,17 +26,28 @@ module Hanami
27
26
  @namespace_path ||= inflector.underscore(namespace.to_s)
28
27
  end
29
28
 
30
- def init
31
- container.import application: application.container
29
+ def prepare(provider_name = nil)
30
+ if provider_name
31
+ container.prepare(provider_name)
32
+ return self
33
+ end
34
+
35
+ @container ||= define_container
36
+
37
+ container.import from: application.container, as: :application
32
38
 
33
39
  slice_block = application.configuration.slices[name]
34
40
  instance_eval(&slice_block) if slice_block
41
+
42
+ # This is here and not inside define_container to allow for the slice block to
43
+ # interact with container config
44
+ container.configured!
45
+
46
+ self
35
47
  end
36
48
 
37
49
  def boot
38
- container.finalize! do
39
- container.config.env = application.container.config.env
40
- end
50
+ container.finalize!
41
51
 
42
52
  @booted = true
43
53
  self
@@ -53,44 +63,47 @@ module Hanami
53
63
  @container ||= define_container
54
64
  end
55
65
 
56
- def import(*slice_names)
66
+ def import(from:, **kwargs)
67
+ # TODO: This should be handled via dry-system (see dry-rb/dry-system#228)
57
68
  raise "Cannot import after booting" if booted?
58
69
 
59
- slice_names.each do |slice_name|
60
- container.import slice_name.to_sym => application.slices.fetch(slice_name.to_sym).container
70
+ if from.is_a?(Symbol) || from.is_a?(String)
71
+ slice_name = from
72
+ # TODO: better error than the KeyError from fetch if the slice doesn't exist
73
+ from = application.slices.fetch(from.to_sym).container
61
74
  end
75
+
76
+ as = kwargs[:as] || slice_name
77
+
78
+ container.import(from: from, as: as, **kwargs)
62
79
  end
63
80
 
64
81
  def register(*args, &block)
65
82
  container.register(*args, &block)
66
83
  end
67
84
 
68
- def register_bootable(*args, &block)
69
- container.boot(*args, &block)
70
- end
71
-
72
- def init_bootable(*args)
73
- container.init(*args)
85
+ def register_provider(...)
86
+ container.register_provider(...)
74
87
  end
75
88
 
76
- def start_bootable(*args)
77
- container.start(*args)
89
+ def start(...)
90
+ container.start(...)
78
91
  end
79
92
 
80
- def key?(*args)
81
- container.key?(*args)
93
+ def key?(...)
94
+ container.key?(...)
82
95
  end
83
96
 
84
97
  def keys
85
98
  container.keys
86
99
  end
87
100
 
88
- def [](*args)
89
- container[*args]
101
+ def [](...)
102
+ container.[](...)
90
103
  end
91
104
 
92
- def resolve(*args)
93
- container.resolve(*args)
105
+ def resolve(...)
106
+ container.resolve(...)
94
107
  end
95
108
 
96
109
  private
@@ -98,82 +111,72 @@ module Hanami
98
111
  # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
99
112
  def define_container
100
113
  container = Class.new(Dry::System::Container)
101
- container.use :env
102
114
 
103
- container.configure do |config|
104
- config.name = name
105
- config.inflector = application.configuration.inflector
106
-
107
- config.component_dirs.loader = Dry::System::Loader::Autoloading
108
- config.component_dirs.add_to_load_path = false
109
-
110
- if root&.directory?
111
- config.root = root
112
- config.bootable_dirs = ["config/boot"]
113
-
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?
117
-
118
- component_dir = component_dir.dup
119
-
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
-
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.
136
- #
137
- # e.g. "actions/foo.rb" should define SliceNamespace::Actions::Foo, to be
138
- # registered as "actions.foo"
139
-
140
- dir_namespace_path = File.join(namespace_path, component_dir.path)
141
-
142
- autoloader_namespace = begin
143
- inflector.constantize(inflector.camelize(dir_namespace_path))
144
- rescue NameError
145
- namespace.const_set(inflector.camelize(component_dir.path), Module.new)
146
- end
147
-
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)
152
-
153
- application.autoloader.push_dir(
154
- container.root.join(component_dir.path),
155
- namespace: autoloader_namespace
156
- )
157
- end
115
+ container.use :env
116
+ container.use :zeitwerk,
117
+ loader: application.autoloader,
118
+ run_setup: false,
119
+ eager_load: false
120
+
121
+ container.config.name = name
122
+ container.config.env = application.configuration.env
123
+ container.config.inflector = application.configuration.inflector
124
+
125
+ if root&.directory?
126
+ container.config.root = root
127
+ container.config.provider_dirs = ["config/providers"]
128
+
129
+ # Add component dirs for each configured component path
130
+ application.configuration.source_dirs.component_dirs.each do |component_dir|
131
+ next unless root.join(component_dir.path).directory?
132
+
133
+ component_dir = component_dir.dup
134
+
135
+ # TODO: this `== "lib"` check should be codified into a method somewhere
136
+ if component_dir.path == "lib"
137
+ # Expect component files in the root of the lib/ component dir to define
138
+ # classes inside the slice's namespace.
139
+ #
140
+ # e.g. "lib/foo.rb" should define SliceNamespace::Foo, to be registered as
141
+ # "foo"
142
+ component_dir.namespaces.delete_root
143
+ component_dir.namespaces.add_root(key: nil, const: namespace_path)
144
+
145
+ container.config.component_dirs.add(component_dir)
146
+ else
147
+ # Expect component files in the root of non-lib/ component dirs to define
148
+ # classes inside a namespace matching that dir.
149
+ #
150
+ # e.g. "actions/foo.rb" should define SliceNamespace::Actions::Foo, to be
151
+ # registered as "actions.foo"
152
+
153
+ dir_namespace_path = File.join(namespace_path, component_dir.path)
154
+
155
+ component_dir.namespaces.delete_root
156
+ component_dir.namespaces.add_root(const: dir_namespace_path, key: component_dir.path)
157
+
158
+ container.config.component_dirs.add(component_dir)
158
159
  end
160
+ end
161
+ end
159
162
 
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)
163
+ if root&.directory?
164
+ # Pass configured autoload dirs to the autoloader
165
+ application.configuration.source_dirs.autoload_paths.each do |autoload_path|
166
+ next unless root.join(autoload_path).directory?
165
167
 
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
168
+ dir_namespace_path = File.join(namespace_path, autoload_path)
171
169
 
172
- application.autoloader.push_dir(
173
- container.root.join(autoload_path),
174
- namespace: autoloader_namespace
175
- )
170
+ autoloader_namespace = begin
171
+ inflector.constantize(inflector.camelize(dir_namespace_path))
172
+ rescue NameError
173
+ namespace.const_set(inflector.camelize(autoload_path), Module.new)
176
174
  end
175
+
176
+ container.config.autoloader.push_dir(
177
+ container.root.join(autoload_path),
178
+ namespace: autoloader_namespace
179
+ )
177
180
  end
178
181
  end
179
182
 
@@ -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.alpha5"
11
+ VERSION = "2.0.0.alpha6"
12
12
 
13
13
  # @since 0.9.0
14
14
  # @api private
@@ -1,19 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "json"
4
- require "rack/request"
5
- require "hanami/utils/hash"
6
-
7
3
  module Hanami
8
4
  module Web
9
5
  # Rack logger for Hanami applications
10
6
  class RackLogger
11
- attr_reader :logger
12
- attr_reader :filter_params
7
+ REQUEST_METHOD = "REQUEST_METHOD"
8
+ private_constant :REQUEST_METHOD
9
+
10
+ HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR"
11
+ private_constant :HTTP_X_FORWARDED_FOR
12
+
13
+ REMOTE_ADDR = "REMOTE_ADDR"
14
+ private_constant :REMOTE_ADDR
15
+
16
+ SCRIPT_NAME = "SCRIPT_NAME"
17
+ private_constant :SCRIPT_NAME
18
+
19
+ PATH_INFO = "PATH_INFO"
20
+ private_constant :PATH_INFO
21
+
22
+ ROUTER_PARAMS = "router.params"
23
+ private_constant :ROUTER_PARAMS
24
+
25
+ CONTENT_LENGTH = "Content-Length"
26
+ private_constant :CONTENT_LENGTH
13
27
 
14
- def initialize(logger, filter_params: [])
28
+ def initialize(logger)
15
29
  @logger = logger
16
- @filter_params = filter_params
17
30
  end
18
31
 
19
32
  def attach(rack_monitor)
@@ -26,22 +39,20 @@ module Hanami
26
39
  end
27
40
  end
28
41
 
29
- # rubocop:disable Metrics/MethodLength
30
- def log_request(env, status, time)
42
+ def log_request(env, status, elapsed)
31
43
  data = {
32
- http: env[HTTP_VERSION],
33
44
  verb: env[REQUEST_METHOD],
34
45
  status: status,
46
+ elapsed: "#{elapsed}ms",
35
47
  ip: env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR],
36
48
  path: env[SCRIPT_NAME] + env[PATH_INFO].to_s,
37
49
  length: extract_content_length(env),
38
- params: extract_params(env),
39
- elapsed: time,
50
+ params: env[ROUTER_PARAMS],
51
+ time: Time.now,
40
52
  }
41
53
 
42
- logger.info JSON.generate(data)
54
+ logger.info(data)
43
55
  end
44
- # rubocop:enable Metrics/MethodLength
45
56
 
46
57
  def log_exception(exception)
47
58
  logger.error exception.message
@@ -50,47 +61,12 @@ module Hanami
50
61
 
51
62
  private
52
63
 
53
- HTTP_VERSION = "HTTP_VERSION"
54
- REQUEST_METHOD = "REQUEST_METHOD"
55
- HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR"
56
- REMOTE_ADDR = "REMOTE_ADDR"
57
- SCRIPT_NAME = "SCRIPT_NAME"
58
- PATH_INFO = "PATH_INFO"
59
- RACK_ERRORS = "rack.errors"
60
- QUERY_HASH = "rack.request.query_hash"
61
- FORM_HASH = "rack.request.form_hash"
62
- ROUTER_PARAMS = "router.params"
63
- CONTENT_LENGTH = "Content-Length"
64
+ attr_reader :logger
64
65
 
65
66
  def extract_content_length(env)
66
67
  value = env[CONTENT_LENGTH]
67
68
  !value || value.to_s == "0" ? "-" : value
68
69
  end
69
-
70
- def extract_params(env)
71
- result = env.fetch(QUERY_HASH, {})
72
- result.merge!(env.fetch(FORM_HASH, {}))
73
- result.merge!(Hanami::Utils::Hash.deep_stringify(env.fetch(ROUTER_PARAMS, {})))
74
- result
75
- end
76
-
77
- FILTERED = "[FILTERED]"
78
-
79
- # rubocop:disable Metrics/MethodLength
80
- def filter(params)
81
- params.each_with_object({}) do |(k, v), h|
82
- if filter_params.include?(k)
83
- h.update(k => FILTERED)
84
- elsif v.is_a?(Hash)
85
- h.update(k => filter(v))
86
- elsif v.is_a?(Array)
87
- h.update(k => v.map { |m| m.is_a?(Hash) ? filter(m) : m })
88
- else
89
- h[k] = v
90
- end
91
- end
92
- end
93
- # rubocop:enable Metrics/MethodLength
94
70
  end
95
71
  end
96
72
  end
data/lib/hanami.rb CHANGED
@@ -47,8 +47,8 @@ module Hanami
47
47
  application[:logger]
48
48
  end
49
49
 
50
- def self.init
51
- application.init
50
+ def self.prepare
51
+ application.prepare
52
52
  end
53
53
 
54
54
  def self.boot
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.alpha5
4
+ version: 2.0.0.alpha6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-12 00:00:00.000000000 Z
11
+ date: 2022-02-10 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.22'
107
+ version: '0.23'
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
- version: 0.22.0
110
+ version: 0.23.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.22'
117
+ version: '0.23'
118
118
  - - ">="
119
119
  - !ruby/object:Gem::Version
120
- version: 0.22.0
120
+ version: 0.23.0
121
121
  - !ruby/object:Gem::Dependency
122
122
  name: hanami-cli
123
123
  requirement: !ruby/object:Gem::Requirement
@@ -217,13 +217,12 @@ files:
217
217
  - hanami.gemspec
218
218
  - lib/hanami.rb
219
219
  - lib/hanami/application.rb
220
- - lib/hanami/application/autoloader/inflector_adapter.rb
221
- - lib/hanami/application/container/boot/inflector.rb
222
- - lib/hanami/application/container/boot/logger.rb
223
- - lib/hanami/application/container/boot/rack_logger.rb
224
- - lib/hanami/application/container/boot/rack_monitor.rb
225
- - lib/hanami/application/container/boot/routes_helper.rb
226
- - lib/hanami/application/container/boot/settings.rb
220
+ - lib/hanami/application/container/providers/inflector.rb
221
+ - lib/hanami/application/container/providers/logger.rb
222
+ - lib/hanami/application/container/providers/rack_logger.rb
223
+ - lib/hanami/application/container/providers/rack_monitor.rb
224
+ - lib/hanami/application/container/providers/routes_helper.rb
225
+ - lib/hanami/application/container/providers/settings.rb
227
226
  - lib/hanami/application/router.rb
228
227
  - lib/hanami/application/routes.rb
229
228
  - lib/hanami/application/routes_helper.rb
@@ -231,13 +230,11 @@ files:
231
230
  - lib/hanami/application/routing/resolver.rb
232
231
  - lib/hanami/application/routing/resolver/node.rb
233
232
  - lib/hanami/application/routing/resolver/trie.rb
234
- - lib/hanami/application/routing/router.rb
235
233
  - lib/hanami/application/settings.rb
236
234
  - lib/hanami/application/settings/dotenv_store.rb
237
235
  - lib/hanami/assets/application_configuration.rb
238
236
  - lib/hanami/assets/configuration.rb
239
237
  - lib/hanami/boot.rb
240
- - lib/hanami/boot/source_dirs.rb
241
238
  - lib/hanami/cli/application/cli.rb
242
239
  - lib/hanami/cli/application/command.rb
243
240
  - lib/hanami/cli/application/commands.rb
@@ -253,7 +250,7 @@ files:
253
250
  - lib/hanami/configuration/router.rb
254
251
  - lib/hanami/configuration/sessions.rb
255
252
  - lib/hanami/configuration/source_dirs.rb
256
- - lib/hanami/init.rb
253
+ - lib/hanami/prepare.rb
257
254
  - lib/hanami/server.rb
258
255
  - lib/hanami/setup.rb
259
256
  - lib/hanami/slice.rb
@@ -263,6 +260,7 @@ homepage: http://hanamirb.org
263
260
  licenses:
264
261
  - MIT
265
262
  metadata:
263
+ rubygems_mfa_required: 'true'
266
264
  allowed_push_host: https://rubygems.org
267
265
  post_install_message:
268
266
  rdoc_options: []
@@ -272,14 +270,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
272
270
  requirements:
273
271
  - - ">="
274
272
  - !ruby/object:Gem::Version
275
- version: 2.6.0
273
+ version: '3.0'
276
274
  required_rubygems_version: !ruby/object:Gem::Requirement
277
275
  requirements:
278
276
  - - ">"
279
277
  - !ruby/object:Gem::Version
280
278
  version: 1.3.1
281
279
  requirements: []
282
- rubygems_version: 3.2.3
280
+ rubygems_version: 3.3.3
283
281
  signing_key:
284
282
  specification_version: 4
285
283
  summary: The web, with simplicity
@@ -1,22 +0,0 @@
1
- module Hanami
2
- class Application
3
- module Autoloader
4
- # Allows the Hanami standard inflector (from dry-inflector) to be used with Zeitwerk
5
- class InflectorAdapter
6
- def initialize(inflector)
7
- @inflector = inflector
8
- end
9
-
10
- def camelize(basename, _abspath)
11
- # Discard unused `_abspath` argument before calling our own inflector's
12
- # `#camelize` (which takes only one argument)
13
- inflector.camelize(basename)
14
- end
15
-
16
- private
17
-
18
- attr_reader :inflector
19
- end
20
- end
21
- end
22
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- Hanami.application.register_bootable :rack_logger do |container|
4
- start do
5
- require "hanami/web/rack_logger"
6
-
7
- use :logger
8
- use :rack_monitor
9
-
10
- rack_logger = Hanami::Web::RackLogger.new(
11
- container[:logger],
12
- filter_params: Hanami.application.configuration.logger.filters
13
- )
14
-
15
- rack_logger.attach container[:rack_monitor]
16
-
17
- register :rack_logger, rack_logger
18
- end
19
- end
@@ -1,36 +0,0 @@
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
@@ -1,44 +0,0 @@
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