hanami 2.0.0.rc1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/FEATURES.md +15 -21
- data/README.md +7 -37
- data/hanami.gemspec +5 -5
- data/lib/hanami/app.rb +0 -5
- data/lib/hanami/config/actions.rb +0 -3
- data/lib/hanami/config/logger.rb +52 -29
- data/lib/hanami/config.rb +22 -1
- data/lib/hanami/extensions/action/slice_configured_action.rb +5 -2
- data/lib/hanami/extensions/view/slice_configured_view.rb +4 -1
- data/lib/hanami/providers/rack.rb +3 -2
- data/lib/hanami/rake_tasks.rb +4 -5
- data/lib/hanami/slice.rb +3 -1
- data/lib/hanami/version.rb +1 -1
- data/lib/hanami/web/rack_logger.rb +64 -15
- data/lib/hanami.rb +24 -5
- data/spec/integration/action/format_config_spec.rb +194 -0
- data/spec/integration/action/slice_configuration_spec.rb +39 -42
- data/spec/integration/code_loading/loading_from_lib_spec.rb +34 -0
- data/spec/integration/rack_app/body_parser_spec.rb +2 -5
- data/spec/integration/rack_app/rack_app_spec.rb +74 -3
- data/spec/integration/setup_spec.rb +2 -2
- data/spec/spec_helper.rb +12 -0
- data/spec/unit/hanami/config/actions/default_values_spec.rb +0 -8
- data/spec/unit/hanami/config/actions_spec.rb +7 -10
- data/spec/unit/hanami/config/logger_spec.rb +4 -4
- data/spec/unit/hanami/version_spec.rb +1 -1
- data/spec/unit/hanami/web/rack_logger_spec.rb +4 -1
- metadata +33 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ff0a8cf3ce1df8c90acbb5feb8352cc0f05d0981ad9b08ac4f6f62351e8d775
|
4
|
+
data.tar.gz: ec3ca71f07e1f4120fb6c4792163a2ffbf926de2160264a294563b6d2a6c77d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce1c3e798ba14c6ec3778beb25b47feaf87bc32dd995797836cdb8a7af9b8e13a6d401e7005f8ec78cf3da4ec5cc5be086f0ff2763eb2082939900ede5f4bae3
|
7
|
+
data.tar.gz: eb4f586e78f1afa3f674ca3e9f7499d7699e4d0c432aef744f98d788a8a77398f11ee27bd9619ed98463bc8065a28d35e9cb8e73b41b18c4044aaab7c9549507
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,23 @@
|
|
2
2
|
|
3
3
|
The web, with simplicity.
|
4
4
|
|
5
|
+
## v2.0.0 - 2022-11-22
|
6
|
+
|
7
|
+
### Added
|
8
|
+
|
9
|
+
- [Tim Riley] Allow custom code from Hanami app `lib/` to be required before to load the app
|
10
|
+
- [Tim Riley] Support the new `Hanami::Action::Config#formats` config from hanami-controller 2.0.0
|
11
|
+
- [Tim Riley] Automatically use body_parser middleware when actions `:json` format is configured
|
12
|
+
|
13
|
+
### Fixed
|
14
|
+
|
15
|
+
- [Luca Guidi] Ensure Hanami app to not crash when `hanami-controller` isn't bundled
|
16
|
+
- [Piotr Solnica] Several logger fixes
|
17
|
+
|
18
|
+
### Changed
|
19
|
+
|
20
|
+
- [Tim Riley] Don't assign a default MIME Type for Hanami apps
|
21
|
+
|
5
22
|
## v2.0.0.rc1 - 2022-11-08
|
6
23
|
|
7
24
|
### Added
|
data/FEATURES.md
CHANGED
@@ -4,27 +4,21 @@
|
|
4
4
|
|
5
5
|
## Features
|
6
6
|
|
7
|
-
## v2.0.0
|
8
|
-
|
9
|
-
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
## v2.0.0.alpha3 - 2021-11-09
|
24
|
-
|
25
|
-
## v2.0.0.alpha2 - 2021-05-04
|
26
|
-
|
27
|
-
## v2.0.0.alpha1 - 2019-01-30
|
7
|
+
## v2.0.0 - 2021-11-22
|
8
|
+
|
9
|
+
- Renamed _apps_ into _slices_, and _project_ into _app_
|
10
|
+
- The core of new applications is going to be `app/`. Slices are now optional.
|
11
|
+
- App class built around a container for managing app components; code from `app/` is loaded into the app
|
12
|
+
- Apps may have multiple Slices; code from `slices/[slice_name]/` is loaded into the corresponding slice
|
13
|
+
- `MyApp::Deps` or `MySlice::Deps` mixin for auto-registering dependencies from the app or a slice
|
14
|
+
- Code autoloading using Zeitwerk
|
15
|
+
- Code reloading via Guard
|
16
|
+
- Providers for setting up and managing the lifecycle of your app's critical components and integrations
|
17
|
+
- Type-safe app settings
|
18
|
+
- Rebuilt high-performance router
|
19
|
+
- Redesigned stateless `Hamami::Action` classes supporting the Deps mixin; add your behavior to `#handle(request, response)`
|
20
|
+
- Simplified action format configuration via `config.format` and `config.formats`
|
21
|
+
- Rewritten CLI and console
|
28
22
|
|
29
23
|
## v1.3.3 - 2019-09-20
|
30
24
|
|
data/README.md
CHANGED
@@ -8,19 +8,16 @@ The web, with simplicity.
|
|
8
8
|
|
9
9
|
## Frameworks
|
10
10
|
|
11
|
-
Hanami is a **full-stack** Ruby web framework.
|
12
|
-
It's made up of smaller, single-purpose libraries.
|
11
|
+
Hanami is a **full-stack** Ruby web framework. It's made up of smaller, single-purpose libraries.
|
13
12
|
|
14
|
-
This repository is for the full-stack framework,
|
15
|
-
which provides the glue that ties all the parts together:
|
13
|
+
This repository is for the full-stack framework, which provides the glue that ties all the parts together:
|
16
14
|
|
17
|
-
* [**Hanami::View**](https://github.com/hanami/view) - Presentation with a separation between views and templates
|
18
|
-
* [**Hanami::Controller**](https://github.com/hanami/controller) - Full featured, fast and testable actions for Rack
|
19
15
|
* [**Hanami::Router**](https://github.com/hanami/router) - Rack compatible HTTP router for Ruby
|
16
|
+
* [**Hanami::Controller**](https://github.com/hanami/controller) - Full featured, fast and testable actions for Rack
|
17
|
+
* [**Hanami::View**](https://github.com/hanami/view) - Presentation with a separation between views and templates
|
20
18
|
* [**Hanami::Helpers**](https://github.com/hanami/helpers) - View helpers for Ruby applications
|
21
19
|
* [**Hanami::Mailer**](https://github.com/hanami/mailer) - Mail for Ruby applications
|
22
20
|
* [**Hanami::Assets**](https://github.com/hanami/assets) - Assets management for Ruby
|
23
|
-
* [**Hanami::Utils**](https://github.com/hanami/utils) - Ruby core extensions and class utilities
|
24
21
|
|
25
22
|
These components are designed to be used independently or together in a Hanami application.
|
26
23
|
|
@@ -28,9 +25,7 @@ These components are designed to be used independently or together in a Hanami a
|
|
28
25
|
|
29
26
|
[![Gem Version](https://badge.fury.io/rb/hanami.svg)](https://badge.fury.io/rb/hanami)
|
30
27
|
[![CI](https://github.com/hanami/hanami/workflows/ci/badge.svg?branch=main)](https://github.com/hanami/hanami/actions?query=workflow%3Aci+branch%3Amain)
|
31
|
-
[![Test Coverage](https://codecov.io/gh/hanami/hanami/branch/main/graph/badge.svg)](https://codecov.io/gh/hanami/hanami)
|
32
28
|
[![Depfu](https://badges.depfu.com/badges/ba000e0f69e6ef1c44cd3038caaa1841/overview.svg)](https://depfu.com/github/hanami/hanami?project=Bundler)
|
33
|
-
[![Inline Docs](http://inch-ci.org/github/hanami/hanami.svg)](http://inch-ci.org/github/hanami/hanami)
|
34
29
|
|
35
30
|
## Installation
|
36
31
|
|
@@ -75,10 +70,7 @@ You can give back to Open Source, by supporting Hanami development via [GitHub S
|
|
75
70
|
|
76
71
|
## Community
|
77
72
|
|
78
|
-
We strive for an inclusive and helpful community.
|
79
|
-
We have a [Code of Conduct](http://hanamirb.org/community/#code-of-conduct) to handle controversial cases.
|
80
|
-
In general, we expect **you** to be **nice** with other people.
|
81
|
-
Our hope is for a great software and a great Community.
|
73
|
+
We strive for an inclusive and helpful community. We have a [Code of Conduct](http://hanamirb.org/community/#code-of-conduct) to handle controversial cases. In general, we expect **you** to be **nice** with other people. Our hope is for a great software and a great Community.
|
82
74
|
|
83
75
|
## Contributing [![Open Source Helpers](https://www.codetriage.com/hanami/hanami/badges/users.svg)](https://www.codetriage.com/hanami/hanami)
|
84
76
|
|
@@ -90,44 +82,22 @@ Our hope is for a great software and a great Community.
|
|
90
82
|
|
91
83
|
In addition to contributing code, you can help to triage issues. This can include reproducing bug reports, or asking for vital information such as version numbers or reproduction instructions. If you would like to start triaging issues, one easy way to get started is to [subscribe to hanami on CodeTriage](https://www.codetriage.com/hanami/hanami).
|
92
84
|
|
93
|
-
### How To Use Hanami HEAD
|
94
|
-
|
95
|
-
If you want to test Hanami's HEAD to try a new feature or to test a bug fix, here's how to do:
|
96
|
-
|
97
|
-
```
|
98
|
-
git clone https://github.com/hanami/hanami.git
|
99
|
-
cd hanami && bundle
|
100
|
-
bundle exec hanami new bookshelf --hanami-head
|
101
|
-
cd bookshelf
|
102
|
-
vim Gemfile # edit with: gem 'hanami', path: '..'
|
103
|
-
bundle
|
104
|
-
```
|
105
|
-
|
106
85
|
### Development Requirements
|
107
86
|
|
108
|
-
* Ruby
|
87
|
+
* Ruby >= 3.0
|
109
88
|
* Bundler
|
110
|
-
* [PhantomJS](http://phantomjs.org/download.html)
|
111
89
|
* Node.js (MacOS)
|
112
90
|
|
113
91
|
### Testing
|
114
92
|
|
115
|
-
In order to simulate installed gems on developers' computers, the build installs
|
116
|
-
all the gems locally in `vendor/cache`, including `hanami` code from `lib/`.
|
93
|
+
In order to simulate installed gems on developers' computers, the build installs all the gems locally in `vendor/cache`, including `hanami` code from `lib/`.
|
117
94
|
|
118
95
|
**Before running a test, please make sure you have a fresh version of the code:**
|
119
96
|
|
120
97
|
```shell
|
121
|
-
./script/setup
|
122
98
|
bundle exec rspec spec/path/to/file_spec.rb
|
123
99
|
```
|
124
100
|
|
125
|
-
To run all the tests, please use:
|
126
|
-
|
127
|
-
```shell
|
128
|
-
./script/ci
|
129
|
-
```
|
130
|
-
|
131
101
|
## Versioning
|
132
102
|
|
133
103
|
__Hanami__ uses [Semantic Versioning 2.0.0](http://semver.org)
|
data/hanami.gemspec
CHANGED
@@ -35,11 +35,11 @@ Gem::Specification.new do |spec|
|
|
35
35
|
spec.add_dependency "dry-configurable", "~> 1.0", "< 2"
|
36
36
|
spec.add_dependency "dry-core", "~> 1.0", "< 2"
|
37
37
|
spec.add_dependency "dry-inflector", "~> 1.0", "< 2"
|
38
|
-
spec.add_dependency "dry-monitor", "~> 1.0", "< 2"
|
39
|
-
spec.add_dependency "dry-system", "~> 1.0
|
40
|
-
spec.add_dependency "dry-logger", "~> 1.0
|
41
|
-
spec.add_dependency "hanami-cli", "~> 2.0
|
42
|
-
spec.add_dependency "hanami-utils", "~> 2.0
|
38
|
+
spec.add_dependency "dry-monitor", "~> 1.0", ">= 1.0.1", "< 2"
|
39
|
+
spec.add_dependency "dry-system", "~> 1.0", "< 2"
|
40
|
+
spec.add_dependency "dry-logger", "~> 1.0", "< 2"
|
41
|
+
spec.add_dependency "hanami-cli", "~> 2.0"
|
42
|
+
spec.add_dependency "hanami-utils", "~> 2.0"
|
43
43
|
spec.add_dependency "zeitwerk", "~> 2.6"
|
44
44
|
|
45
45
|
spec.add_development_dependency "rspec", "~> 3.8"
|
data/lib/hanami/app.rb
CHANGED
@@ -29,11 +29,6 @@ module Hanami
|
|
29
29
|
subclass.class_eval do
|
30
30
|
@config = Hanami::Config.new(app_name: slice_name, env: Hanami.env)
|
31
31
|
|
32
|
-
# Prepare the load path (based on the default root of `Dir.pwd`) as early as possible, so
|
33
|
-
# you can make a `require` inside the body of an `App` subclass, which may be useful for
|
34
|
-
# certain kinds of app configuration.
|
35
|
-
prepare_load_path
|
36
|
-
|
37
32
|
load_dotenv
|
38
33
|
end
|
39
34
|
end
|
@@ -136,9 +136,6 @@ module Hanami
|
|
136
136
|
|
137
137
|
# Apply defaults for base config
|
138
138
|
def configure_defaults
|
139
|
-
self.default_request_format = :html
|
140
|
-
self.default_response_format = :html
|
141
|
-
|
142
139
|
self.default_headers = {
|
143
140
|
"X-Frame-Options" => "DENY",
|
144
141
|
"X-Content-Type-Options" => "nosniff",
|
data/lib/hanami/config/logger.rb
CHANGED
@@ -15,9 +15,15 @@ module Hanami
|
|
15
15
|
# @return [Hanami::SliceName]
|
16
16
|
#
|
17
17
|
# @api private
|
18
|
-
# @since 2.0.
|
18
|
+
# @since 2.0.0
|
19
19
|
attr_reader :app_name
|
20
20
|
|
21
|
+
# @return [Symbol]
|
22
|
+
#
|
23
|
+
# @api private
|
24
|
+
# @since 2.0.0
|
25
|
+
attr_reader :env
|
26
|
+
|
21
27
|
# @!attribute [rw] level
|
22
28
|
# Sets or returns the logger level.
|
23
29
|
#
|
@@ -40,7 +46,7 @@ module Hanami
|
|
40
46
|
#
|
41
47
|
# @api public
|
42
48
|
# @since 2.0.0
|
43
|
-
setting :stream
|
49
|
+
setting :stream, default: $stdout
|
44
50
|
|
45
51
|
# @!attribute [rw] formatter
|
46
52
|
# Sets or returns the logger's formatter.
|
@@ -57,7 +63,7 @@ module Hanami
|
|
57
63
|
#
|
58
64
|
# @api public
|
59
65
|
# @since 2.0.0
|
60
|
-
setting :formatter
|
66
|
+
setting :formatter, default: :string
|
61
67
|
|
62
68
|
# @!attribute [rw] template
|
63
69
|
# Sets or returns log entry string template
|
@@ -68,7 +74,7 @@ module Hanami
|
|
68
74
|
#
|
69
75
|
# @api public
|
70
76
|
# @since 2.0.0
|
71
|
-
setting :template, default:
|
77
|
+
setting :template, default: :details
|
72
78
|
|
73
79
|
# @!attribute [rw] filters
|
74
80
|
# Sets or returns an array of attribute names to filter from logs.
|
@@ -85,11 +91,11 @@ module Hanami
|
|
85
91
|
# @!attribute [rw] logger_constructor
|
86
92
|
# Sets or returns the constructor proc to use for the logger instantiation.
|
87
93
|
#
|
88
|
-
# Defaults to `
|
94
|
+
# Defaults to either `Config#production_logger` or `Config#development_logger`
|
89
95
|
#
|
90
96
|
# @api public
|
91
97
|
# @since 2.0.0
|
92
|
-
setting :logger_constructor
|
98
|
+
setting :logger_constructor
|
93
99
|
|
94
100
|
# @!attribute [rw] options
|
95
101
|
# Sets or returns a hash of options to pass to the {logger_constructor} when initializing
|
@@ -113,27 +119,18 @@ module Hanami
|
|
113
119
|
# @api private
|
114
120
|
def initialize(env:, app_name:)
|
115
121
|
@app_name = app_name
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
$stdout
|
129
|
-
end
|
130
|
-
|
131
|
-
config.formatter = case env
|
132
|
-
when :production
|
133
|
-
:json
|
134
|
-
else
|
135
|
-
:rack
|
136
|
-
end
|
122
|
+
@env = env
|
123
|
+
|
124
|
+
case env
|
125
|
+
when :development, :test
|
126
|
+
config.level = :debug
|
127
|
+
config.stream = File.join("log", "#{env}.log") if env == :test
|
128
|
+
config.logger_constructor = method(:development_logger)
|
129
|
+
when :production
|
130
|
+
config.level = :info
|
131
|
+
config.formatter = :json
|
132
|
+
config.logger_constructor = method(:production_logger)
|
133
|
+
end
|
137
134
|
end
|
138
135
|
|
139
136
|
# Returns a new instance of the logger.
|
@@ -143,13 +140,39 @@ module Hanami
|
|
143
140
|
# @api public
|
144
141
|
# @since 2.0.0
|
145
142
|
def instance
|
146
|
-
logger_constructor.call(app_name.name, **
|
143
|
+
logger_constructor.call(env, app_name.name, **logger_constructor_options)
|
144
|
+
end
|
145
|
+
|
146
|
+
# Build an instance of a development logger
|
147
|
+
#
|
148
|
+
# This logger is used in both development and test
|
149
|
+
#
|
150
|
+
# @return [Dry::Logger::Dispatcher]
|
151
|
+
# @since 2.0.0
|
152
|
+
# @api private
|
153
|
+
def development_logger(_env, app_name, **options)
|
154
|
+
Dry.Logger(app_name, **options) do |setup|
|
155
|
+
setup
|
156
|
+
.add_backend(log_if: -> entry { !entry.tag?(:rack) })
|
157
|
+
.add_backend(formatter: :rack, log_if: -> entry { entry.tag?(:rack) })
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Build an instance of a production logger
|
162
|
+
#
|
163
|
+
# This logger is used in both development and test
|
164
|
+
#
|
165
|
+
# @return [Dry::Logger::Dispatcher]
|
166
|
+
# @since 2.0.0
|
167
|
+
# @api private
|
168
|
+
def production_logger(_env, app_name, **options)
|
169
|
+
Dry.Logger(app_name, **options)
|
147
170
|
end
|
148
171
|
|
149
172
|
private
|
150
173
|
|
151
174
|
# @api private
|
152
|
-
def
|
175
|
+
def logger_constructor_options
|
153
176
|
{stream: stream,
|
154
177
|
level: level,
|
155
178
|
formatter: formatter,
|
data/lib/hanami/config.rb
CHANGED
@@ -274,6 +274,8 @@ module Hanami
|
|
274
274
|
logger.finalize!
|
275
275
|
router.finalize!
|
276
276
|
|
277
|
+
use_body_parser_middleware
|
278
|
+
|
277
279
|
super
|
278
280
|
end
|
279
281
|
|
@@ -371,7 +373,26 @@ module Hanami
|
|
371
373
|
self.slices = ENV["HANAMI_SLICES"]&.split(",")&.map(&:strip)
|
372
374
|
end
|
373
375
|
|
374
|
-
|
376
|
+
SUPPORTED_MIDDLEWARE_PARSERS = %i[json].freeze
|
377
|
+
private_constant :SUPPORTED_MIDDLEWARE_PARSERS
|
378
|
+
|
379
|
+
def use_body_parser_middleware
|
380
|
+
return unless Hanami.bundled?("hanami-controller")
|
381
|
+
|
382
|
+
return if actions.formats.empty?
|
383
|
+
return if middleware.stack["/"].map(&:first).any? { |klass| klass == "Hanami::Middleware::BodyParser" }
|
384
|
+
|
385
|
+
parsers = SUPPORTED_MIDDLEWARE_PARSERS & actions.formats.values
|
386
|
+
return if parsers.empty?
|
387
|
+
|
388
|
+
middleware.use(
|
389
|
+
:body_parser,
|
390
|
+
[parsers.to_h { |parser_format|
|
391
|
+
[parser_format, actions.formats.mime_types_for(parser_format)]
|
392
|
+
}]
|
393
|
+
)
|
394
|
+
end
|
395
|
+
|
375
396
|
def load_dependent_config(gem_name)
|
376
397
|
if Hanami.bundled?(gem_name)
|
377
398
|
yield
|
@@ -60,7 +60,7 @@ module Hanami
|
|
60
60
|
#
|
61
61
|
# module MyApp
|
62
62
|
# class Action < Hanami::Action
|
63
|
-
# config.
|
63
|
+
# config.format :json
|
64
64
|
# end
|
65
65
|
# end
|
66
66
|
#
|
@@ -91,7 +91,10 @@ module Hanami
|
|
91
91
|
|
92
92
|
next if slice.parent && slice_value == parent_value
|
93
93
|
|
94
|
-
action_class.config.public_send(
|
94
|
+
action_class.config.public_send(
|
95
|
+
:"#{setting.name}=",
|
96
|
+
setting.mutable? ? slice_value.dup : slice_value
|
97
|
+
)
|
95
98
|
end
|
96
99
|
end
|
97
100
|
|
@@ -77,7 +77,10 @@ module Hanami
|
|
77
77
|
|
78
78
|
next if slice.parent && slice_value == parent_value
|
79
79
|
|
80
|
-
view_class.config.public_send(
|
80
|
+
view_class.config.public_send(
|
81
|
+
:"#{setting.name}=",
|
82
|
+
setting.mutable? ? slice_value.dup : slice_value
|
83
|
+
)
|
81
84
|
end
|
82
85
|
|
83
86
|
view_class.config.inflector = inflector
|
@@ -27,9 +27,10 @@ module Hanami
|
|
27
27
|
|
28
28
|
notifications = target[:notifications]
|
29
29
|
|
30
|
-
|
30
|
+
clock = Dry::Monitor::Clock.new(unit: :microsecond)
|
31
|
+
monitor_middleware = Dry::Monitor::Rack::Middleware.new(notifications, clock: clock)
|
31
32
|
|
32
|
-
rack_logger = Hanami::Web::RackLogger.new(target[:logger])
|
33
|
+
rack_logger = Hanami::Web::RackLogger.new(target[:logger], env: target.env)
|
33
34
|
rack_logger.attach(monitor_middleware)
|
34
35
|
|
35
36
|
register "monitor", monitor_middleware
|
data/lib/hanami/rake_tasks.rb
CHANGED
@@ -1,11 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "hanami/cli
|
4
|
-
require "hanami/cli/command_line"
|
3
|
+
require "hanami/cli"
|
5
4
|
|
6
5
|
Hanami::CLI::RakeTasks.register_tasks do
|
7
|
-
@_hanami_command_line = Hanami::CLI::CommandLine.new
|
8
|
-
|
9
6
|
desc "Load the app environment"
|
10
7
|
task :environment do
|
11
8
|
require "hanami/prepare"
|
@@ -53,8 +50,10 @@ Hanami::CLI::RakeTasks.register_tasks do
|
|
53
50
|
|
54
51
|
private
|
55
52
|
|
53
|
+
@_hanami_cli_bundler = Hanami::CLI::Bundler.new
|
54
|
+
|
56
55
|
def run_hanami_command(command)
|
57
|
-
@
|
56
|
+
@_hanami_cli_bundler.exec(command)
|
58
57
|
end
|
59
58
|
end
|
60
59
|
|
data/lib/hanami/slice.rb
CHANGED
@@ -957,7 +957,9 @@ module Hanami
|
|
957
957
|
**config.router.options
|
958
958
|
) do
|
959
959
|
use(rack_monitor)
|
960
|
-
|
960
|
+
if Hanami.bundled?("hanami-controller")
|
961
|
+
use(*config.actions.sessions.middleware) if config.actions.sessions.enabled?
|
962
|
+
end
|
961
963
|
|
962
964
|
middleware_stack.update(config.middleware_stack)
|
963
965
|
end
|
data/lib/hanami/version.rb
CHANGED
@@ -8,6 +8,9 @@ module Hanami
|
|
8
8
|
# @api private
|
9
9
|
# @since 2.0.0
|
10
10
|
class RackLogger
|
11
|
+
EMPTY_PARAMS = {}.freeze
|
12
|
+
private_constant :EMPTY_PARAMS
|
13
|
+
|
11
14
|
REQUEST_METHOD = "REQUEST_METHOD"
|
12
15
|
private_constant :REQUEST_METHOD
|
13
16
|
|
@@ -29,10 +32,46 @@ module Hanami
|
|
29
32
|
CONTENT_LENGTH = "Content-Length"
|
30
33
|
private_constant :CONTENT_LENGTH
|
31
34
|
|
35
|
+
MILISECOND = "ms"
|
36
|
+
private_constant :MILISECOND
|
37
|
+
|
38
|
+
MICROSECOND = "µs"
|
39
|
+
private_constant :MICROSECOND
|
40
|
+
|
41
|
+
# Dynamic extension used in production environments
|
42
|
+
# @api private
|
43
|
+
module Production
|
44
|
+
private
|
45
|
+
|
46
|
+
# @since 1.0.0
|
47
|
+
# @api private
|
48
|
+
def data(env, status:, elapsed:)
|
49
|
+
payload = super
|
50
|
+
payload[:elapsed] = elapsed
|
51
|
+
payload[:elapsed_unit] = MICROSECOND
|
52
|
+
payload
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Dynamic extension used in non-production environments
|
57
|
+
# @api private
|
58
|
+
module Development
|
59
|
+
private
|
60
|
+
|
61
|
+
# @since 1.0.0
|
62
|
+
# @api private
|
63
|
+
def data(env, status:, elapsed:)
|
64
|
+
payload = super
|
65
|
+
payload[:elapsed] = elapsed > 1000 ? "#{elapsed / 1000}ms" : "#{elapsed}#{MICROSECOND}"
|
66
|
+
payload
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
32
70
|
# @api private
|
33
71
|
# @since 2.0.0
|
34
|
-
def initialize(logger)
|
72
|
+
def initialize(logger, env: :development)
|
35
73
|
@logger = logger
|
74
|
+
extend(env == :production ? Production : Development)
|
36
75
|
end
|
37
76
|
|
38
77
|
# @api private
|
@@ -43,36 +82,46 @@ module Hanami
|
|
43
82
|
end
|
44
83
|
|
45
84
|
rack_monitor.on :error do |event|
|
46
|
-
|
85
|
+
# TODO: why we don't provide time on error?
|
86
|
+
log_exception event[:env], event[:exception], 500, 0
|
47
87
|
end
|
48
88
|
end
|
49
89
|
|
50
90
|
# @api private
|
51
91
|
# @since 2.0.0
|
52
92
|
def log_request(env, status, elapsed)
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
elapsed: "#{elapsed}ms",
|
57
|
-
ip: env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR],
|
58
|
-
path: env[SCRIPT_NAME] + env[PATH_INFO].to_s,
|
59
|
-
length: extract_content_length(env),
|
60
|
-
params: env[ROUTER_PARAMS]
|
61
|
-
}
|
62
|
-
|
63
|
-
logger.info(data)
|
93
|
+
logger.tagged(:rack) do
|
94
|
+
logger.info(data(env, status: status, elapsed: elapsed))
|
95
|
+
end
|
64
96
|
end
|
65
97
|
|
66
98
|
# @api private
|
67
99
|
# @since 2.0.0
|
68
|
-
def log_exception(exception)
|
69
|
-
logger.
|
100
|
+
def log_exception(env, exception, status, elapsed)
|
101
|
+
logger.tagged(:rack) do
|
102
|
+
logger.error(exception, **data(env, status: status, elapsed: elapsed))
|
103
|
+
end
|
70
104
|
end
|
71
105
|
|
72
106
|
private
|
73
107
|
|
74
108
|
attr_reader :logger
|
75
109
|
|
110
|
+
# @api private
|
111
|
+
# @since 2.0.0
|
112
|
+
def data(env, status:, elapsed:)
|
113
|
+
{
|
114
|
+
verb: env[REQUEST_METHOD],
|
115
|
+
status: status,
|
116
|
+
ip: env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR],
|
117
|
+
path: "#{env[SCRIPT_NAME]}#{env[PATH_INFO]}",
|
118
|
+
length: extract_content_length(env),
|
119
|
+
params: env.fetch(ROUTER_PARAMS, EMPTY_PARAMS)
|
120
|
+
}
|
121
|
+
end
|
122
|
+
|
123
|
+
# @api private
|
124
|
+
# @since 2.0.0
|
76
125
|
def extract_content_length(env)
|
77
126
|
value = env[CONTENT_LENGTH]
|
78
127
|
!value || value.to_s == "0" ? "-" : value
|
data/lib/hanami.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "pathname"
|
3
4
|
require "zeitwerk"
|
4
5
|
require_relative "hanami/constants"
|
5
6
|
|
@@ -36,7 +37,8 @@ module Hanami
|
|
36
37
|
app_path = self.app_path
|
37
38
|
|
38
39
|
if app_path
|
39
|
-
|
40
|
+
prepare_load_path
|
41
|
+
require(app_path.to_s)
|
40
42
|
app
|
41
43
|
elsif raise_exception
|
42
44
|
raise(
|
@@ -47,6 +49,23 @@ module Hanami
|
|
47
49
|
end
|
48
50
|
end
|
49
51
|
|
52
|
+
# Prepare the load path as early as possible (based on the default root inferred from the location
|
53
|
+
# of `config/app.rb`), so `require` can work at the top of `config/app.rb`. This may be useful
|
54
|
+
# when external classes are needed for configuring certain aspects of the app.
|
55
|
+
#
|
56
|
+
# @api private
|
57
|
+
# @since 2.0.0
|
58
|
+
private_class_method def self.prepare_load_path
|
59
|
+
lib_path = app_path&.join("..", "..", LIB_DIR)
|
60
|
+
|
61
|
+
if lib_path&.directory?
|
62
|
+
path = lib_path.realpath.to_s
|
63
|
+
$LOAD_PATH.prepend(path) unless $LOAD_PATH.include?(path)
|
64
|
+
end
|
65
|
+
|
66
|
+
lib_path
|
67
|
+
end
|
68
|
+
|
50
69
|
# Returns the Hamami app class.
|
51
70
|
#
|
52
71
|
# To ensure your Hanami app is loaded, run {.setup} (or `require "hanami/setup"`) first.
|
@@ -98,10 +117,10 @@ module Hanami
|
|
98
117
|
# Searches within the given directory, then searches upwards through parent directories until the
|
99
118
|
# app file can be found.
|
100
119
|
#
|
101
|
-
# @param dir [String] The directory from which to start searching. Defaults to the
|
102
|
-
# directory.
|
120
|
+
# @param dir [String, Pathname] The directory from which to start searching. Defaults to the
|
121
|
+
# current directory.
|
103
122
|
#
|
104
|
-
# @return [
|
123
|
+
# @return [Pathname, nil] the app file path, or nil if not found.
|
105
124
|
#
|
106
125
|
# @api public
|
107
126
|
# @since 2.0.0
|
@@ -110,7 +129,7 @@ module Hanami
|
|
110
129
|
path = dir.join(APP_PATH)
|
111
130
|
|
112
131
|
if path.file?
|
113
|
-
path
|
132
|
+
path
|
114
133
|
elsif !dir.root?
|
115
134
|
app_path(dir.parent)
|
116
135
|
end
|