hanami 2.0.0.alpha4 → 2.0.0.alpha7

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: 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