hanami 2.3.2 → 3.0.0

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.
Files changed (189) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +103 -19
  3. data/LICENSE +20 -0
  4. data/README.md +18 -35
  5. data/hanami.gemspec +36 -37
  6. data/lib/hanami/app.rb +12 -2
  7. data/lib/hanami/config/db.rb +2 -0
  8. data/lib/hanami/config/i18n.rb +138 -0
  9. data/lib/hanami/config/logger.rb +15 -7
  10. data/lib/hanami/config/null_config.rb +1 -1
  11. data/lib/hanami/config/views.rb +17 -0
  12. data/lib/hanami/config.rb +66 -22
  13. data/lib/hanami/errors.rb +6 -0
  14. data/lib/hanami/extensions/action/i18n_helper.rb +64 -0
  15. data/lib/hanami/extensions/action/name_inferrer.rb +34 -0
  16. data/lib/hanami/extensions/action/slice_configured_action.rb +31 -2
  17. data/lib/hanami/extensions/action.rb +20 -7
  18. data/lib/hanami/extensions/mailer/slice_configured_mailer.rb +134 -0
  19. data/lib/hanami/extensions/mailer.rb +28 -0
  20. data/lib/hanami/extensions/operation/slice_configured_db_operation.rb +2 -0
  21. data/lib/hanami/extensions/view/context.rb +26 -4
  22. data/lib/hanami/extensions/view/part.rb +2 -0
  23. data/lib/hanami/extensions/view/slice_configured_context.rb +7 -0
  24. data/lib/hanami/extensions/view/slice_configured_part.rb +2 -0
  25. data/lib/hanami/extensions/view/slice_configured_view.rb +8 -8
  26. data/lib/hanami/extensions/view/standard_helpers.rb +4 -0
  27. data/lib/hanami/extensions.rb +6 -1
  28. data/lib/hanami/helpers/assets_helper.rb +0 -4
  29. data/lib/hanami/helpers/form_helper.rb +1 -1
  30. data/lib/hanami/helpers/i18n_helper.rb +241 -0
  31. data/lib/hanami/logger/rack_formatter.rb +73 -0
  32. data/lib/hanami/logger/sql_formatter.rb +80 -0
  33. data/lib/hanami/logger/sql_logger.rb +48 -0
  34. data/lib/hanami/middleware/render_errors.rb +2 -2
  35. data/lib/hanami/providers/db.rb +7 -2
  36. data/lib/hanami/providers/db_logging.rb +4 -7
  37. data/lib/hanami/providers/i18n/backend.rb +373 -0
  38. data/lib/hanami/providers/i18n/locale/en.yml +57 -0
  39. data/lib/hanami/providers/i18n.rb +114 -0
  40. data/lib/hanami/providers/logger.rb +23 -1
  41. data/lib/hanami/providers/mailers.rb +101 -0
  42. data/lib/hanami/routes.rb +1 -0
  43. data/lib/hanami/settings/composite_store.rb +53 -0
  44. data/lib/hanami/settings.rb +4 -4
  45. data/lib/hanami/slice/router.rb +15 -10
  46. data/lib/hanami/slice.rb +102 -11
  47. data/lib/hanami/slice_configurable.rb +1 -3
  48. data/lib/hanami/slice_registrar.rb +2 -2
  49. data/lib/hanami/universal_logger.rb +250 -0
  50. data/lib/hanami/version.rb +1 -1
  51. data/lib/hanami/web/rack_logger.rb +2 -80
  52. data/lib/hanami/web/welcome.html.erb +443 -58
  53. data/lib/hanami.rb +4 -2
  54. metadata +34 -280
  55. data/CODE_OF_CONDUCT.md +0 -74
  56. data/FEATURES.md +0 -269
  57. data/LICENSE.md +0 -22
  58. data/spec/integration/action/cookies_spec.rb +0 -58
  59. data/spec/integration/action/csrf_protection_spec.rb +0 -54
  60. data/spec/integration/action/format_config_spec.rb +0 -129
  61. data/spec/integration/action/routes_spec.rb +0 -71
  62. data/spec/integration/action/sessions_spec.rb +0 -50
  63. data/spec/integration/action/slice_configuration_spec.rb +0 -284
  64. data/spec/integration/action/view_rendering/automatic_rendering_spec.rb +0 -247
  65. data/spec/integration/action/view_rendering/paired_view_inference_spec.rb +0 -115
  66. data/spec/integration/action/view_rendering/view_context_spec.rb +0 -221
  67. data/spec/integration/action/view_rendering_spec.rb +0 -89
  68. data/spec/integration/assets/assets_spec.rb +0 -155
  69. data/spec/integration/assets/cross_slice_assets_helpers_spec.rb +0 -129
  70. data/spec/integration/assets/serve_static_assets_spec.rb +0 -152
  71. data/spec/integration/code_loading/loading_from_app_spec.rb +0 -152
  72. data/spec/integration/code_loading/loading_from_lib_spec.rb +0 -242
  73. data/spec/integration/code_loading/loading_from_slice_spec.rb +0 -165
  74. data/spec/integration/container/application_routes_helper_spec.rb +0 -48
  75. data/spec/integration/container/auto_injection_spec.rb +0 -53
  76. data/spec/integration/container/auto_registration_spec.rb +0 -86
  77. data/spec/integration/container/autoloader_spec.rb +0 -82
  78. data/spec/integration/container/imports_spec.rb +0 -253
  79. data/spec/integration/container/prepare_container_spec.rb +0 -125
  80. data/spec/integration/container/provider_environment_spec.rb +0 -52
  81. data/spec/integration/container/provider_lifecycle_spec.rb +0 -61
  82. data/spec/integration/container/shutdown_spec.rb +0 -91
  83. data/spec/integration/container/standard_providers/rack_provider_spec.rb +0 -44
  84. data/spec/integration/container/standard_providers_spec.rb +0 -124
  85. data/spec/integration/db/auto_registration_spec.rb +0 -39
  86. data/spec/integration/db/commands_spec.rb +0 -80
  87. data/spec/integration/db/db_inflector_spec.rb +0 -57
  88. data/spec/integration/db/db_slices_spec.rb +0 -398
  89. data/spec/integration/db/db_spec.rb +0 -245
  90. data/spec/integration/db/gateways_spec.rb +0 -361
  91. data/spec/integration/db/logging_spec.rb +0 -301
  92. data/spec/integration/db/mappers_spec.rb +0 -84
  93. data/spec/integration/db/provider_config_spec.rb +0 -88
  94. data/spec/integration/db/provider_spec.rb +0 -35
  95. data/spec/integration/db/relations_spec.rb +0 -60
  96. data/spec/integration/db/repo_spec.rb +0 -300
  97. data/spec/integration/db/slices_importing_from_parent.rb +0 -130
  98. data/spec/integration/dotenv_loading_spec.rb +0 -138
  99. data/spec/integration/logging/exception_logging_spec.rb +0 -120
  100. data/spec/integration/logging/notifications_spec.rb +0 -68
  101. data/spec/integration/logging/request_logging_spec.rb +0 -202
  102. data/spec/integration/operations/extension_spec.rb +0 -122
  103. data/spec/integration/rack_app/body_parser_spec.rb +0 -108
  104. data/spec/integration/rack_app/method_override_spec.rb +0 -97
  105. data/spec/integration/rack_app/middleware_spec.rb +0 -720
  106. data/spec/integration/rack_app/non_booted_rack_app_spec.rb +0 -104
  107. data/spec/integration/rack_app/rack_app_spec.rb +0 -442
  108. data/spec/integration/rake_tasks_spec.rb +0 -107
  109. data/spec/integration/router/resource_routes_spec.rb +0 -281
  110. data/spec/integration/settings/access_in_slice_class_body_spec.rb +0 -83
  111. data/spec/integration/settings/access_to_constants_spec.rb +0 -46
  112. data/spec/integration/settings/loading_from_env_spec.rb +0 -188
  113. data/spec/integration/settings/settings_component_loading_spec.rb +0 -113
  114. data/spec/integration/settings/slice_registration_spec.rb +0 -145
  115. data/spec/integration/settings/using_types_spec.rb +0 -80
  116. data/spec/integration/setup_spec.rb +0 -165
  117. data/spec/integration/slices/external_slice_spec.rb +0 -91
  118. data/spec/integration/slices/slice_configuration_spec.rb +0 -42
  119. data/spec/integration/slices/slice_loading_spec.rb +0 -171
  120. data/spec/integration/slices/slice_registrations_spec.rb +0 -80
  121. data/spec/integration/slices/slice_routing_spec.rb +0 -219
  122. data/spec/integration/slices_spec.rb +0 -471
  123. data/spec/integration/view/config/default_context_spec.rb +0 -149
  124. data/spec/integration/view/config/inflector_spec.rb +0 -57
  125. data/spec/integration/view/config/part_class_spec.rb +0 -147
  126. data/spec/integration/view/config/part_namespace_spec.rb +0 -103
  127. data/spec/integration/view/config/paths_spec.rb +0 -119
  128. data/spec/integration/view/config/scope_class_spec.rb +0 -147
  129. data/spec/integration/view/config/scope_namespace_spec.rb +0 -103
  130. data/spec/integration/view/config/template_spec.rb +0 -38
  131. data/spec/integration/view/context/assets_spec.rb +0 -79
  132. data/spec/integration/view/context/inflector_spec.rb +0 -40
  133. data/spec/integration/view/context/request_spec.rb +0 -57
  134. data/spec/integration/view/context/routes_spec.rb +0 -84
  135. data/spec/integration/view/helpers/form_helper_spec.rb +0 -174
  136. data/spec/integration/view/helpers/part_helpers_spec.rb +0 -124
  137. data/spec/integration/view/helpers/scope_helpers_spec.rb +0 -84
  138. data/spec/integration/view/helpers/user_defined_helpers/part_helpers_spec.rb +0 -162
  139. data/spec/integration/view/helpers/user_defined_helpers/scope_helpers_spec.rb +0 -119
  140. data/spec/integration/view/parts/default_rendering_spec.rb +0 -138
  141. data/spec/integration/view/slice_configuration_spec.rb +0 -289
  142. data/spec/integration/view/views_spec.rb +0 -103
  143. data/spec/integration/web/content_security_policy_nonce_spec.rb +0 -251
  144. data/spec/integration/web/render_detailed_errors_spec.rb +0 -107
  145. data/spec/integration/web/render_errors_spec.rb +0 -242
  146. data/spec/integration/web/welcome_view_spec.rb +0 -84
  147. data/spec/spec_helper.rb +0 -28
  148. data/spec/support/app_integration.rb +0 -157
  149. data/spec/support/coverage.rb +0 -1
  150. data/spec/support/matchers.rb +0 -32
  151. data/spec/support/rspec.rb +0 -27
  152. data/spec/unit/hanami/config/actions/content_security_policy_spec.rb +0 -96
  153. data/spec/unit/hanami/config/actions/cookies_spec.rb +0 -46
  154. data/spec/unit/hanami/config/actions/csrf_protection_spec.rb +0 -58
  155. data/spec/unit/hanami/config/actions/default_values_spec.rb +0 -43
  156. data/spec/unit/hanami/config/actions/sessions_spec.rb +0 -48
  157. data/spec/unit/hanami/config/actions_spec.rb +0 -52
  158. data/spec/unit/hanami/config/base_url_spec.rb +0 -25
  159. data/spec/unit/hanami/config/console_spec.rb +0 -22
  160. data/spec/unit/hanami/config/db_spec.rb +0 -38
  161. data/spec/unit/hanami/config/inflector_spec.rb +0 -35
  162. data/spec/unit/hanami/config/logger_spec.rb +0 -195
  163. data/spec/unit/hanami/config/render_detailed_errors_spec.rb +0 -25
  164. data/spec/unit/hanami/config/render_errors_spec.rb +0 -25
  165. data/spec/unit/hanami/config/router_spec.rb +0 -44
  166. data/spec/unit/hanami/config/slices_spec.rb +0 -34
  167. data/spec/unit/hanami/config/views_spec.rb +0 -80
  168. data/spec/unit/hanami/env_spec.rb +0 -37
  169. data/spec/unit/hanami/extensions/view/context_spec.rb +0 -59
  170. data/spec/unit/hanami/helpers/assets_helper/asset_url_spec.rb +0 -120
  171. data/spec/unit/hanami/helpers/assets_helper/audio_tag_spec.rb +0 -132
  172. data/spec/unit/hanami/helpers/assets_helper/favicon_tag_spec.rb +0 -87
  173. data/spec/unit/hanami/helpers/assets_helper/image_tag_spec.rb +0 -92
  174. data/spec/unit/hanami/helpers/assets_helper/javascript_tag_spec.rb +0 -143
  175. data/spec/unit/hanami/helpers/assets_helper/stylesheet_tag_spec.rb +0 -126
  176. data/spec/unit/hanami/helpers/assets_helper/video_tag_spec.rb +0 -136
  177. data/spec/unit/hanami/helpers/form_helper_spec.rb +0 -2857
  178. data/spec/unit/hanami/port_spec.rb +0 -117
  179. data/spec/unit/hanami/providers/db/config/default_config_spec.rb +0 -100
  180. data/spec/unit/hanami/providers/db/config/gateway_spec.rb +0 -73
  181. data/spec/unit/hanami/providers/db/config_spec.rb +0 -143
  182. data/spec/unit/hanami/router/errors/not_allowed_error_spec.rb +0 -27
  183. data/spec/unit/hanami/router/errors/not_found_error_spec.rb +0 -22
  184. data/spec/unit/hanami/settings/env_store_spec.rb +0 -52
  185. data/spec/unit/hanami/settings_spec.rb +0 -111
  186. data/spec/unit/hanami/slice_configurable_spec.rb +0 -141
  187. data/spec/unit/hanami/slice_name_spec.rb +0 -47
  188. data/spec/unit/hanami/slice_spec.rb +0 -99
  189. data/spec/unit/hanami/web/rack_logger_spec.rb +0 -99
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 83aa8539603f6f36097cafc14e3808b5ccc9c6797b8ba1e84e43c180f4f09b3b
4
- data.tar.gz: 4b739af805d108359042c2c87529f7f258aaf4f05567efe4ebf457cf60175687
3
+ metadata.gz: 53f2d51070211158a50d0adfd0e4326c2647cd8dfb81135d74b5c09449213b24
4
+ data.tar.gz: f8c19c0c73096809f15176ed90c358be89dfda92adb8c418e1863c902b7835dc
5
5
  SHA512:
6
- metadata.gz: 6199e57e74e60b8b2206511a7ac86ec1f853e7c5103cbdf425b79cb085c32f297658e2f5d5c36346945fa3c4218070f9e88b2b8e42c4ddb9328241c426b846a5
7
- data.tar.gz: 2b94c7d2829d04580602f14637210316e7b24488ccfb343254c7b6cbc77b870f5cdeb3c5482e3eb41c160097e413248e4269a1a1b7ce1fbda38d267874c25999
6
+ metadata.gz: a0b02ef4b8832c4de4d7ba33077ccde81a5412a1483e942fcf3ac8d179c6b5a4dc1ad23c2c597ef50cfb77f84034c6045679051c7c70e7bcc0c9ccd43f7414f0
7
+ data.tar.gz: 82fe7c7f69fc77c9a4cce6017a3b3e3dea90e3eb55aabc58205532c77711caab93cf2bc1824177a1d1840d5d723da12c7337a7a158390043fad9d7e5f88c7ea3
data/CHANGELOG.md CHANGED
@@ -1,26 +1,27 @@
1
1
  # Hanami
2
2
 
3
- A flexible framework for maintainable Ruby apps.
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Break Versioning](https://www.taoensso.com/break-versioning).
4
6
 
5
7
  A complete Hanami app is composed of multiple gems. For a complete overview of changes, see also these CHANGELOGs:
6
8
 
7
- [Assets][assets], [Assets JS][assets-js], [CLI][cli],
8
- [Controller][controller], [DB][db], [RSpec][rspec],
9
- [Reloader][reloader], [Router][router], [Utils][utils],
10
- [Validations][validations], [View][view], [Webconsole][webconsole]
11
-
12
- [assets]: https://github.com/hanami/hanami-assets/blob/main/CHANGELOG.md
13
- [assets-js]: https://github.com/hanami/hanami-assets-js/blob/main/CHANGELOG.md
14
- [cli]: https://github.com/hanami/hanami-cli/blob/main/CHANGELOG.md
15
- [controller]: https://github.com/hanami/hanami-controller/blob/main/CHANGELOG.md
16
- [db]: https://github.com/hanami/hanami-db/blob/main/CHANGELOG.md
17
- [rspec]: https://github.com/hanami/hanami-rspec/blob/main/CHANGELOG.md
18
- [reloader]: https://github.com/hanami/hanami-reloader/blob/main/CHANGELOG.md
19
- [router]: https://github.com/hanami/hanami-router/blob/main/CHANGELOG.md
20
- [utils]: https://github.com/hanami/hanami-utils/blob/main/CHANGELOG.md
21
- [validations]: https://github.com/hanami/hanami-validations/blob/main/CHANGELOG.md
22
- [view]: https://github.com/hanami/hanami-view/blob/main/CHANGELOG.md
23
- [webconsole]: https://github.com/hanami/hanami-webconsole/blob/main/CHANGELOG.md
9
+ [Assets], [Assets JS], [CLI], [Action], [DB], [Mailer], [Minitest],
10
+ [RSpec], [Reloader], [Router], [Utils], [View], [Webconsole]
11
+
12
+ [Assets]: https://github.com/hanami/hanami-assets/blob/main/CHANGELOG.md
13
+ [Assets JS]: https://github.com/hanami/hanami-assets-js/blob/main/CHANGELOG.md
14
+ [CLI]: https://github.com/hanami/hanami-cli/blob/main/CHANGELOG.md
15
+ [Action]: https://github.com/hanami/hanami-action/blob/main/CHANGELOG.md
16
+ [DB]: https://github.com/hanami/hanami-db/blob/main/CHANGELOG.md
17
+ [Mailer]: https://github.com/hanami/hanami-mailer/blob/main/CHANGELOG.md
18
+ [Minitest]: https://github.com/hanami/hanami-minitest/blob/main/CHANGELOG.md
19
+ [RSpec]: https://github.com/hanami/hanami-rspec/blob/main/CHANGELOG.md
20
+ [Reloader]: https://github.com/hanami/hanami-reloader/blob/main/CHANGELOG.md
21
+ [Router]: https://github.com/hanami/hanami-router/blob/main/CHANGELOG.md
22
+ [Utils]: https://github.com/hanami/hanami-utils/blob/main/CHANGELOG.md
23
+ [View]: https://github.com/hanami/hanami-view/blob/main/CHANGELOG.md
24
+ [Webconsole]: https://github.com/hanami/hanami-webconsole/blob/main/CHANGELOG.md
24
25
 
25
26
  ## [Unreleased]
26
27
 
@@ -36,7 +37,90 @@ A complete Hanami app is composed of multiple gems. For a complete overview of c
36
37
 
37
38
  ### Security
38
39
 
39
- [unreleased]: https://github.com/hanami/hanami/compare/v2.3.2...HEAD
40
+ [unreleased]: https://github.com/hanami/hanami/compare/v3.0.0...HEAD
41
+
42
+ ## [3.0.0] - 2026-06-30
43
+
44
+ ### Added
45
+
46
+ - Integrate hanami-mailer gem when bundled. (@timriley in #1597, #1600, #1606, #1609)
47
+
48
+ Load templates from `templates/mailers/`. Register a `"mailers.delivery_method"`, which is either an SMTP mailer when `SMTP_ADDRESS`, `SMTP_PORT`, `SMTP_USERNAME`, `SMTP_PASSWORD`, `SMTP_AUTHENTICATION` env vars are present. These can also be prefixed with a slice name. Register a test delivery always in the test env, and also in other envs when the env vars are absent.
49
+ - Integrate i18n gem when bundled. (@timriley in #1562, #1589, #1590, #1591, #1592, #1593)
50
+
51
+ Register an `"i18n"` component in each slice, which may be configured via `config.i18n` or a dedicated `:i18n` provider. Load translations from `config/i18n/` within each slice. Load shared translations from `config/i18n/shared/` at the app-level only. Bundle default English translations for `#localize`. Make helpers available in views and actions, which also prefix relative keys (with a leading ".") with their own dot-delimited template or action names.
52
+ - Wrap the configured app logger with `Hanami::UniversalLogger`, to provide a consistent logging interface regardless of the underlying logger. The app can now be depended upon to support (1) structured logging via keyword args passed to log methods, and (2) tagged logging via `#tagged`. (@timriley in #1567, #1568, #1608)
53
+ - Allow the built-in logger to be further configured in a `config/providers/logger.rb` provider file, useful for calling arbitrary methods on the logger, like adding backends. (@timriley in #1608)
54
+
55
+ ```ruby
56
+ Hanami.app.configure_provider :logger do
57
+ before :start do
58
+ logger.add_backend(
59
+ stream: Hanami.app.root.join("log", "payments.log"),
60
+ log_if: -> entry { entry.tag?(:payments) }
61
+ )
62
+ end
63
+ end
64
+ ```
65
+ - Support `HANAMI_LOG_LEVEL` env var to set the log level (e.g. `HANAMI_LOG_LEVEL=warn bundle exec hanami server`). Takes precedence over `config.logger.level` set in `config/app.rb`. (@cllns in #1580)
66
+ - Add `config.db.log_level` setting, for changing the log level for SQL logs. (@katafrakt in #1587)
67
+ - New setting `:default_template_engine` that sets which template engine should be used by default when doing `hanami generate`. (@katafrakt in #1564)
68
+ - Add `Hanami::Settings::CompositeStore`, which can be used to chain setting lookups from multiple stores. (@aaronmallen in #1572)
69
+ - Add `Hanami::Slice.with_slices`, returning the slice and all its nested slices. (@timriley in #1604)
70
+
71
+ ### Changed
72
+
73
+ - Default to memoizing all components, except in test env. Opt out for some or all components via `config.no_memoize`. (@timriley in #1573, #1599)
74
+ - Colorize logs by default in development env. (@timriley in #1566)
75
+ - Emit structured log entries for SQL queries, formatted consistently with request logs. (@timriley in #1569)
76
+ - Syntax highlight SQL in logs when the rouge gem is bundled. (@timriley in #1570, #1607)
77
+ - Colorize web request logs. (@timriley in #1571)
78
+ - Change default log level for SQL (and other database) statements from `:info` to `:debug`. (@katafrakt in #1595)
79
+ - Raise a helpful error message when the `Slice.call` Rack entrypoint is called and no routes are available. (@sandbergja in #1586)
80
+ - Apply extensions to hanami-action gem rather than hanami-controller (which is now retired). (@cllns in #1582)
81
+ - Redesign the new app welcome screen to match our new Hanakai visuals. (@makenosound in #1598)
82
+ - Require Ruby 3.3 or newer.
83
+
84
+ ### Removed
85
+
86
+ - Remove default body parsing middleware. This functionality has moved into Hanami Action. (@timriley in #1575)
87
+
88
+ [3.0.0]: https://github.com/hanami/hanami/compare/v2.3.2...v3.0.0
89
+
90
+ ## [3.0.0.rc1] - 2026-06-16
91
+
92
+ ### Added
93
+
94
+ - Integrate hanami-mailer gem when bundled. (@timriley in #1597, #1600)
95
+
96
+ Load templates from `templates/mailers/`. Register a `"mailers.delivery_method"`, which is either an SMTP mailer when `SMTP_ADDRESS`, `SMTP_PORT`, `SMTP_USERNAME`, `SMTP_PASSWORD`, `SMTP_AUTHENTICATION` env vars are present. These can also be prefixed with a slice name. Register a test delivery always in the test env, and also in other envs when the env vars are absent.
97
+ - Integrate i18n gem when bundled. (@timriley in #1562, #1589, #1590, #1591, #1592, #1593)
98
+
99
+ Register an `"i18n"` component in each slice, which may be configured via `config.i18n` or a dedicated `:i18n` provider. Load translations from `config/i18n/` within each slice. Load shared translations from `config/i18n/shared/` at the app-level only. Bundle default English translations for `#localize`. Make helpers available in views and actions, which also prefix relative keys (with a leading ".") with their own dot-delimited template or action names.
100
+ - Wrap the configured app logger with `Hanami::UniversalLogger`, to provide a consistent logging interface regardless of the underlying logger. The app can now be depended upon to support (1) structured logging via keyword args passed to log methods, and (2) tagged logging via `#tagged`. (@timriley in #1567, #1568)
101
+ - Support `HANAMI_LOG_LEVEL` env var to set the log level (e.g. `HANAMI_LOG_LEVEL=warn bundle exec hanami server`). Takes precedence over `config.logger.level` set in `config/app.rb`. (@cllns in #1580)
102
+ - Add `config.db.log_level` setting, for changing the log level for SQL logs. (@katafrakt in #1587)
103
+ - New setting `:default_template_engine` that sets which template engine should be used by default when doing `hanami generate`. (@katafrakt in #1564)
104
+ - Add `Hanami::Settings::CompositeStore`, which can be used to chain setting lookups from multiple stores. (@aaronmallen in #1572)
105
+
106
+ ### Changed
107
+
108
+ - Default to memoizing all components, except in test env. Opt out for some or all components via `config.no_memoize`. (@timriley in #1573, #1599)
109
+ - Colorize logs by default in development env. (@timriley in #1566)
110
+ - Emit structured log entries for SQL queries, formatted consistently with request logs. (@timriley in #1569)
111
+ - Syntax highlight SQL in logs when the rouge gem is bundled. (@timriley in #1570)
112
+ - Colorize web request logs. (@timriley in #1571)
113
+ - Change default log level for SQL (and other database) statements from `:info` to `:debug`. (@katafrakt in #1595)
114
+ - Raise a helpful error message when the `Slice.call` Rack entrypoint is called and no routes are available. (@sandbergja in #1586)
115
+ - Apply extensions to hanami-action gem rather than hanami-controller (which is now retired). (@cllns in #1582)
116
+ - Redesign the new app welcome screen to match our new Hanakai visuals. (@makenosound in #1598)
117
+ - Require Ruby 3.3 or newer.
118
+
119
+ ### Removed
120
+
121
+ - Remove default body parsing middleware. This functionality has moved into Hanami Action. (@timriley in #1575)
122
+
123
+ [3.0.0.rc1]: https://github.com/hanami/hanami/compare/v2.3.2...v3.0.0.rc1
40
124
 
41
125
  ## [v2.3.2] - 2025-12-04
42
126
 
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015-2026 Hanakai team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,4 +1,14 @@
1
- # Hanami :cherry_blossom:
1
+ <!--- This file is synced from hanakai-rb/repo-sync -->
2
+
3
+ [actions]: https://github.com/hanami/hanami/actions
4
+ [chat]: https://discord.gg/naQApPAsZB
5
+ [forum]: https://discourse.hanamirb.org
6
+ [rubygem]: https://rubygems.org/gems/hanami
7
+
8
+ # Hanami [![Gem Version](https://badge.fury.io/rb/hanami.svg)][rubygem] [![CI Status](https://github.com/hanami/hanami/workflows/CI/badge.svg)][actions]
9
+
10
+ [![Forum](https://img.shields.io/badge/Forum-dc360f?logo=discourse&logoColor=white)][forum]
11
+ [![Chat](https://img.shields.io/badge/Chat-717cf8?logo=discord&logoColor=white)][chat]
2
12
 
3
13
  **A flexible framework for maintainable Ruby apps.**
4
14
 
@@ -7,18 +17,13 @@ Hanami is a **full-stack** Ruby web framework. It's made up of smaller, single-p
7
17
  This repository is for the full-stack framework, which provides the glue that ties all the parts together:
8
18
 
9
19
  * [**Hanami::Router**](https://github.com/hanami/router) - Rack compatible HTTP router for Ruby
10
- * [**Hanami::Controller**](https://github.com/hanami/controller) - Full featured, fast and testable actions for Rack
20
+ * [**Hanami::Action**](https://github.com/hanami/hanami-action) - Full featured, fast and testable actions for Rack
11
21
  * [**Hanami::View**](https://github.com/hanami/view) - Presentation with a separation between views and templates
12
22
  * [**Hanami::DB**](https://github.com/hanami/db) - Database integration, complete with migrations, repositories, relations, and structs
13
23
  * [**Hanami::Assets**](https://github.com/hanami/assets) - Assets management for Ruby
14
24
 
15
25
  These components are designed to be used independently or together in a Hanami application.
16
26
 
17
- ## Status
18
-
19
- [![Gem Version](https://badge.fury.io/rb/hanami.svg)](https://badge.fury.io/rb/hanami)
20
- [![CI](https://github.com/hanami/hanami/actions/workflows/ci.yml/badge.svg)](https://github.com/hanami/hanami/actions?query=workflow%3Aci+branch%3Amain)
21
-
22
27
  ## Installation
23
28
 
24
29
  ```shell
@@ -36,28 +41,9 @@ bundle exec hanami dev
36
41
 
37
42
  Please follow along with the [Getting Started guide](https://guides.hanamirb.org/getting-started/).
38
43
 
39
- ## Donations
40
-
41
- You can give back to Open Source, by supporting Hanami development via [GitHub Sponsors](https://github.com/sponsors/hanami).
42
-
43
- ## Contact
44
-
45
- * [Home page](http://hanamirb.org)
46
- * [Community](http://hanamirb.org/community)
47
- * [Guides](https://guides.hanamirb.org)
48
- * [Issues](https://github.com/hanami/hanami/issues)
49
- * [Forum](https://discourse.hanamirb.org)
50
- * [Chat](https://discord.gg/KFCxDmk3JQ)
51
-
52
- ## Community
53
-
54
- We care about building a friendly, inclusive and helpful community. We welcome people of all backgrounds, genders and experience levels, and respect you all equally.
55
-
56
- We do not tolerate nazis, transphobes, racists, or any kind of bigotry. See our [code of conduct](http://hanamirb.org/community/#code-of-conduct) for more.
57
-
58
44
  ## Contributing
59
45
 
60
- 1. Fork it ( https://github.com/hanami/hanami/fork )
46
+ 1. Fork it (https://github.com/hanami/hanami/fork)
61
47
  2. Create your feature branch (`git checkout -b my-new-feature`)
62
48
  3. Commit your changes (`git commit -am 'Add some feature'`)
63
49
  4. Push to the branch (`git push origin my-new-feature`)
@@ -91,16 +77,13 @@ To run a single test:
91
77
  $ bundle exec rspec path/to/spec.rb
92
78
  ```
93
79
 
94
- ### Development Requirements
80
+ ## Links
95
81
 
96
- * Ruby >= 3.2
97
- * Bundler
98
- * Node.js
82
+ - [User documentation](https://hanamirb.org)
83
+ - [API documentation](http://rubydoc.info/gems/hanami)
99
84
 
100
- ## Versioning
101
85
 
102
- Hanami uses [Semantic Versioning 2.0.0](http://semver.org).
86
+ ## License
103
87
 
104
- ## Copyright
88
+ See `LICENSE` file.
105
89
 
106
- Copyright © 2014–2025 Hanami Team – Released under MIT License.
data/hanami.gemspec CHANGED
@@ -1,50 +1,49 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- lib = File.expand_path("../lib", __FILE__)
4
- $LOAD_PATH.prepend(lib) unless $LOAD_PATH.include?(lib)
3
+ # This file is synced from hanakai-rb/repo-sync. To update it, edit repo-sync.yml.
4
+
5
+ lib = File.expand_path("lib", __dir__)
6
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
7
  require "hanami/version"
6
8
 
7
9
  Gem::Specification.new do |spec|
8
10
  spec.name = "hanami"
9
- spec.version = Hanami::VERSION
10
11
  spec.authors = ["Hanakai team"]
11
12
  spec.email = ["info@hanakai.org"]
12
- spec.summary = "A flexible framework for maintainable Ruby apps"
13
- spec.description = spec.summary
14
- spec.homepage = "http://hanamirb.org"
15
13
  spec.license = "MIT"
14
+ spec.version = Hanami::VERSION.dup
16
15
 
17
- spec.files = Dir[
18
- "CODE_OF_CONDUCT.md",
19
- "CHANGELOG.md",
20
- "FEATURES.md",
21
- "LICENSE.md",
22
- "README.md",
23
- "hanami.gemspec",
24
- "lib/**/*"
25
- ]
26
-
27
- spec.test_files = Dir["spec/**/*"]
16
+ spec.summary = "A flexible framework for maintainable Ruby apps"
17
+ spec.description = spec.summary
18
+ spec.homepage = "https://hanamirb.org"
19
+ spec.files = Dir["CHANGELOG.md", "LICENSE", "README.md", "hanami.gemspec", "lib/**/*"]
20
+ spec.bindir = "exe"
21
+ spec.executables = Dir["exe/*"].map { |f| File.basename(f) }
28
22
  spec.require_paths = ["lib"]
29
- spec.metadata["rubygems_mfa_required"] = "true"
30
- spec.required_ruby_version = ">= 3.2"
31
-
32
- spec.metadata["allowed_push_host"] = "https://rubygems.org"
33
-
34
- spec.add_dependency "bundler", ">= 2.0"
35
- spec.add_dependency "dry-configurable", "~> 1.0", ">= 1.2.0", "< 2"
36
- spec.add_dependency "dry-core", "~> 1.0", "< 2"
37
- spec.add_dependency "dry-inflector", "~> 1.0", ">= 1.1.0", "< 2"
38
- spec.add_dependency "dry-monitor", "~> 1.0", ">= 1.0.1", "< 2"
39
- spec.add_dependency "dry-system", "~> 1.1"
40
- spec.add_dependency "dry-logger", "~> 1.2", "< 2"
41
- spec.add_dependency "hanami-cli", ">= 2.3.1"
42
- spec.add_dependency "hanami-utils", ">= 2.3.0"
43
- spec.add_dependency "json", ">= 2.7.2"
44
- spec.add_dependency "zeitwerk", "~> 2.6"
45
- spec.add_dependency "rack-session"
46
-
47
- spec.add_development_dependency "rspec", "~> 3.8"
23
+
24
+ spec.extra_rdoc_files = ["README.md", "CHANGELOG.md", "LICENSE"]
25
+
26
+ spec.metadata["changelog_uri"] = "https://github.com/hanami/hanami/blob/main/CHANGELOG.md"
27
+ spec.metadata["source_code_uri"] = "https://github.com/hanami/hanami"
28
+ spec.metadata["bug_tracker_uri"] = "https://github.com/hanami/hanami/issues"
29
+ spec.metadata["funding_uri"] = "https://github.com/sponsors/hanami"
30
+
31
+ spec.required_ruby_version = ">= 3.3"
32
+
33
+ spec.add_runtime_dependency "bundler", ">= 2.0"
34
+ spec.add_runtime_dependency "dry-configurable", "~> 1.0", ">= 1.2.0", "< 2"
35
+ spec.add_runtime_dependency "dry-core", "~> 1.0", "< 2"
36
+ spec.add_runtime_dependency "dry-inflector", "~> 1.0", ">= 1.1.0", "< 2"
37
+ spec.add_runtime_dependency "dry-monitor", "~> 1.0", ">= 1.0.1", "< 2"
38
+ spec.add_runtime_dependency "dry-system", "~> 1.1"
39
+ spec.add_runtime_dependency "dry-logger", "~> 1.2", "< 2"
40
+ spec.add_runtime_dependency "hanami-cli", ">= 2.3.1"
41
+ spec.add_runtime_dependency "hanami-utils", "~> 3.0.0"
42
+ spec.add_runtime_dependency "json", ">= 2.7.2"
43
+ spec.add_runtime_dependency "zeitwerk", "~> 2.6"
44
+ spec.add_runtime_dependency "rack-session"
45
+ spec.add_development_dependency "rspec", "~> 3.8"
48
46
  spec.add_development_dependency "rack-test", "~> 2.0"
49
- spec.add_development_dependency "rake", "~> 13.0"
47
+ spec.add_development_dependency "rake", "~> 13.0"
50
48
  end
49
+
data/lib/hanami/app.rb CHANGED
@@ -151,12 +151,22 @@ module Hanami
151
151
  require_relative "providers/inflector"
152
152
  register_provider(:inflector, source: Hanami::Providers::Inflector)
153
153
 
154
- # Allow logger to be replaced by users with a manual provider, for advanced cases
154
+ # Allow the logger to be replaced by users with a manual provider, for advanced cases.
155
+ #
156
+ # Require the logger provider source up front, to make `configure_provider(:logger)`
157
+ # possible.
158
+ require_relative "providers/logger"
155
159
  unless container.providers[:logger]
156
- require_relative "providers/logger"
157
160
  register_provider(:logger, source: Hanami::Providers::Logger)
158
161
  end
159
162
 
163
+ # Ensure the logger is wrapped by `Hanami::UniversalLogger`, even if manually registered in a
164
+ # user-defined provider, guaranteeing Hanami's structured and tagged logging interface across
165
+ # the framework.
166
+ container.providers[:logger].source.after(:start) do
167
+ container.decorate(:logger) { |logger| Hanami::UniversalLogger[logger] }
168
+ end
169
+
160
170
  if Hanami.bundled?("rack")
161
171
  require_relative "providers/rack"
162
172
  register_provider(:rack, source: Hanami::Providers::Rack, namespace: true)
@@ -15,6 +15,8 @@ module Hanami
15
15
 
16
16
  setting :import_from_parent, default: false
17
17
 
18
+ setting :log_level, default: :debug
19
+
18
20
  private
19
21
 
20
22
  def method_missing(name, *args, &block)
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/configurable"
4
+ require_relative "../providers/i18n"
5
+
6
+ module Hanami
7
+ class Config
8
+ # Hanami I18n config
9
+ #
10
+ # @api public
11
+ # @since 3.0.0
12
+ class I18n
13
+ include Dry::Configurable
14
+
15
+ # @!attribute [rw] default_locale
16
+ # Sets or returns the default locale to use for translations.
17
+ #
18
+ # Defaults to `:en`.
19
+ #
20
+ # @return [Symbol]
21
+ #
22
+ # @example
23
+ # config.i18n.default_locale = :fr
24
+ #
25
+ # @api public
26
+ # @since 3.0.0
27
+ setting :default_locale, default: Providers::I18n::DEFAULT_LOCALE
28
+
29
+ # @!attribute [rw] available_locales
30
+ # Sets or returns the array of available locales for the application.
31
+ #
32
+ # When set, only these locales will be considered available, even if translation files exist
33
+ # for other locales. When empty or not set, all locales from loaded translation files are
34
+ # available.
35
+ #
36
+ # Defaults to `[]` (all loaded locales are available).
37
+ #
38
+ # @return [Array<Symbol>]
39
+ #
40
+ # @example Restrict to specific locales
41
+ # config.i18n.available_locales = [:en, :fr, :de]
42
+ #
43
+ # @api public
44
+ # @since 3.0.0
45
+ setting :available_locales, default: Providers::I18n::DEFAULT_AVAILABLE_LOCALES
46
+
47
+ # @!attribute [rw] load_path
48
+ # Sets or returns the array of file path patterns for loading per-slice translation files.
49
+ #
50
+ # Patterns can be:
51
+ #
52
+ # - Relative paths/globs (resolved against the slice's own root)
53
+ # - Absolute paths (used as-is)
54
+ #
55
+ # Defaults to `["config/i18n/**/*.{yml,yaml,json,rb}"]`.
56
+ #
57
+ # See {#shared_load_path} for common translations that should be loaded into every slice.
58
+ #
59
+ # @return [Array<String>]
60
+ #
61
+ # @example Append custom paths
62
+ # config.i18n.load_path += ["config/custom_translations/**/*.yml"]
63
+ #
64
+ # @example Replace default paths
65
+ # config.i18n.load_path = ["translations/**/*.yml"]
66
+ #
67
+ # @api public
68
+ # @since 3.0.0
69
+ setting :load_path, default: Providers::I18n::DEFAULT_LOAD_PATH
70
+
71
+ # @!attribute [rw] shared_load_path
72
+ # Sets or returns the array of file path patterns for loading translation files that
73
+ # should be shared across every slice in the app.
74
+ #
75
+ # Relative patterns are resolved against the **app root**, regardless of which slice is
76
+ # being loaded. Absolute paths are used as-is. Files matched by these patterns are loaded
77
+ # into every slice's i18n backend before that slice's own {#load_path} files, so
78
+ # slice-specific translations override shared ones on key conflicts.
79
+ #
80
+ # This is the recommended place for foundational translation data needed by every slice,
81
+ # such as the `date.*` and `time.*` keys used by `localize`.
82
+ #
83
+ # Defaults to `["config/i18n/shared/**/*.{yml,yaml,json,rb}"]`.
84
+ #
85
+ # @return [Array<String>]
86
+ #
87
+ # @example Disable shared translations
88
+ # config.i18n.shared_load_path = []
89
+ #
90
+ # @example Add another shared source
91
+ # config.i18n.shared_load_path += ["vendor/translations/**/*.yml"]
92
+ #
93
+ # @api public
94
+ # @since 3.0.0
95
+ setting :shared_load_path, default: Providers::I18n::DEFAULT_SHARED_LOAD_PATH
96
+
97
+ # @!attribute [rw] fallbacks
98
+ # Sets or returns the locale fallbacks configuration for missing translations.
99
+ #
100
+ # When enabled, the i18n backend will fall back to other locales when a translation is
101
+ # missing in the requested locale.
102
+ #
103
+ # This can be set to `true` to enable default fallbacks, a hash to configure explicit
104
+ # fallback chains per locale, or an array to set a default fallback locale for all locales.
105
+ #
106
+ # Defaults to `nil` (fallbacks disabled).
107
+ #
108
+ # @return [Boolean, Hash, Array, nil]
109
+ #
110
+ # @example Enable default fallbacks
111
+ # config.i18n.fallbacks = true
112
+ #
113
+ # @example Configure fallbacks with a hash
114
+ # config.i18n.fallbacks = {de: [:de, :en], fr: [:fr, :en]}
115
+ #
116
+ # @example Configure a default fallback locale
117
+ # config.i18n.fallbacks = [:en]
118
+ #
119
+ # @api public
120
+ # @since 3.0.0
121
+ setting :fallbacks
122
+
123
+ private
124
+
125
+ def method_missing(name, *args, &block)
126
+ if config.respond_to?(name)
127
+ config.public_send(name, *args, &block)
128
+ else
129
+ super
130
+ end
131
+ end
132
+
133
+ def respond_to_missing?(name, _include_all = false)
134
+ config.respond_to?(name) || super
135
+ end
136
+ end
137
+ end
138
+ end
@@ -28,6 +28,7 @@ module Hanami
28
28
  # Sets or returns the logger's level.
29
29
  #
30
30
  # Defaults to `:info` for the production environment and `:debug` for all others.
31
+ # Can be set via the `HANAMI_LOG_LEVEL` environment variable.
31
32
  #
32
33
  # @return [Symbol]
33
34
  #
@@ -122,9 +123,13 @@ module Hanami
122
123
  @env = env
123
124
 
124
125
  case env
125
- when :development, :test
126
+ when :development
126
127
  config.level = :debug
127
- config.stream = File.join("log", "#{env}.log") if env == :test
128
+ config.options = {colorize: true}
129
+ config.logger_constructor = method(:development_logger)
130
+ when :test
131
+ config.level = :debug
132
+ config.stream = File.join("log", "#{env}.log")
128
133
  config.logger_constructor = method(:development_logger)
129
134
  else
130
135
  config.level = :info
@@ -153,8 +158,9 @@ module Hanami
153
158
  def development_logger(_env, app_name, **options)
154
159
  Dry.Logger(app_name, **options) do |setup|
155
160
  setup
156
- .add_backend(log_if: -> entry { !entry.tag?(:rack) })
157
- .add_backend(formatter: :rack, log_if: -> entry { entry.tag?(:rack) })
161
+ .add_backend(log_if: -> entry { !entry.tag?(:rack) && !entry.tag?(:sql) })
162
+ .add_backend(log_if: -> entry { entry.tag?(:rack) }, formatter: Hanami::Logger::RackFormatter)
163
+ .add_backend(log_if: -> entry { entry.tag?(:sql) }, formatter: Hanami::Logger::SQLFormatter)
158
164
  end
159
165
  end
160
166
 
@@ -173,12 +179,14 @@ module Hanami
173
179
 
174
180
  # @api private
175
181
  def logger_constructor_options
176
- {stream: stream,
177
- level: level,
182
+ {
183
+ stream: stream,
184
+ level: ENV["HANAMI_LOG_LEVEL"]&.to_sym || level,
178
185
  formatter: formatter,
179
186
  filters: filters,
180
187
  template: template,
181
- **options}
188
+ **options
189
+ }
182
190
  end
183
191
 
184
192
  # @api private
@@ -5,7 +5,7 @@ require "dry/configurable"
5
5
  module Hanami
6
6
  class Config
7
7
  # NullConfig can serve as a fallback config object when out-of-gem config objects are not
8
- # available (specifically, when the hanami-controller, hanami-router or hanami-view gems are not
8
+ # available (specifically, when the hanami-action, hanami-router or hanami-view gems are not
9
9
  # loaded)
10
10
  class NullConfig
11
11
  include Dry::Configurable
@@ -16,6 +16,23 @@ module Hanami
16
16
  class Views
17
17
  include Dry::Configurable
18
18
 
19
+ # @!attribute [rw] default_template_engine
20
+ # Sets or returns the default template engine to use for generated views.
21
+ #
22
+ # Used by generators when no explicit template engine is specified.
23
+ # Supports `erb`, `haml`, and `slim`.
24
+ #
25
+ # Defaults to `"erb"`.
26
+ #
27
+ # @example
28
+ # config.views.default_template_engine = "slim"
29
+ #
30
+ # @return [String] the template engine name
31
+ #
32
+ # @api public
33
+ # @since 2.4.0
34
+ setting :default_template_engine, default: "erb"
35
+
19
36
  # @api private
20
37
  # @since 2.1.0
21
38
  attr_reader :base_config