hanami 2.0.0.alpha8 → 2.0.0.beta1

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 (224) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +442 -241
  3. data/FEATURES.md +30 -9
  4. data/README.md +1 -3
  5. data/hanami.gemspec +21 -11
  6. data/lib/hanami/app.rb +141 -0
  7. data/lib/hanami/assets/application_configuration.rb +10 -4
  8. data/lib/hanami/configuration/actions/content_security_policy.rb +5 -5
  9. data/lib/hanami/configuration/actions/cookies.rb +2 -2
  10. data/lib/hanami/configuration/actions.rb +10 -4
  11. data/lib/hanami/configuration/logger.rb +4 -4
  12. data/lib/hanami/configuration/router.rb +2 -6
  13. data/lib/hanami/configuration/sessions.rb +1 -1
  14. data/lib/hanami/configuration/views.rb +9 -4
  15. data/lib/hanami/configuration.rb +118 -46
  16. data/lib/hanami/constants.rb +24 -2
  17. data/lib/hanami/errors.rb +1 -1
  18. data/lib/hanami/{application → extensions}/action/slice_configured_action.rb +9 -9
  19. data/lib/hanami/extensions/action.rb +79 -0
  20. data/lib/hanami/extensions/view/context.rb +106 -0
  21. data/lib/hanami/{application → extensions}/view/slice_configured_context.rb +10 -10
  22. data/lib/hanami/{application → extensions}/view/slice_configured_view.rb +12 -6
  23. data/lib/hanami/extensions/view.rb +33 -0
  24. data/lib/hanami/extensions.rb +10 -0
  25. data/lib/hanami/providers/inflector.rb +13 -0
  26. data/lib/hanami/providers/logger.rb +13 -0
  27. data/lib/hanami/providers/rack.rb +27 -0
  28. data/lib/hanami/providers/routes.rb +33 -0
  29. data/lib/hanami/providers/settings.rb +23 -0
  30. data/lib/hanami/rake_tasks.rb +61 -0
  31. data/lib/hanami/routes.rb +51 -0
  32. data/lib/hanami/server.rb +1 -1
  33. data/lib/hanami/settings/dotenv_store.rb +58 -0
  34. data/lib/hanami/settings.rb +90 -0
  35. data/lib/hanami/setup.rb +4 -2
  36. data/lib/hanami/{application → slice}/router.rb +18 -13
  37. data/lib/hanami/slice/routes_helper.rb +37 -0
  38. data/lib/hanami/{application → slice}/routing/middleware/stack.rb +43 -5
  39. data/lib/hanami/slice/routing/resolver.rb +97 -0
  40. data/lib/hanami/{application → slice}/view_name_inferrer.rb +3 -3
  41. data/lib/hanami/slice.rb +246 -73
  42. data/lib/hanami/slice_configurable.rb +4 -17
  43. data/lib/hanami/slice_name.rb +6 -6
  44. data/lib/hanami/slice_registrar.rb +119 -0
  45. data/lib/hanami/version.rb +1 -1
  46. data/lib/hanami/web/rack_logger.rb +1 -1
  47. data/lib/hanami.rb +34 -26
  48. data/spec/integration/application_middleware_stack_spec.rb +84 -0
  49. data/spec/integration/assets/cdn_spec.rb +48 -0
  50. data/spec/integration/assets/fingerprint_spec.rb +42 -0
  51. data/spec/integration/assets/helpers_spec.rb +50 -0
  52. data/spec/integration/assets/serve_spec.rb +70 -0
  53. data/spec/integration/assets/subresource_integrity_spec.rb +54 -0
  54. data/spec/integration/body_parsers_spec.rb +50 -0
  55. data/spec/integration/cli/assets/precompile_spec.rb +147 -0
  56. data/spec/integration/cli/assets_spec.rb +14 -0
  57. data/spec/integration/cli/console_spec.rb +105 -0
  58. data/spec/integration/cli/db/apply_spec.rb +74 -0
  59. data/spec/integration/cli/db/console_spec.rb +40 -0
  60. data/spec/integration/cli/db/create_spec.rb +50 -0
  61. data/spec/integration/cli/db/drop_spec.rb +54 -0
  62. data/spec/integration/cli/db/migrate_spec.rb +108 -0
  63. data/spec/integration/cli/db/prepare_spec.rb +36 -0
  64. data/spec/integration/cli/db/rollback_spec.rb +96 -0
  65. data/spec/integration/cli/db/version_spec.rb +38 -0
  66. data/spec/integration/cli/db_spec.rb +21 -0
  67. data/spec/integration/cli/destroy/action_spec.rb +143 -0
  68. data/spec/integration/cli/destroy/app_spec.rb +118 -0
  69. data/spec/integration/cli/destroy/mailer_spec.rb +74 -0
  70. data/spec/integration/cli/destroy/migration_spec.rb +70 -0
  71. data/spec/integration/cli/destroy/model_spec.rb +113 -0
  72. data/spec/integration/cli/destroy_spec.rb +18 -0
  73. data/spec/integration/cli/generate/action_spec.rb +469 -0
  74. data/spec/integration/cli/generate/app_spec.rb +215 -0
  75. data/spec/integration/cli/generate/mailer_spec.rb +189 -0
  76. data/spec/integration/cli/generate/migration_spec.rb +72 -0
  77. data/spec/integration/cli/generate/model_spec.rb +290 -0
  78. data/spec/integration/cli/generate/secret_spec.rb +56 -0
  79. data/spec/integration/cli/generate_spec.rb +19 -0
  80. data/spec/integration/cli/new/database_spec.rb +235 -0
  81. data/spec/integration/cli/new/hanami_head_spec.rb +27 -0
  82. data/spec/integration/cli/new/template_spec.rb +118 -0
  83. data/spec/integration/cli/new/test_spec.rb +274 -0
  84. data/spec/integration/cli/new_spec.rb +970 -0
  85. data/spec/integration/cli/plugins_spec.rb +39 -0
  86. data/spec/integration/cli/routes_spec.rb +49 -0
  87. data/spec/integration/cli/server_spec.rb +626 -0
  88. data/spec/integration/cli/version_spec.rb +85 -0
  89. data/spec/integration/early_hints_spec.rb +35 -0
  90. data/spec/integration/handle_exceptions_spec.rb +244 -0
  91. data/spec/integration/head_spec.rb +89 -0
  92. data/spec/integration/http_headers_spec.rb +29 -0
  93. data/spec/integration/mailer_spec.rb +32 -0
  94. data/spec/integration/middleware_spec.rb +81 -0
  95. data/spec/integration/mount_applications_spec.rb +88 -0
  96. data/spec/integration/project_initializers_spec.rb +40 -0
  97. data/spec/integration/rackup_spec.rb +35 -0
  98. data/spec/integration/rake/with_minitest_spec.rb +67 -0
  99. data/spec/integration/rake/with_rspec_spec.rb +69 -0
  100. data/spec/integration/routing_helpers_spec.rb +61 -0
  101. data/spec/integration/security/content_security_policy_spec.rb +46 -0
  102. data/spec/integration/security/csrf_protection_spec.rb +42 -0
  103. data/spec/integration/security/force_ssl_spec.rb +29 -0
  104. data/spec/integration/security/x_content_type_options_spec.rb +46 -0
  105. data/spec/integration/security/x_frame_options_spec.rb +46 -0
  106. data/spec/integration/security/x_xss_protection_spec.rb +46 -0
  107. data/spec/integration/send_file_spec.rb +51 -0
  108. data/spec/integration/sessions_spec.rb +247 -0
  109. data/spec/integration/static_middleware_spec.rb +21 -0
  110. data/spec/integration/streaming_spec.rb +41 -0
  111. data/spec/integration/unsafe_send_file_spec.rb +52 -0
  112. data/spec/isolation/hanami/application/already_configured_spec.rb +19 -0
  113. data/spec/isolation/hanami/application/inherit_anonymous_class_spec.rb +10 -0
  114. data/spec/isolation/hanami/application/inherit_concrete_class_spec.rb +14 -0
  115. data/spec/isolation/hanami/application/not_configured_spec.rb +9 -0
  116. data/spec/isolation/hanami/application/routes/configured_spec.rb +44 -0
  117. data/spec/isolation/hanami/application/routes/not_configured_spec.rb +16 -0
  118. data/spec/isolation/hanami/boot/success_spec.rb +50 -0
  119. data/spec/new_integration/action/configuration_spec.rb +26 -0
  120. data/spec/new_integration/action/cookies_spec.rb +58 -0
  121. data/spec/new_integration/action/csrf_protection_spec.rb +54 -0
  122. data/spec/new_integration/action/routes_spec.rb +73 -0
  123. data/spec/new_integration/action/sessions_spec.rb +50 -0
  124. data/spec/new_integration/action/view_integration_spec.rb +165 -0
  125. data/spec/new_integration/action/view_rendering/automatic_rendering_spec.rb +247 -0
  126. data/spec/new_integration/action/view_rendering/paired_view_inference_spec.rb +115 -0
  127. data/spec/new_integration/action/view_rendering_spec.rb +107 -0
  128. data/spec/new_integration/code_loading/loading_from_app_spec.rb +152 -0
  129. data/spec/new_integration/code_loading/loading_from_slice_spec.rb +165 -0
  130. data/spec/new_integration/container/application_routes_helper_spec.rb +48 -0
  131. data/spec/new_integration/container/auto_injection_spec.rb +53 -0
  132. data/spec/new_integration/container/auto_registration_spec.rb +86 -0
  133. data/spec/new_integration/container/autoloader_spec.rb +80 -0
  134. data/spec/new_integration/container/imports_spec.rb +253 -0
  135. data/spec/new_integration/container/prepare_container_spec.rb +123 -0
  136. data/spec/new_integration/container/shutdown_spec.rb +91 -0
  137. data/spec/new_integration/container/standard_bootable_components_spec.rb +124 -0
  138. data/spec/new_integration/rack_app/middleware_spec.rb +215 -0
  139. data/spec/new_integration/rack_app/non_booted_rack_app_spec.rb +105 -0
  140. data/spec/new_integration/rack_app/rack_app_spec.rb +524 -0
  141. data/spec/new_integration/settings_spec.rb +115 -0
  142. data/spec/new_integration/slices/external_slice_spec.rb +92 -0
  143. data/spec/new_integration/slices/slice_configuration_spec.rb +40 -0
  144. data/spec/new_integration/slices/slice_routing_spec.rb +226 -0
  145. data/spec/new_integration/slices/slice_settings_spec.rb +141 -0
  146. data/spec/new_integration/slices_spec.rb +101 -0
  147. data/spec/new_integration/view/configuration_spec.rb +49 -0
  148. data/spec/new_integration/view/context/assets_spec.rb +67 -0
  149. data/spec/new_integration/view/context/inflector_spec.rb +48 -0
  150. data/spec/new_integration/view/context/request_spec.rb +61 -0
  151. data/spec/new_integration/view/context/routes_spec.rb +86 -0
  152. data/spec/new_integration/view/context/settings_spec.rb +50 -0
  153. data/spec/new_integration/view/inflector_spec.rb +57 -0
  154. data/spec/new_integration/view/part_namespace_spec.rb +96 -0
  155. data/spec/new_integration/view/path_spec.rb +56 -0
  156. data/spec/new_integration/view/template_spec.rb +68 -0
  157. data/spec/new_integration/view/views_spec.rb +103 -0
  158. data/spec/spec_helper.rb +16 -0
  159. data/spec/support/app_integration.rb +91 -0
  160. data/spec/support/coverage.rb +1 -0
  161. data/spec/support/fixtures/hanami-plugin/Gemfile +8 -0
  162. data/spec/support/fixtures/hanami-plugin/README.md +35 -0
  163. data/spec/support/fixtures/hanami-plugin/Rakefile +4 -0
  164. data/spec/support/fixtures/hanami-plugin/bin/console +15 -0
  165. data/spec/support/fixtures/hanami-plugin/bin/setup +8 -0
  166. data/spec/support/fixtures/hanami-plugin/hanami-plugin.gemspec +28 -0
  167. data/spec/support/fixtures/hanami-plugin/lib/hanami/plugin/cli.rb +19 -0
  168. data/spec/support/fixtures/hanami-plugin/lib/hanami/plugin/version.rb +7 -0
  169. data/spec/support/fixtures/hanami-plugin/lib/hanami/plugin.rb +8 -0
  170. data/spec/support/rspec.rb +27 -0
  171. data/spec/support/shared_examples/cli/generate/app.rb +494 -0
  172. data/spec/support/shared_examples/cli/generate/migration.rb +32 -0
  173. data/spec/support/shared_examples/cli/generate/model.rb +81 -0
  174. data/spec/support/shared_examples/cli/new.rb +97 -0
  175. data/spec/unit/hanami/configuration/actions/content_security_policy_spec.rb +102 -0
  176. data/spec/unit/hanami/configuration/actions/cookies_spec.rb +46 -0
  177. data/spec/unit/hanami/configuration/actions/csrf_protection_spec.rb +57 -0
  178. data/spec/unit/hanami/configuration/actions/default_values_spec.rb +52 -0
  179. data/spec/unit/hanami/configuration/actions/sessions_spec.rb +50 -0
  180. data/spec/unit/hanami/configuration/actions_spec.rb +78 -0
  181. data/spec/unit/hanami/configuration/base_url_spec.rb +25 -0
  182. data/spec/unit/hanami/configuration/inflector_spec.rb +35 -0
  183. data/spec/unit/hanami/configuration/logger_spec.rb +203 -0
  184. data/spec/unit/hanami/configuration/views_spec.rb +120 -0
  185. data/spec/unit/hanami/configuration_spec.rb +43 -0
  186. data/spec/unit/hanami/env_spec.rb +54 -0
  187. data/spec/unit/hanami/routes_spec.rb +25 -0
  188. data/spec/unit/hanami/settings/dotenv_store_spec.rb +119 -0
  189. data/spec/unit/hanami/settings_spec.rb +56 -0
  190. data/spec/unit/hanami/slice_configurable_spec.rb +104 -0
  191. data/spec/unit/hanami/slice_name_spec.rb +47 -0
  192. data/spec/unit/hanami/slice_spec.rb +17 -0
  193. data/spec/unit/hanami/version_spec.rb +7 -0
  194. data/spec/unit/hanami/web/rack_logger_spec.rb +78 -0
  195. metadata +353 -57
  196. data/lib/hanami/application/action.rb +0 -72
  197. data/lib/hanami/application/container/providers/inflector.rb +0 -7
  198. data/lib/hanami/application/container/providers/logger.rb +0 -7
  199. data/lib/hanami/application/container/providers/rack_logger.rb +0 -15
  200. data/lib/hanami/application/container/providers/rack_monitor.rb +0 -12
  201. data/lib/hanami/application/container/providers/routes_helper.rb +0 -9
  202. data/lib/hanami/application/container/providers/settings.rb +0 -7
  203. data/lib/hanami/application/routes.rb +0 -55
  204. data/lib/hanami/application/routes_helper.rb +0 -34
  205. data/lib/hanami/application/routing/resolver/node.rb +0 -50
  206. data/lib/hanami/application/routing/resolver/trie.rb +0 -59
  207. data/lib/hanami/application/routing/resolver.rb +0 -87
  208. data/lib/hanami/application/routing/router.rb +0 -36
  209. data/lib/hanami/application/settings/dotenv_store.rb +0 -60
  210. data/lib/hanami/application/settings.rb +0 -93
  211. data/lib/hanami/application/slice_registrar.rb +0 -106
  212. data/lib/hanami/application/view/context.rb +0 -95
  213. data/lib/hanami/application/view.rb +0 -24
  214. data/lib/hanami/application.rb +0 -273
  215. data/lib/hanami/cli/application/cli.rb +0 -40
  216. data/lib/hanami/cli/application/command.rb +0 -47
  217. data/lib/hanami/cli/application/commands/console.rb +0 -81
  218. data/lib/hanami/cli/application/commands.rb +0 -16
  219. data/lib/hanami/cli/base_command.rb +0 -48
  220. data/lib/hanami/cli/commands/command.rb +0 -171
  221. data/lib/hanami/cli/commands/server.rb +0 -88
  222. data/lib/hanami/cli/commands.rb +0 -65
  223. data/lib/hanami/configuration/middleware.rb +0 -20
  224. data/lib/hanami/configuration/source_dirs.rb +0 -42
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "App action / View rendering", :app_integration do
4
+ specify "Views render with a request-specific context object" do
5
+ with_tmp_directory(Dir.mktmpdir) do
6
+ write "config/app.rb", <<~RUBY
7
+ require "hanami"
8
+
9
+ module TestApp
10
+ class App < Hanami::App
11
+ end
12
+ end
13
+ RUBY
14
+
15
+ write "app/action.rb", <<~RUBY
16
+ # auto_register: false
17
+
18
+ module TestApp
19
+ class Action < Hanami::Action
20
+ end
21
+ end
22
+ RUBY
23
+
24
+ write "app/view.rb", <<~RUBY
25
+ # auto_register: false
26
+
27
+ require "hanami/view"
28
+
29
+ module TestApp
30
+ class View < Hanami::View
31
+ end
32
+ end
33
+ RUBY
34
+
35
+ write "app/views/context.rb", <<~RUBY
36
+ require "hanami/view/context"
37
+
38
+ module TestApp
39
+ module Views
40
+ class Context < Hanami::View::Context
41
+ def request
42
+ _options.fetch(:request)
43
+ end
44
+
45
+ def response
46
+ _options.fetch(:response)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ RUBY
52
+
53
+ write "app/actions/users/show.rb", <<~RUBY
54
+ module TestApp
55
+ module Actions
56
+ module Users
57
+ class Show < TestApp::Action
58
+ include Deps[view: "views.users.show"]
59
+
60
+ def handle(req, res)
61
+ res[:job] = "Singer"
62
+ res[:age] = 0
63
+
64
+ res.render view, name: req.params[:name], age: 51
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ RUBY
71
+
72
+ write "app/views/users/show.rb", <<~RUBY
73
+ module TestApp
74
+ module Views
75
+ module Users
76
+ class Show < TestApp::View
77
+ expose :name, :job, :age
78
+ end
79
+ end
80
+ end
81
+ end
82
+ RUBY
83
+
84
+ write "app/templates/layouts/app.html.slim", <<~SLIM
85
+ html
86
+ body
87
+ == yield
88
+ SLIM
89
+
90
+ write "app/templates/users/show.html.slim", <<~'SLIM'
91
+ h1 Hello, #{name}
92
+ - request.params.to_h.values.sort.each do |value|
93
+ p = value
94
+ p = job
95
+ p = age
96
+ SLIM
97
+
98
+ require "hanami/prepare"
99
+
100
+ action = TestApp::App["actions.users.show"]
101
+ response = action.(name: "Jennifer", last_name: "Lopez")
102
+ rendered = response.body[0]
103
+
104
+ expect(rendered).to eq "<html><body><h1>Hello, Jennifer</h1><p>Jennifer</p><p>Lopez</p><p>Singer</p><p>51</p></body></html>"
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "Code loading / Loading from app directory", :app_integration do
4
+ before :context do
5
+ with_directory(@dir = make_tmp_directory) do
6
+ write "config/app.rb", <<~'RUBY'
7
+ require "hanami"
8
+
9
+ module TestApp
10
+ class App < Hanami::App
11
+ end
12
+ end
13
+ RUBY
14
+
15
+ write "app/test_class.rb", <<~'RUBY'
16
+ module TestApp
17
+ class TestClass
18
+ end
19
+ end
20
+ RUBY
21
+
22
+ write "app/action.rb", <<~'RUBY'
23
+ # auto_register: false
24
+
25
+ module TestApp
26
+ class Action < Hanami::Action
27
+ end
28
+ end
29
+ RUBY
30
+
31
+ write "app/actions/home/show.rb", <<~'RUBY'
32
+ module TestApp
33
+ module Actions
34
+ module Home
35
+ class Show < TestApp::Action
36
+ end
37
+ end
38
+ end
39
+ end
40
+ RUBY
41
+ end
42
+ end
43
+
44
+ before do
45
+ with_directory(@dir) do
46
+ require "hanami/prepare"
47
+ end
48
+ end
49
+
50
+ specify "Classes in app/ directory are autoloaded with the app namespace" do
51
+ expect(TestApp::TestClass).to be
52
+ expect(TestApp::Action).to be
53
+ expect(TestApp::Actions::Home::Show).to be
54
+ end
55
+
56
+ specify "Classes in app directory are auto-registered" do
57
+ expect(TestApp::App["test_class"]).to be_an_instance_of TestApp::TestClass
58
+ expect(TestApp::App["actions.home.show"]).to be_an_instance_of TestApp::Actions::Home::Show
59
+
60
+ # Files with "auto_register: false" magic comments are not auto-registered
61
+ expect(TestApp::App.key?("action")).to be false
62
+ end
63
+
64
+ describe "app/lib/ directory" do
65
+ before :context do
66
+ with_directory(@dir = make_tmp_directory) do
67
+ write "config/app.rb", <<~'RUBY'
68
+ require "hanami"
69
+
70
+ module TestApp
71
+ class App < Hanami::App
72
+ end
73
+ end
74
+ RUBY
75
+
76
+ write "app/lib/test_class.rb", <<~'RUBY'
77
+ module TestApp
78
+ class TestClass
79
+ end
80
+ end
81
+ RUBY
82
+ end
83
+ end
84
+
85
+ specify "Classes in app/lib/ directory are autoloaded with the app namespace" do
86
+ expect(TestApp::TestClass).to be
87
+ end
88
+
89
+ specify "Classes in app/lib/ directory are auto-registered" do
90
+ expect(TestApp::App["test_class"]).to be_an_instance_of TestApp::TestClass
91
+ end
92
+
93
+ specify "Classes in app/lib/ directory are not redundantly auto-registered under 'lib' key namespace" do
94
+ expect(TestApp::App.key?("lib.test_class")).to be false
95
+ end
96
+ end
97
+
98
+ # rubocop:disable Style/GlobalVars
99
+ describe "same-named class defined in both app/ and app/lib/ directories" do
100
+ before :context do
101
+ with_directory(@dir = make_tmp_directory) do
102
+ write "config/app.rb", <<~'RUBY'
103
+ require "hanami"
104
+
105
+ module TestApp
106
+ class App < Hanami::App
107
+ end
108
+ end
109
+ RUBY
110
+
111
+ write "app/test_class.rb", <<~'RUBY'
112
+ $app_class_loaded = true
113
+
114
+ module TestApp
115
+ class TestClass
116
+ (@loaded_from ||= []) << "app"
117
+ end
118
+ end
119
+ RUBY
120
+
121
+ write "app/lib/test_class.rb", <<~'RUBY'
122
+ $app_lib_class_loaded = true
123
+
124
+ module TestApp
125
+ class TestClass
126
+ (@loaded_from ||= []) << "app/lib"
127
+ end
128
+ end
129
+ RUBY
130
+ end
131
+ end
132
+
133
+ after do
134
+ $app_class_loaded = $app_lib_class_loaded = nil
135
+ end
136
+
137
+ specify "Classes in app/lib/ directory are preferred for autoloading" do
138
+ expect(TestApp::TestClass).to be
139
+ expect(TestApp::TestClass.instance_variable_get(:@loaded_from)).to eq ["app/lib"]
140
+ expect($app_lib_class_loaded).to be true
141
+ expect($app_class_loaded).to be nil
142
+ end
143
+
144
+ specify "Classes in app/lib/ directory are preferred for auto-registration" do
145
+ expect(TestApp::App["test_class"]).to be
146
+ expect(TestApp::TestClass.instance_variable_get(:@loaded_from)).to eq ["app/lib"]
147
+ expect($app_lib_class_loaded).to be true
148
+ expect($app_class_loaded).to be nil
149
+ end
150
+ end
151
+ # rubocop:enable Style/GlobalVars
152
+ end
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "Code loading / Loading from slice directory", :app_integration do
4
+ before :context do
5
+ with_directory(@dir = make_tmp_directory) do
6
+ write "config/app.rb", <<~'RUBY'
7
+ require "hanami"
8
+
9
+ module TestApp
10
+ class App < Hanami::App
11
+ end
12
+ end
13
+ RUBY
14
+
15
+ write "slices/main/config/not_loadable.rb", <<~'RUBY'
16
+ raise "This file should never be loaded"
17
+ RUBY
18
+
19
+ write "slices/main/test_class.rb", <<~'RUBY'
20
+ module Main
21
+ class TestClass
22
+ end
23
+ end
24
+ RUBY
25
+
26
+ write "slices/main/action.rb", <<~'RUBY'
27
+ # auto_register: false
28
+
29
+ module Main
30
+ class Action < Hanami::Action
31
+ end
32
+ end
33
+ RUBY
34
+
35
+ write "slices/main/actions/home/show.rb", <<~'RUBY'
36
+ module Main
37
+ module Actions
38
+ module Home
39
+ class Show < Main::Action
40
+ end
41
+ end
42
+ end
43
+ end
44
+ RUBY
45
+ end
46
+ end
47
+
48
+ before do
49
+ with_directory(@dir) do
50
+ require "hanami/prepare"
51
+ end
52
+ end
53
+
54
+ specify "Classes in slice directory are autoloaded with the slice namespace" do
55
+ expect(Main::TestClass).to be
56
+ expect(Main::Action).to be
57
+ expect(Main::Actions::Home::Show).to be
58
+ end
59
+
60
+ specify "Files in slice config/ directory are not autoloaded" do
61
+ expect { Main::NotLoadable }.to raise_error NameError
62
+ expect { Main::Config::NotLoadable }.to raise_error NameError
63
+ end
64
+
65
+ specify "Classes in slice directory are auto-registered" do
66
+ expect(Main::Slice["test_class"]).to be_an_instance_of Main::TestClass
67
+ expect(Main::Slice["actions.home.show"]).to be_an_instance_of Main::Actions::Home::Show
68
+
69
+ # Files with "auto_register: false" magic comments are not auto-registered
70
+ expect(Main::Slice.key?("action")).to be false
71
+ end
72
+
73
+ specify "Files in slice config/ directory are not auto-registered" do
74
+ expect(Main::Slice.key?("config.settings")).to be false
75
+ end
76
+
77
+ describe "slice lib/ directory" do
78
+ before :context do
79
+ with_directory(@dir = make_tmp_directory) do
80
+ write "config/app.rb", <<~'RUBY'
81
+ require "hanami"
82
+
83
+ module TestApp
84
+ class App < Hanami::App
85
+ end
86
+ end
87
+ RUBY
88
+
89
+ write "slices/main/lib/test_class.rb", <<~'RUBY'
90
+ module Main
91
+ class TestClass
92
+ end
93
+ end
94
+ RUBY
95
+ end
96
+ end
97
+
98
+ specify "Classes in slice lib/ directory are autoloaded with the slice namespace" do
99
+ expect(Main::TestClass).to be
100
+ end
101
+
102
+ specify "Classes in slice lib/ directory are auto-registered" do
103
+ expect(Main::Slice["test_class"]).to be_an_instance_of Main::TestClass
104
+ end
105
+
106
+ specify "Classes in slice lib/ directory are not redundantly auto-registered under 'lib' key namespace" do
107
+ expect(Main::Slice.key?("lib.test_class")).to be false
108
+ end
109
+ end
110
+
111
+ # rubocop:disable Style/GlobalVars
112
+ describe "same-named class defined in both slice and lib/ directories" do
113
+ before :context do
114
+ with_directory(@dir = make_tmp_directory) do
115
+ write "config/app.rb", <<~'RUBY'
116
+ require "hanami"
117
+
118
+ module TestApp
119
+ class App < Hanami::App
120
+ end
121
+ end
122
+ RUBY
123
+
124
+ write "slices/main/test_class.rb", <<~'RUBY'
125
+ $slice_class_loaded = true
126
+
127
+ module Main
128
+ class TestClass
129
+ (@loaded_from ||= []) << "slice"
130
+ end
131
+ end
132
+ RUBY
133
+
134
+ write "slices/main/lib/test_class.rb", <<~'RUBY'
135
+ $slice_lib_class_loaded = true
136
+
137
+ module Main
138
+ class TestClass
139
+ (@loaded_from ||= []) << "slice/lib"
140
+ end
141
+ end
142
+ RUBY
143
+ end
144
+ end
145
+
146
+ after do
147
+ $slice_class_loaded = $slice_lib_class_loaded = nil
148
+ end
149
+
150
+ specify "Classes in slice lib/ directory are preferred for autoloading" do
151
+ expect(Main::TestClass).to be
152
+ expect(Main::TestClass.instance_variable_get(:@loaded_from)).to eq ["slice/lib"]
153
+ expect($slice_lib_class_loaded).to be true
154
+ expect($slice_class_loaded).to be nil
155
+ end
156
+
157
+ specify "Classes in slice lib/ directory are preferred for auto-registration" do
158
+ expect(Main::Slice["test_class"]).to be
159
+ expect(Main::TestClass.instance_variable_get(:@loaded_from)).to eq ["slice/lib"]
160
+ expect($slice_lib_class_loaded).to be true
161
+ expect($slice_class_loaded).to be nil
162
+ end
163
+ end
164
+ # rubocop:enable Style/GlobalVars
165
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "App routes helper", :app_integration do
4
+ specify "Routing to actions based on their container identifiers" do
5
+ with_tmp_directory(Dir.mktmpdir) do
6
+ write "config/app.rb", <<~RUBY
7
+ require "hanami"
8
+
9
+ module TestApp
10
+ class App < Hanami::App
11
+ config.logger.stream = File.new("/dev/null", "w")
12
+ end
13
+ end
14
+ RUBY
15
+
16
+ write "config/routes.rb", <<~RUBY
17
+ module TestApp
18
+ class Routes < Hanami::Routes
19
+ define do
20
+ root to: "home.index"
21
+ end
22
+ end
23
+ end
24
+ RUBY
25
+
26
+ write "app/actions/home/index.rb", <<~RUBY
27
+ require "hanami/action"
28
+
29
+ module TestApp
30
+ module Actions
31
+ module Home
32
+ class Index < Hanami::Action
33
+ def handle(*, res)
34
+ res.body = "Hello world"
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ RUBY
41
+
42
+ require "hanami/prepare"
43
+
44
+ expect(TestApp::App["routes"].path(:root)).to eq "/"
45
+ expect(TestApp::App["routes"].url(:root).to_s).to match /http:\/\/.*\//
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "Container auto-injection (aka \"Deps\") mixin", :app_integration do
4
+ # rubocop:disable Metrics/MethodLength
5
+ def with_app
6
+ with_tmp_directory(Dir.mktmpdir) do
7
+ write "config/app.rb", <<~RUBY
8
+ require "hanami"
9
+
10
+ module TestApp
11
+ class App < Hanami::App
12
+ end
13
+ end
14
+ RUBY
15
+
16
+ write "app/some_service.rb", <<~'RUBY'
17
+ module TestApp
18
+ class SomeService
19
+ end
20
+ end
21
+ RUBY
22
+
23
+ write "app/some_operation.rb", <<~'RUBY'
24
+ module TestApp
25
+ class SomeOperation
26
+ include Deps["some_service"]
27
+ end
28
+ end
29
+ RUBY
30
+
31
+ yield
32
+ end
33
+ end
34
+ # rubocop:enable Metrics/MethodLength
35
+
36
+ specify "Dependencies are auto-injected in a booted app" do
37
+ with_app do
38
+ require "hanami/boot"
39
+
40
+ op = TestApp::App["some_operation"]
41
+ expect(op.some_service).to be_a TestApp::SomeService
42
+ end
43
+ end
44
+
45
+ specify "Dependencies are lazily resolved and auto-injected in an unbooted app" do
46
+ with_app do
47
+ require "hanami/prepare"
48
+
49
+ op = TestApp::App["some_operation"]
50
+ expect(op.some_service).to be_a TestApp::SomeService
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "Container auto-registration", :app_integration do
4
+ specify "Auto-registering files in slice source directories" do
5
+ with_tmp_directory(Dir.mktmpdir) do
6
+ write "config/app.rb", <<~RUBY
7
+ require "hanami"
8
+
9
+ module TestApp
10
+ class App < Hanami::App
11
+ config.inflections do |inflections|
12
+ inflections.acronym "NBA"
13
+ end
14
+ end
15
+ end
16
+ RUBY
17
+
18
+ write "app/action.rb", <<~RUBY
19
+ # auto_register: false
20
+ require "hanami/action"
21
+
22
+ module TestApp
23
+ class Action < Hanami::Action
24
+ end
25
+ end
26
+ RUBY
27
+
28
+ write "app/actions/nba_rosters/index.rb", <<~RUBY
29
+ module TestApp
30
+ module Actions
31
+ module NBARosters
32
+ class Index < TestApp::Action
33
+ end
34
+ end
35
+ end
36
+ end
37
+ RUBY
38
+
39
+ write "slices/admin/lib/nba_jam/get_that_outta_here.rb", <<~RUBY
40
+ module Admin
41
+ module NBAJam
42
+ class GetThatOuttaHere
43
+ end
44
+ end
45
+ end
46
+ RUBY
47
+
48
+ require "hanami/setup"
49
+ Hanami.boot
50
+
51
+ expect(TestApp::App["actions.nba_rosters.index"]).to be_an TestApp::Actions::NBARosters::Index
52
+ expect(Admin::Slice["nba_jam.get_that_outta_here"]).to be_an Admin::NBAJam::GetThatOuttaHere
53
+ end
54
+ end
55
+
56
+ it "Unbooted app resolves components lazily from the lib/ directories" do
57
+ with_tmp_directory(Dir.mktmpdir) do
58
+ write "config/app.rb", <<~RUBY
59
+ require "hanami"
60
+
61
+ module TestApp
62
+ class App < Hanami::App
63
+ config.inflections do |inflections|
64
+ inflections.acronym "NBA"
65
+ end
66
+ end
67
+ end
68
+ RUBY
69
+
70
+ write "slices/admin/lib/nba_jam/get_that_outta_here.rb", <<~RUBY
71
+ module Admin
72
+ module NBAJam
73
+ class GetThatOuttaHere
74
+ end
75
+ end
76
+ end
77
+ RUBY
78
+
79
+ require "hanami/prepare"
80
+
81
+ expect(Admin::Slice.keys).not_to include("nba_jam.get_that_outta_here")
82
+ expect(Admin::Slice["nba_jam.get_that_outta_here"]).to be_an Admin::NBAJam::GetThatOuttaHere
83
+ expect(Admin::Slice.keys).to include("nba_jam.get_that_outta_here")
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,80 @@
1
+ RSpec.describe "App autoloader", :app_integration do
2
+ specify "Classes are autoloaded through direct reference, including through components resolved from the container" do
3
+ with_tmp_directory(Dir.mktmpdir) do
4
+ write "config/app.rb", <<~RUBY
5
+ require "hanami"
6
+
7
+ module TestApp
8
+ class App < Hanami::App
9
+ # Use a custom inflection to ensure this is respected by the autoloader
10
+ config.inflections do |inflections|
11
+ inflections.acronym "NBA"
12
+ end
13
+ end
14
+ end
15
+ RUBY
16
+
17
+ write "lib/non_app/thing.rb", <<~RUBY
18
+ module NonApp
19
+ class Thing
20
+ end
21
+ end
22
+ RUBY
23
+
24
+ write "lib/test_app/nba_jam/get_that_outta_here.rb", <<~RUBY
25
+ module TestApp
26
+ module NBAJam
27
+ class GetThatOuttaHere
28
+ end
29
+ end
30
+ end
31
+ RUBY
32
+
33
+ write "slices/admin/lib/operations/create_game.rb", <<~RUBY
34
+ module Admin
35
+ module Operations
36
+ class CreateGame
37
+ def call
38
+ Entities::Game.new
39
+ end
40
+ end
41
+ end
42
+ end
43
+ RUBY
44
+
45
+ write "slices/admin/lib/entities/game.rb", <<~RUBY
46
+ # auto_register: false
47
+
48
+ module Admin
49
+ module Entities
50
+ class Game
51
+ end
52
+ end
53
+ end
54
+ RUBY
55
+
56
+ write "slices/admin/lib/entities/quarter.rb", <<~RUBY
57
+ # auto_register: false
58
+
59
+ module Admin
60
+ module Entities
61
+ class Quarter
62
+ end
63
+ end
64
+ end
65
+ RUBY
66
+
67
+ require "hanami/prepare"
68
+
69
+ expect(require("non_app/thing")).to be true
70
+ expect(NonApp::Thing).to be
71
+
72
+ expect(TestApp::NBAJam::GetThatOuttaHere).to be
73
+
74
+ expect(Admin::Slice["operations.create_game"]).to be_an_instance_of(Admin::Operations::CreateGame)
75
+ expect(Admin::Slice["operations.create_game"].call).to be_an_instance_of(Admin::Entities::Game)
76
+
77
+ expect(Admin::Entities::Quarter).to be
78
+ end
79
+ end
80
+ end