hanami 2.1.0.beta2.1 → 2.1.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +30 -0
  3. data/hanami.gemspec +3 -3
  4. data/lib/hanami/config/actions.rb +16 -3
  5. data/lib/hanami/config/assets.rb +1 -1
  6. data/lib/hanami/config/views.rb +10 -2
  7. data/lib/hanami/config.rb +21 -12
  8. data/lib/hanami/extensions/action/slice_configured_action.rb +5 -5
  9. data/lib/hanami/extensions/action.rb +4 -4
  10. data/lib/hanami/extensions/view/context.rb +111 -19
  11. data/lib/hanami/extensions/view/part.rb +64 -3
  12. data/lib/hanami/extensions/view/scope.rb +7 -0
  13. data/lib/hanami/extensions/view/slice_configured_context.rb +12 -8
  14. data/lib/hanami/extensions/view/slice_configured_helpers.rb +12 -1
  15. data/lib/hanami/extensions/view/slice_configured_part.rb +71 -0
  16. data/lib/hanami/extensions/view/slice_configured_view.rb +14 -6
  17. data/lib/hanami/extensions/view/standard_helpers.rb +4 -0
  18. data/lib/hanami/extensions/view.rb +5 -3
  19. data/lib/hanami/helpers/assets_helper.rb +47 -79
  20. data/lib/hanami/routes.rb +33 -2
  21. data/lib/hanami/slice.rb +12 -2
  22. data/lib/hanami/slice_registrar.rb +48 -23
  23. data/lib/hanami/version.rb +1 -1
  24. data/lib/hanami/web/rack_logger.rb +70 -2
  25. data/lib/hanami/web/welcome.html.erb +203 -0
  26. data/lib/hanami/web/welcome.rb +46 -0
  27. data/spec/integration/assets/assets_spec.rb +14 -3
  28. data/spec/integration/logging/request_logging_spec.rb +65 -7
  29. data/spec/integration/rack_app/method_override_spec.rb +97 -0
  30. data/spec/integration/slices_spec.rb +275 -5
  31. data/spec/integration/view/context/assets_spec.rb +0 -8
  32. data/spec/integration/view/context/inflector_spec.rb +0 -8
  33. data/spec/integration/view/context/settings_spec.rb +0 -8
  34. data/spec/integration/view/helpers/part_helpers_spec.rb +2 -2
  35. data/spec/integration/view/helpers/user_defined_helpers/part_helpers_spec.rb +10 -10
  36. data/spec/integration/view/parts/default_rendering_spec.rb +138 -0
  37. data/spec/integration/web/welcome_view_spec.rb +84 -0
  38. data/spec/support/app_integration.rb +22 -4
  39. data/spec/unit/hanami/config/render_detailed_errors_spec.rb +1 -1
  40. data/spec/unit/hanami/helpers/assets_helper/{audio_spec.rb → audio_tag_spec.rb} +10 -14
  41. data/spec/unit/hanami/helpers/assets_helper/{favicon_spec.rb → favicon_tag_spec.rb} +7 -11
  42. data/spec/unit/hanami/helpers/assets_helper/{image_spec.rb → image_tag_spec.rb} +8 -12
  43. data/spec/unit/hanami/helpers/assets_helper/{javascript_spec.rb → javascript_tag_spec.rb} +14 -18
  44. data/spec/unit/hanami/helpers/assets_helper/{stylesheet_spec.rb → stylesheet_tag_spec.rb} +12 -16
  45. data/spec/unit/hanami/helpers/assets_helper/{video_spec.rb → video_tag_spec.rb} +11 -11
  46. data/spec/unit/hanami/version_spec.rb +1 -1
  47. metadata +28 -19
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rack/test"
4
+ require "stringio"
5
+
6
+ RSpec.describe "Hanami web app: Method Override", :app_integration do
7
+ include Rack::Test::Methods
8
+
9
+ let(:app) { Hanami.app }
10
+
11
+ around do |example|
12
+ with_tmp_directory(Dir.mktmpdir, &example)
13
+ end
14
+
15
+ context "enabled by default" do
16
+ before do
17
+ write "config/app.rb", <<~RUBY
18
+ require "hanami"
19
+
20
+ module TestApp
21
+ class App < Hanami::App
22
+ config.logger.stream = StringIO.new
23
+ end
24
+ end
25
+ RUBY
26
+
27
+ generate_app_code
28
+ end
29
+
30
+ it "overrides the original HTTP method" do
31
+ post(
32
+ "/users/:id",
33
+ {"_method" => "PUT"},
34
+ "CONTENT_TYPE" => "multipart/form-data"
35
+ )
36
+
37
+ expect(last_response).to be_successful
38
+ expect(last_response.body).to eq("PUT")
39
+ end
40
+ end
41
+
42
+ context "when disabled" do
43
+ before do
44
+ write "config/app.rb", <<~RUBY
45
+ require "hanami"
46
+
47
+ module TestApp
48
+ class App < Hanami::App
49
+ config.logger.stream = StringIO.new
50
+ config.actions.method_override = false
51
+ end
52
+ end
53
+ RUBY
54
+
55
+ generate_app_code
56
+ end
57
+
58
+ it "overrides the original HTTP method" do
59
+ post(
60
+ "/users/:id",
61
+ {"_method" => "PUT"},
62
+ "CONTENT_TYPE" => "multipart/form-data"
63
+ )
64
+
65
+ expect(last_response).to_not be_successful
66
+ expect(last_response.status).to be(404)
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ def generate_app_code
73
+ write "config/routes.rb", <<~RUBY
74
+ module TestApp
75
+ class Routes < Hanami::Routes
76
+ put "/users/:id", to: "users.update"
77
+ end
78
+ end
79
+ RUBY
80
+
81
+ write "app/actions/users/update.rb", <<~RUBY
82
+ module TestApp
83
+ module Actions
84
+ module Users
85
+ class Update < Hanami::Action
86
+ def handle(req, res)
87
+ res.body = req.env.fetch("REQUEST_METHOD")
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ RUBY
94
+
95
+ require "hanami/boot"
96
+ end
97
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  RSpec.describe "Slices", :app_integration do
4
- it "Loading a slice uses a defined slice class" do
4
+ specify "Loading a slice from a slice class in the app's config dir" do
5
5
  with_tmp_directory(Dir.mktmpdir) do
6
6
  write "config/app.rb", <<~RUBY
7
7
  require "hanami"
@@ -31,7 +31,7 @@ RSpec.describe "Slices", :app_integration do
31
31
  end
32
32
  end
33
33
 
34
- it "Loading a slice with a defined slice class but no slice dir" do
34
+ specify "Loading a slice from a slice class in the app's config dir, even when no slice dir exists" do
35
35
  with_tmp_directory(Dir.mktmpdir) do
36
36
  write "config/app.rb", <<~RUBY
37
37
  require "hanami"
@@ -55,7 +55,7 @@ RSpec.describe "Slices", :app_integration do
55
55
  end
56
56
  end
57
57
 
58
- specify "Loading a nested slice with a defined slice class" do
58
+ specify "Loading a nested slice from a slice class in its parent's config dir" do
59
59
  with_tmp_directory(Dir.mktmpdir) do
60
60
  write "config/app.rb", <<~RUBY
61
61
  require "hanami"
@@ -81,7 +81,277 @@ RSpec.describe "Slices", :app_integration do
81
81
  end
82
82
  end
83
83
 
84
- it "Loading a slice generates a slice class if none is defined" do
84
+ specify "Loading a slice from a slice class in its own config dir" do
85
+ with_tmp_directory(Dir.mktmpdir) do
86
+ write "config/app.rb", <<~RUBY
87
+ require "hanami"
88
+
89
+ module TestApp
90
+ class App < Hanami::App
91
+ end
92
+ end
93
+ RUBY
94
+
95
+ write "slices/main/config/slice.rb", <<~RUBY
96
+ module Main
97
+ class Slice < Hanami::Slice
98
+ def self.loaded_from = "own config dir"
99
+ end
100
+ end
101
+ RUBY
102
+
103
+ require "hanami/prepare"
104
+
105
+ expect(Hanami.app.slices[:main]).to be Main::Slice
106
+ expect(Hanami.app.slices[:main].loaded_from).to eq "own config dir"
107
+ end
108
+ end
109
+
110
+ specify "Loading a slice from a slice class in the app's config dir, in preference to a slice class in its own config dir" do
111
+ with_tmp_directory(Dir.mktmpdir) do
112
+ write "config/app.rb", <<~RUBY
113
+ require "hanami"
114
+
115
+ module TestApp
116
+ class App < Hanami::App
117
+ end
118
+ end
119
+ RUBY
120
+
121
+ write "config/slices/main.rb", <<~RUBY
122
+ require "hanami"
123
+
124
+ module Main
125
+ class Slice < Hanami::Slice
126
+ def self.loaded_from = "app config dir"
127
+ end
128
+ end
129
+ RUBY
130
+
131
+ write "slices/main/config/slice.rb", <<~RUBY
132
+ raise "This should not be loaded"
133
+ RUBY
134
+
135
+ require "hanami/prepare"
136
+
137
+ expect(Hanami.app.slices[:main]).to be Main::Slice
138
+ expect(Hanami.app.slices[:main].loaded_from).to eq "app config dir"
139
+ end
140
+ end
141
+
142
+ specify "Loading a nested slice from a slice class in its own config dir" do
143
+ with_tmp_directory(Dir.mktmpdir) do
144
+ write "config/app.rb", <<~RUBY
145
+ require "hanami"
146
+
147
+ module TestApp
148
+ class App < Hanami::App
149
+ end
150
+ end
151
+ RUBY
152
+
153
+ write "slices/main/slices/nested/config/slice.rb", <<~RUBY
154
+ module Main
155
+ module Nested
156
+ class Slice < Hanami::Slice
157
+ def self.loaded_from = "own config dir"
158
+ end
159
+ end
160
+ end
161
+ RUBY
162
+
163
+ require "hanami/prepare"
164
+
165
+ expect(Hanami.app.slices[:main]).to be Main::Slice
166
+ expect(Hanami.app.slices[:main].slices[:nested].loaded_from).to eq "own config dir"
167
+ end
168
+ end
169
+
170
+ specify "Loading a deeply nested slice from a slice class in its own config dir" do
171
+ with_tmp_directory(Dir.mktmpdir) do
172
+ write "config/app.rb", <<~RUBY
173
+ require "hanami"
174
+
175
+ module TestApp
176
+ class App < Hanami::App
177
+ end
178
+ end
179
+ RUBY
180
+
181
+ # It does NOT look up "grandparent" (or above) configs; only the parent and the app
182
+ write "slices/main/config/slices/deeply/nested.rb", <<~RUBY
183
+ raise "This should not be loaded"
184
+ RUBY
185
+
186
+ write "slices/main/slices/deeply/slices/nested/config/slice.rb", <<~RUBY
187
+ module Main
188
+ module Deeply
189
+ module Nested
190
+ class Slice < Hanami::Slice
191
+ def self.loaded_from = "own config dir"
192
+ end
193
+ end
194
+ end
195
+ end
196
+ RUBY
197
+
198
+ require "hanami/prepare"
199
+
200
+ expect(Hanami.app.slices[:main].slices[:deeply].slices[:nested]).to be Main::Deeply::Nested::Slice
201
+ expect(Hanami.app.slices[:main].slices[:deeply].slices[:nested].loaded_from).to eq "own config dir"
202
+ end
203
+ end
204
+
205
+ specify "Loading a nested slice from a slice class in its parent's config dir, in preference to a slice class in its own config dir" do
206
+ with_tmp_directory(Dir.mktmpdir) do
207
+ write "config/app.rb", <<~RUBY
208
+ require "hanami"
209
+
210
+ module TestApp
211
+ class App < Hanami::App
212
+ end
213
+ end
214
+ RUBY
215
+
216
+ write "slices/main/config/slices/nested.rb", <<~RUBY
217
+ require "hanami"
218
+
219
+ module Main
220
+ module Nested
221
+ class Slice < Hanami::Slice
222
+ def self.loaded_from = "parent config dir"
223
+ end
224
+ end
225
+ end
226
+ RUBY
227
+
228
+ write "slices/main/slices/nested/config/slice.rb", <<~RUBY
229
+ raise "This should not be loaded"
230
+ RUBY
231
+
232
+ require "hanami/prepare"
233
+
234
+ expect(Hanami.app.slices[:main]).to be Main::Slice
235
+ expect(Hanami.app.slices[:main].slices[:nested].loaded_from).to eq "parent config dir"
236
+ end
237
+ end
238
+
239
+ specify "Loading a deeply nested slice from a slice class in its parent's config dir, in preference to a slice class in its own config dir" do
240
+ with_tmp_directory(Dir.mktmpdir) do
241
+ write "config/app.rb", <<~RUBY
242
+ require "hanami"
243
+
244
+ module TestApp
245
+ class App < Hanami::App
246
+ end
247
+ end
248
+ RUBY
249
+
250
+ # It does NOT look up "grandparent" (or above) configs; only the parent and the app
251
+ write "slices/main/config/slices/deeply/nested.rb", <<~RUBY
252
+ raise "This should not be loaded"
253
+ RUBY
254
+
255
+ write "slices/main/slices/deeply/config/slices/nested.rb", <<~RUBY
256
+ module Main
257
+ module Deeply
258
+ module Nested
259
+ class Slice < Hanami::Slice
260
+ def self.loaded_from = "parent config dir"
261
+ end
262
+ end
263
+ end
264
+ end
265
+ RUBY
266
+
267
+ write "slices/main/slices/deeply/slices/nested/config/slice.rb", <<~RUBY
268
+ raise "This should not be loaded"
269
+ RUBY
270
+
271
+ require "hanami/prepare"
272
+
273
+ expect(Hanami.app.slices[:main].slices[:deeply].slices[:nested]).to be Main::Deeply::Nested::Slice
274
+ expect(Hanami.app.slices[:main].slices[:deeply].slices[:nested].loaded_from).to eq "parent config dir"
275
+ end
276
+ end
277
+
278
+ specify "Loading a nested slice from a slice class in the app's config dir, in preference to a slice class in the slice's parent config dir or the slice's own config dir" do
279
+ with_tmp_directory(Dir.mktmpdir) do
280
+ write "config/app.rb", <<~RUBY
281
+ require "hanami"
282
+
283
+ module TestApp
284
+ class App < Hanami::App
285
+ end
286
+ end
287
+ RUBY
288
+
289
+ write "config/slices/main/nested.rb", <<~RUBY
290
+ require "hanami"
291
+
292
+ module Main
293
+ module Nested
294
+ class Slice < Hanami::Slice
295
+ def self.loaded_from = "app config dir"
296
+ end
297
+ end
298
+ end
299
+ RUBY
300
+
301
+ write "slices/main/config/slices/nested.rb", <<~RUBY
302
+ raise "This should not be loaded"
303
+ RUBY
304
+
305
+ write "slices/main/slices/nested/config/slice.rb", <<~RUBY
306
+ raise "This should not be loaded"
307
+ RUBY
308
+
309
+ require "hanami/prepare"
310
+
311
+ expect(Hanami.app.slices[:main]).to be Main::Slice
312
+ expect(Hanami.app.slices[:main].slices[:nested].loaded_from).to eq "app config dir"
313
+ end
314
+ end
315
+
316
+ specify "Loading a deeply nested slice from a slice class in the app's config dir, in preference to a slice class in the slice's parent config dir or the slice's own config dir" do
317
+ with_tmp_directory(Dir.mktmpdir) do
318
+ write "config/app.rb", <<~RUBY
319
+ require "hanami"
320
+
321
+ module TestApp
322
+ class App < Hanami::App
323
+ end
324
+ end
325
+ RUBY
326
+
327
+ write "config/slices/main/deeply/nested.rb", <<~RUBY
328
+ module Main
329
+ module Deeply
330
+ module Nested
331
+ class Slice < Hanami::Slice
332
+ def self.loaded_from = "app config dir"
333
+ end
334
+ end
335
+ end
336
+ end
337
+ RUBY
338
+
339
+ write "slices/main/config/slices/deeply/nested.rb", <<~RUBY
340
+ raise "This should not be loaded"
341
+ RUBY
342
+
343
+ write "slices/main/slices/deeply/slices/nested/config/slice.rb", <<~RUBY
344
+ raise "This should not be loaded"
345
+ RUBY
346
+
347
+ require "hanami/prepare"
348
+
349
+ expect(Hanami.app.slices[:main].slices[:deeply].slices[:nested]).to be Main::Deeply::Nested::Slice
350
+ expect(Hanami.app.slices[:main].slices[:deeply].slices[:nested].loaded_from).to eq "app config dir"
351
+ end
352
+ end
353
+
354
+ specify "Loading a slice generates a slice class if none is defined" do
85
355
  with_tmp_directory(Dir.mktmpdir) do
86
356
  write "config/app.rb", <<~RUBY
87
357
  require "hanami"
@@ -178,7 +448,7 @@ RSpec.describe "Slices", :app_integration do
178
448
  end
179
449
  end
180
450
 
181
- it "Registering a slice with a block creates a slice class and evals the block" do
451
+ specify "Registering a slice with a block creates a slice class and evals the block" do
182
452
  with_tmp_directory(Dir.mktmpdir) do
183
453
  write "config/app.rb", <<~RUBY
184
454
  require "hanami"
@@ -47,14 +47,6 @@ RSpec.describe "App view / Context / Assets", :app_integration do
47
47
  it "is the injected assets" do
48
48
  expect(context.assets).to be assets
49
49
  end
50
-
51
- context "rebuilt context" do
52
- subject(:new_context) { context.with }
53
-
54
- it "retains the injected assets" do
55
- expect(new_context.assets).to be assets
56
- end
57
- end
58
50
  end
59
51
  end
60
52
  end
@@ -35,14 +35,6 @@ RSpec.describe "App view / Context / Inflector", :app_integration do
35
35
  it "is the injected inflector" do
36
36
  expect(context.inflector).to be inflector
37
37
  end
38
-
39
- context "rebuilt context" do
40
- subject(:new_context) { context.with }
41
-
42
- it "retains the injected inflector" do
43
- expect(new_context.inflector).to be inflector
44
- end
45
- end
46
38
  end
47
39
  end
48
40
  end
@@ -41,14 +41,6 @@ RSpec.describe "App view / Context / Settings", :app_integration do
41
41
  it "is the injected settings" do
42
42
  expect(context.settings).to be settings
43
43
  end
44
-
45
- context "rebuilt context" do
46
- subject(:new_context) { context.with }
47
-
48
- it "retains the injected settings" do
49
- expect(new_context.settings).to be settings
50
- end
51
- end
52
44
  end
53
45
  end
54
46
  end
@@ -51,7 +51,7 @@ RSpec.describe "App view / Helpers / Part helpers", :app_integration do
51
51
  module Parts
52
52
  class Post < TestApp::Views::Part
53
53
  def number
54
- format_number(value.number)
54
+ helpers.format_number(value.number)
55
55
  end
56
56
  end
57
57
  end
@@ -99,7 +99,7 @@ RSpec.describe "App view / Helpers / Part helpers", :app_integration do
99
99
  module Parts
100
100
  class Post < Main::Views::Part
101
101
  def number
102
- format_number(value.number)
102
+ helpers.format_number(value.number)
103
103
  end
104
104
  end
105
105
  end
@@ -33,7 +33,7 @@ RSpec.describe "App view / Helpers / User-defined helpers / Scope helpers", :app
33
33
  module Views
34
34
  module Helpers
35
35
  def exclaim_from_app(str)
36
- tag.h1("#{str}! (app helper)")
36
+ tag.h1("#{str}! (app #{_context.inflector.pluralize('helper')})")
37
37
  end
38
38
  end
39
39
  end
@@ -65,7 +65,7 @@ RSpec.describe "App view / Helpers / User-defined helpers / Scope helpers", :app
65
65
  module Parts
66
66
  class Post < TestApp::Views::Part
67
67
  def title
68
- exclaim_from_app(value.title)
68
+ helpers.exclaim_from_app(value.title)
69
69
  end
70
70
  end
71
71
  end
@@ -78,11 +78,11 @@ RSpec.describe "App view / Helpers / User-defined helpers / Scope helpers", :app
78
78
  ERB
79
79
  end
80
80
 
81
- it "makes user-defined helpers available in parts" do
81
+ it "makes user-defined helpers available in parts via a `helpers` object" do
82
82
  post = OpenStruct.new(title: "Hello world")
83
83
  output = TestApp::App["views.posts.show"].call(post: post).to_s.strip
84
84
 
85
- expect(output).to eq "<h1>Hello world! (app helper)</h1>"
85
+ expect(output).to eq "<h1>Hello world! (app helpers)</h1>"
86
86
  end
87
87
  end
88
88
 
@@ -104,7 +104,7 @@ RSpec.describe "App view / Helpers / User-defined helpers / Scope helpers", :app
104
104
  module Views
105
105
  module Helpers
106
106
  def exclaim_from_slice(str)
107
- tag.h1("#{str}! (slice helper)")
107
+ tag.h1("#{str}! (slice #{_context.inflector.pluralize('helper')})")
108
108
  end
109
109
  end
110
110
  end
@@ -129,11 +129,11 @@ RSpec.describe "App view / Helpers / User-defined helpers / Scope helpers", :app
129
129
  module Parts
130
130
  class Post < Main::Views::Part
131
131
  def title
132
- exclaim_from_slice(value.title)
132
+ helpers.exclaim_from_slice(value.title)
133
133
  end
134
134
 
135
135
  def title_from_app
136
- exclaim_from_app(value.title)
136
+ helpers.exclaim_from_app(value.title)
137
137
  end
138
138
  end
139
139
  end
@@ -147,13 +147,13 @@ RSpec.describe "App view / Helpers / User-defined helpers / Scope helpers", :app
147
147
  ERB
148
148
  end
149
149
 
150
- it "makes user-defined helpers (from app as well as slice) available in parts" do
150
+ it "makes user-defined helpers (from app as well as slice) available in parts via a `helpers` object" do
151
151
  post = OpenStruct.new(title: "Hello world")
152
152
  output = Main::Slice["views.posts.show"].call(post: post).to_s
153
153
 
154
154
  expect(output).to eq <<~HTML
155
- <h1>Hello world! (slice helper)</h1>
156
- <h1>Hello world! (app helper)</h1>
155
+ <h1>Hello world! (slice helpers)</h1>
156
+ <h1>Hello world! (app helpers)</h1>
157
157
  HTML
158
158
  end
159
159
  end
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "App view / Parts / Default rendering", :app_integration do
4
+ before do
5
+ with_directory(make_tmp_directory) do
6
+ write "config/app.rb", <<~RUBY
7
+ module TestApp
8
+ class App < Hanami::App
9
+ end
10
+ end
11
+ RUBY
12
+
13
+ write "app/view.rb", <<~RUBY
14
+ # auto_register: false
15
+
16
+ require "hanami/view"
17
+
18
+ module TestApp
19
+ class View < Hanami::View
20
+ config.layout = nil
21
+ end
22
+ end
23
+ RUBY
24
+
25
+ write "app/views/part.rb", <<~RUBY
26
+ # auto_register: false
27
+
28
+ module TestApp
29
+ module Views
30
+ class Part < Hanami::View::Part
31
+ end
32
+ end
33
+ end
34
+ RUBY
35
+
36
+ before_prepare if respond_to?(:before_prepare)
37
+ require "hanami/prepare"
38
+ end
39
+ end
40
+
41
+ describe "app part" do
42
+ def before_prepare
43
+ write "app/views/helpers.rb", <<~RUBY
44
+ # auto_register: false
45
+
46
+ module TestApp
47
+ module Views
48
+ module Helpers
49
+ def app_screaming_snake_case(str)
50
+ _context.inflector
51
+ .underscore(str)
52
+ .gsub(/\s+/, "_")
53
+ .upcase + "!"
54
+ end
55
+ end
56
+ end
57
+ end
58
+ RUBY
59
+ write "app/views/parts/post.rb", <<~RUBY
60
+ # auto_register: false
61
+
62
+ module TestApp
63
+ module Views
64
+ module Parts
65
+ class Post < TestApp::Views::Part
66
+ def title_tag
67
+ helpers.tag.h1(helpers.app_screaming_snake_case(value.title))
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ RUBY
74
+ end
75
+
76
+ it "provides a default rendering from the app" do
77
+ post = Struct.new(:title).new("Hello world")
78
+ part = TestApp::Views::Parts::Post.new(value: post)
79
+
80
+ expect(part.title_tag).to eq "<h1>HELLO_WORLD!</h1>"
81
+ end
82
+ end
83
+
84
+ describe "slice part" do
85
+ def before_prepare
86
+ write "slices/main/views/helpers.rb", <<~RUBY
87
+ # auto_register: false
88
+
89
+ module Main
90
+ module Views
91
+ module Helpers
92
+ def slice_screaming_snake_case(str)
93
+ _context.inflector
94
+ .underscore(str)
95
+ .gsub(/\s+/, "_")
96
+ .upcase + "!"
97
+ end
98
+ end
99
+ end
100
+ end
101
+ RUBY
102
+
103
+ write "slices/main/views/part.rb", <<~RUBY
104
+ # auto_register: false
105
+
106
+ module Main
107
+ module Views
108
+ class Part < TestApp::View::Part
109
+ end
110
+ end
111
+ end
112
+ RUBY
113
+
114
+ write "slices/main/views/parts/post.rb", <<~RUBY
115
+ # auto_register: false
116
+
117
+ module Main
118
+ module Views
119
+ module Parts
120
+ class Post < Main::Views::Part
121
+ def title_tag
122
+ helpers.tag.h1(helpers.slice_screaming_snake_case(value.title))
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+ RUBY
129
+ end
130
+
131
+ it "provides a default rendering from the app" do
132
+ post = Struct.new(:title).new("Hello world")
133
+ part = Main::Views::Parts::Post.new(value: post)
134
+
135
+ expect(part.title_tag).to eq "<h1>HELLO_WORLD!</h1>"
136
+ end
137
+ end
138
+ end