hanami 2.0.0.alpha4 → 2.0.0.alpha7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2188bc3aee5a164b6610c6bc97fad9f0bba0384bf11a80be27228e7f19dad4e0
4
- data.tar.gz: 7fa39987132cf6bfda0b0986a36894d08297c1df06b31354cfbeae934d73a813
3
+ metadata.gz: d8a7910a3dd4b6e7d82711df4f181de1e8c63fbb91981542d2eb067d2cfe06b4
4
+ data.tar.gz: 2d09e35743119e1e630f196780df68cf7b7685c2d6e3208fe0c7804816ccb45f
5
5
  SHA512:
6
- metadata.gz: f7b1aad0186fcdaa94593ba4ff5d01cf4f8d4431aaffba173c3c795c2c0c76993a27da3aa503b0ce59fd67467615c86c50a4ab227986e38dd0986e91c30766a5
7
- data.tar.gz: cd2d8b82bc7f98e906686fdab7299282b1c1be4b29278c9ee5b0f9b3cefbb7d31fa83013a840b2b9fa2b8e2b2f3f8c0582ca3587b35ced91f65db6f853d67cf7
6
+ metadata.gz: 51ecc6d32c036bfc2fae43498ca6f88bb937317e610d24e499a069b02ff4c8a49b253684ba4fe47d6f67e2c2fc2b0a989460fc1462b397ddd1a5ec539ace2b7c
7
+ data.tar.gz: aa3a1f17f9304605135391c3cb915f61cabbd5cbb2e4351e70be122353d36a85af979bbf4710ffdbfa27e1e77aea023f3de7ddda2b547399e1d96b396134da9c
data/CHANGELOG.md CHANGED
@@ -1,6 +1,262 @@
1
1
  # Hanami
2
2
  The web, with simplicity.
3
3
 
4
+ ## v2.0.0.alpha7 - 2020-03-08
5
+
6
+ ## Added
7
+ - [Tim Riley] Introduced `Hanami::ApplicationLoadError` and `Hanami::SliceLoadError` exceptions to represent errors encountered during application and slice loading.
8
+ - [Tim Riley] `Hanami::Slice.shutdown` can be used to stop all the providers in a slice
9
+
10
+ ## Changed
11
+ - [Tim Riley] Slices are now represented as concrete classes (such as `Main::Slice`) inheriting from `Hanami::Slice`, as opposed to _instances_ of `Hanami::Slice`. You may create your own definitions for these slices in `config/slices/[slice_name].rb`, which you can then use for customising per-slice config and behavior, e.g.
12
+
13
+ ```ruby
14
+ # config/slices/main.rb:
15
+
16
+ module Main
17
+ class Slice < Hanami::Slice
18
+ # slice config here
19
+ end
20
+ end
21
+ ```
22
+ - [Tim Riley] Application-level `config.slice(slice_name, &block)` setting has been removed in favour of slice configuration within concrete slice class definitions
23
+ - [Tim Riley] You can configure your slice imports inside your slice classes, e.g.
24
+
25
+ ```ruby
26
+ # config/slices/main.rb:
27
+
28
+ module Main
29
+ class Slice < Hanami::Slice
30
+ # Import all exported components from "search" slice
31
+ import from: :search
32
+ end
33
+ end
34
+ ```
35
+ - [Tim Riley] You can configure your slice exports inside your slice classes, e.g.
36
+
37
+ ```ruby
38
+ # config/slices/search.rb:
39
+
40
+ module Search
41
+ class Slice < Hanami::Slice
42
+ # Export the "index_entity" component only
43
+ export ["index_entity"]
44
+ end
45
+ end
46
+ ```
47
+ - [Tim Riley] For advanced cases, you can configure your slice's container via a `prepare_container` block:
48
+
49
+ ```ruby
50
+ # config/slices/search.rb:
51
+
52
+ module Search
53
+ class Slice < Hanami::Slice
54
+ prepare_container do |container|
55
+ # `container` object is available here, with
56
+ # slice-specific configuration already applied
57
+ end
58
+ end
59
+ end
60
+ ```
61
+ - [Tim Riley] `Hanami::Application.shutdown` will now also shutdown all registered slices
62
+
63
+ ## v2.0.0.alpha6 - 2022-02-10
64
+ ### Added
65
+ - [Luca Guidi] Official support for Ruby: MRI 3.1
66
+ - [Tim Riley] Introduce partial Slice imports and exports. It allows to selectively export a functionality from a slice and import into another.
67
+
68
+ Import from `search` slice, uses `search` as the imported key namespace:
69
+
70
+ ```ruby
71
+ # config/application.rb
72
+
73
+ module MyApp
74
+ class Application < Hanami::Application
75
+ config.slice(:admin) do
76
+ import(from: :search)
77
+ end
78
+ end
79
+ end
80
+ ```
81
+
82
+ Import from `search` slice with custom namespace:
83
+
84
+ ```ruby
85
+ # config/application.rb
86
+
87
+ module MyApp
88
+ class Application < Hanami::Application
89
+ config.slice(:admin) do
90
+ import(from: :search, as: :search_engine)
91
+ end
92
+ end
93
+ end
94
+ ```
95
+
96
+ Import specific keys from `search` slice
97
+
98
+ ```ruby
99
+ # config/application.rb
100
+
101
+ module MyApp
102
+ class Application < Hanami::Application
103
+ config.slice(:admin) do
104
+ import(keys: ["run_query"], from: :search)
105
+ end
106
+ end
107
+ end
108
+ ```
109
+
110
+ Export only specific keys from `search` slice, and import them in `admin`
111
+
112
+ ```ruby
113
+ # config/application.rb
114
+
115
+ module MyApp
116
+ class Application < Hanami::Application
117
+ config.slice(:admin) do
118
+ import(from: :search)
119
+ end
120
+
121
+ config.slice(:search) do
122
+ container.config.exports = %w[run_query index_item]
123
+ end
124
+ end
125
+ end
126
+ ```
127
+
128
+ ### Fixed
129
+ - [Luca Guidi] Ensure request logger to respect logger formatter option.
130
+
131
+ ### Changed
132
+ - [Luca Guidi] Drop support for Ruby: MRI 2.6 and 2.7.
133
+ - [Tim Riley] `Hanami.init` => `Hanami.prepare` and `hanami/init` => `hanami/prepare`
134
+ - [Tim Riley] `Hanami.register_bootable` => `Hanami.register_provider`
135
+ - [Tim Riley] `Hanami.start_bootable` => `Hanami.start`
136
+ - [Tim Riley] `Hanami::Slice#init` => `Hanami::Slice#prepare`
137
+ - [Tim Riley] `Hanami::Slice#register_bootable` => `Hanami::Slice#register_provider`
138
+ - [Tim Riley] `Hanami::Slice#start_bootable` => `Hanami::Slice#start`
139
+
140
+ ## v2.0.0.alpha5 - 2022-01-12
141
+ ### Changed
142
+ - [Luca Guidi] Sensible default configuration for application logger, with per-environment defaults:
143
+
144
+ The defaults are:
145
+
146
+ - In **production**, log for level `info`, send logs to `$stdout` in JSON format without colours
147
+ - In **development**, log for level `debug`, send logs to `$stdout` in single-line format with colours
148
+ - In **test**, log for level `debug`, send logs to `log/test.log` in single-line format without colours
149
+
150
+ To configure the logger:
151
+
152
+ ```ruby
153
+ module MyApp
154
+ class Application < Hanami::Application
155
+ config.logger.level = :info
156
+
157
+ config.logger.stream = $stdout
158
+ config.logger.stream = "/path/to/file"
159
+ config.logger.stream = StringIO.new
160
+
161
+ config.logger.format = :json
162
+ config.logger.format = MyCustomFormatter.new
163
+
164
+ config.logger.color = false # disable coloring
165
+ config.logger.color = MyCustomColorizer.new
166
+
167
+ config.logger.filters << "secret" # add
168
+ config.logger.filters += ["yet", "another"] # add
169
+ config.logger.filters = ["foo"] # replace
170
+
171
+ # See https://ruby-doc.org/stdlib/libdoc/logger/rdoc/Logger.html
172
+ config.logger.options = ["daily"] # time based log rotation
173
+ config.logger.options = [0, 1048576] # size based log rotation
174
+ end
175
+ end
176
+ ```
177
+
178
+ To configure the logger for specific environments:
179
+
180
+ ```ruby
181
+ module MyApp
182
+ class Application < Hanami::Application
183
+ config.environment(:staging) do
184
+ config.logger.level = :info
185
+ end
186
+ end
187
+ end
188
+ ```
189
+
190
+ To assign a custom replacement logger object:
191
+
192
+ ```ruby
193
+ module MyApp
194
+ class Application < Hanami::Application
195
+ config.logger = MyCustomLogger.new
196
+ end
197
+ end
198
+ ```
199
+ - [Tim Riley] Comprehensive `config.source_dirs` setting
200
+
201
+ This replaces the previous `component_dir_paths` setting, and contains two nested settings:
202
+
203
+ - `config.source_dirs.component_dirs` (backed by `Dry::System::Config::ComponentDirs`), for directories of source files intended to be registered as components
204
+ - `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
205
+
206
+ To add and configure your own additional component dirs:
207
+
208
+ ```ruby
209
+ module MyApp
210
+ class Application < Hanami::Application
211
+ # Adding a simple component dir
212
+ config.source_dirs.component_dirs.add "serializers"
213
+
214
+ # Adding a component dir with custom configuration
215
+ config.source_dirs.component_dirs.add "serializers" do |dir|
216
+ dir.auto_register = proc { |component|
217
+ !component.identifier.start_with?("structs")
218
+ }
219
+ end
220
+ end
221
+ end
222
+ ```
223
+
224
+ To customize the configuration of the default component dirs ("lib", "actions", "repositories", "views"):
225
+
226
+ ```ruby
227
+ module MyApp
228
+ class Application < Hanami::Application
229
+ # Customising a default component dir
230
+ config.source_dirs.component_dirs.dir("lib").auto_register = proc { |component|
231
+ !component.identifier.start_with?("structs")
232
+ }
233
+
234
+ # Setting default config to apply to all component dirs
235
+ config.source_dirs.component_dirs.auto_register = proc { |component|
236
+ !component.identifier.start_with?("entities")
237
+ }
238
+
239
+ # Removing a default component dir
240
+ config.source_dirs.component_dirs.delete("views")
241
+ end
242
+ end
243
+ ```
244
+
245
+ To configure the autoload paths (defaulting to `["entities"]`):
246
+
247
+ ```ruby
248
+ module MyApp
249
+ class Application < Hanami::Application
250
+ # Adding your own autoload paths
251
+ config.source_dirs.autoload_paths << "structs"
252
+
253
+ # Or providing a full replacement
254
+ config.source_dirs.autoload_paths = ["structs"]
255
+ end
256
+ end
257
+ ```
258
+ - [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).
259
+
4
260
  ## v2.0.0.alpha4 - 2021-12-07
5
261
  ### Added
6
262
  - [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
@@ -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
@@ -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
 
@@ -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.19", ">= 0.21.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
@@ -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_provider :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
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../constants"
4
+ require_relative "../slice"
5
+
6
+ module Hanami
7
+ class Application
8
+ # @api private
9
+ class SliceRegistrar
10
+ attr_reader :application, :slices
11
+ private :application, :slices
12
+
13
+ def initialize(application)
14
+ @application = application
15
+ @slices = {}
16
+ end
17
+
18
+ def register(name, slice_class = nil, &block)
19
+ if slices.key?(name.to_sym)
20
+ raise SliceLoadError, "Slice '#{name}' is already registered"
21
+ end
22
+
23
+ # TODO: raise error unless name meets format (i.e. single level depth only)
24
+
25
+ slices[name.to_sym] = slice_class || build_slice(name, &block)
26
+ end
27
+
28
+ def [](name)
29
+ slices.fetch(name) do
30
+ raise SliceLoadError, "Slice '#{name}' not found"
31
+ end
32
+ end
33
+
34
+ def freeze
35
+ slices.freeze
36
+ super
37
+ end
38
+
39
+ def load_slices
40
+ slice_configs = Dir[root.join(CONFIG_DIR, "slices", "*#{RB_EXT}")]
41
+ .map { |file| File.basename(file, RB_EXT) }
42
+
43
+ slice_dirs = Dir[File.join(root, SLICES_DIR, "*")]
44
+ .select { |path| File.directory?(path) }
45
+ .map { |path| File.basename(path) }
46
+
47
+ (slice_dirs + slice_configs).uniq.sort.each do |slice_name|
48
+ load_slice(slice_name)
49
+ end
50
+
51
+ self
52
+ end
53
+
54
+ def each(&block)
55
+ slices.each_value(&block)
56
+ end
57
+
58
+ def to_a
59
+ slices.values
60
+ end
61
+
62
+ private
63
+
64
+ # Attempts to load a slice class defined in `config/slices/[slice_name].rb`, then
65
+ # registers the slice with the matching class, if found.
66
+ def load_slice(slice_name)
67
+ slice_const_name = inflector.camelize(slice_name)
68
+ slice_require_path = root.join("config", "slices", slice_name).to_s
69
+
70
+ begin
71
+ require(slice_require_path)
72
+ rescue LoadError => e
73
+ raise e unless e.path == slice_require_path
74
+ end
75
+
76
+ slice_class =
77
+ begin
78
+ inflector.constantize("#{slice_const_name}::Slice")
79
+ rescue NameError => e
80
+ raise e unless e.name == :Slice
81
+ end
82
+
83
+ register(slice_name, slice_class)
84
+ end
85
+
86
+ def build_slice(slice_name, &block)
87
+ slice_module =
88
+ begin
89
+ slice_module_name = inflector.camelize(slice_name.to_s)
90
+ inflector.constantize(slice_module_name)
91
+ rescue NameError
92
+ Object.const_set(inflector.camelize(slice_module_name), Module.new)
93
+ end
94
+
95
+ slice_module.const_set(:Slice, Class.new(Hanami::Slice, &block))
96
+ end
97
+
98
+ def root
99
+ application.root
100
+ end
101
+
102
+ def inflector
103
+ application.inflector
104
+ end
105
+ end
106
+ end
107
+ end