hanami 2.1.0.beta2.1 → 2.1.0.rc2

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 (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
@@ -3,19 +3,30 @@
3
3
  module Hanami
4
4
  module Extensions
5
5
  module View
6
- # @api private
6
+ # Provides slice-specific helper methods any view object requiring access to helpers.
7
+ #
8
+ # @api public
9
+ # @since 2.1.0
7
10
  class SliceConfiguredHelpers < Module
8
11
  attr_reader :slice
9
12
 
13
+ # @api private
14
+ # @since 2.1.0
10
15
  def initialize(slice)
11
16
  super()
12
17
  @slice = slice
13
18
  end
14
19
 
20
+ # @api private
21
+ # @since 2.1.0
15
22
  def extended(klass)
16
23
  include_helpers(klass)
17
24
  end
18
25
 
26
+ # @return [String]
27
+ #
28
+ # @api public
29
+ # @since 2.1.0
19
30
  def inspect
20
31
  "#<#{self.class.name}[#{slice.name}]>"
21
32
  end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ module Extensions
5
+ module View
6
+ # Provides slice-specific configuration and behavior for any view part class defined within a
7
+ # slice's module namespace.
8
+ #
9
+ # @api public
10
+ # @since 2.1.0
11
+ class SliceConfiguredPart < Module
12
+ attr_reader :slice
13
+
14
+ # @api private
15
+ # @since 2.1.0
16
+ def initialize(slice)
17
+ super()
18
+ @slice = slice
19
+ end
20
+
21
+ # @api private
22
+ # @since 2.1.0
23
+ def extended(klass)
24
+ define_new
25
+ end
26
+
27
+ # @return [String]
28
+ #
29
+ # @api public
30
+ # @since 2.1.0
31
+ def inspect
32
+ "#<#{self.class.name}[#{slice.name}]>"
33
+ end
34
+
35
+ private
36
+
37
+ # Defines a `.new` method on the part class that provides a default `rendering:` argument of
38
+ # a rendering coming from a view configured for the slice. This means that any part can be
39
+ # initialized standalone (with a `value:` only) and still have access to all the integrated
40
+ # view facilities from the slice, such as helpers. This is helpful when unit testing parts.
41
+ #
42
+ # @example
43
+ # module MyApp::Views::Parts
44
+ # class Post < MyApp::View::Part
45
+ # def title_tag
46
+ # helpers.h1(value.title)
47
+ # end
48
+ # end
49
+ # end
50
+ #
51
+ # # Useful when unit testing parts
52
+ # part = MyApp::Views::Parts::Post.new(value: hello_world_post)
53
+ # part.title_tag # => "<h1>Hello world</h1>"
54
+ def define_new
55
+ slice = self.slice
56
+
57
+ define_method(:new) do |**args|
58
+ return super(**args) if args.key?(:rendering)
59
+
60
+ slice_rendering = Class.new(Hanami::View)
61
+ .configure_for_slice(slice)
62
+ .new
63
+ .rendering
64
+
65
+ super(rendering: slice_rendering, **args)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -3,11 +3,11 @@
3
3
  module Hanami
4
4
  module Extensions
5
5
  module View
6
- # Provides slice-specific configuration and behavior for any view class defined
7
- # within a slice's module namespace.
6
+ # Provides slice-specific configuration and behavior for any view class defined within a
7
+ # slice's module namespace.
8
8
  #
9
- # @api private
10
- # @since 2.0.0
9
+ # @api public
10
+ # @since 2.1.0
11
11
  class SliceConfiguredView < Module
12
12
  TEMPLATES_DIR = "templates"
13
13
  VIEWS_DIR = "views"
@@ -16,17 +16,25 @@ module Hanami
16
16
 
17
17
  attr_reader :slice
18
18
 
19
+ # @api private
20
+ # @since 2.1.0
19
21
  def initialize(slice)
20
22
  super()
21
23
  @slice = slice
22
24
  end
23
25
 
26
+ # @api private
27
+ # @since 2.1.0
24
28
  def extended(view_class)
25
29
  load_app_view
26
30
  configure_view(view_class)
27
31
  define_inherited
28
32
  end
29
33
 
34
+ # @return [String]
35
+ #
36
+ # @api public
37
+ # @since 2.1.0
30
38
  def inspect
31
39
  "#<#{self.class.name}[#{slice.name}]>"
32
40
  end
@@ -108,7 +116,7 @@ module Hanami
108
116
  # - We are a slice, and the view's inherited `paths` is identical to the parent's config
109
117
  # (which would result in the view in a slice erroneously trying to find templates in
110
118
  # the app)
111
- if (!slice.parent && view_class.config.paths.empty?) ||
119
+ if view_class.config.paths.empty? ||
112
120
  (slice.parent && view_class.config.paths.map(&:dir) == [templates_path(slice.parent)])
113
121
  view_class.config.paths = templates_path(slice)
114
122
  end
@@ -178,7 +186,7 @@ module Hanami
178
186
  else
179
187
  views_namespace.const_set(:Part, Class.new(part_superclass).tap { |klass|
180
188
  # Give the slice to `configure_for_slice`, since it cannot be inferred when it is
181
- # called via `.inherited`, since the class is anonymous at this point
189
+ # called via `.inherited`, because the class is anonymous at this point
182
190
  klass.configure_for_slice(slice)
183
191
  })
184
192
  end
@@ -3,6 +3,10 @@
3
3
  module Hanami
4
4
  module Extensions
5
5
  module View
6
+ # Module including the standard library of Hanami helpers
7
+ #
8
+ # @api public
9
+ # @since 2.1.0
6
10
  module StandardHelpers
7
11
  include Hanami::View::Helpers::EscapeHelper
8
12
  include Hanami::View::Helpers::NumberFormattingHelper
@@ -7,13 +7,13 @@ module Hanami
7
7
  module Extensions
8
8
  # Integrated behavior for `Hanami::View` classes within Hanami apps.
9
9
  #
10
- # This is NOT RELEASED as of 2.0.0.
11
- #
12
10
  # @see Hanami::View
13
11
  #
14
- # @api private
12
+ # @api public
13
+ # @since 2.1.0
15
14
  module View
16
15
  # @api private
16
+ # @since 2.1.0
17
17
  def self.included(view_class)
18
18
  super
19
19
 
@@ -22,8 +22,10 @@ module Hanami
22
22
  end
23
23
 
24
24
  # @api private
25
+ # @since 2.1.0
25
26
  module ClassMethods
26
27
  # @api private
28
+ # @since 2.1.0
27
29
  def configure_for_slice(slice)
28
30
  extend SliceConfiguredView.new(slice)
29
31
  end
@@ -99,62 +99,62 @@ module Hanami
99
99
  #
100
100
  # @example Single Asset
101
101
  #
102
- # <%= js "application" %>
102
+ # <%= javascript_tag "application" %>
103
103
  #
104
104
  # # <script src="/assets/application.js" type="text/javascript"></script>
105
105
  #
106
106
  # @example Multiple Assets
107
107
  #
108
- # <%= js "application", "dashboard" %>
108
+ # <%= javascript_tag "application", "dashboard" %>
109
109
  #
110
110
  # # <script src="/assets/application.js" type="text/javascript"></script>
111
111
  # # <script src="/assets/dashboard.js" type="text/javascript"></script>
112
112
  #
113
113
  # @example Asynchronous Execution
114
114
  #
115
- # <%= js "application", async: true %>
115
+ # <%= javascript_tag "application", async: true %>
116
116
  #
117
117
  # # <script src="/assets/application.js" type="text/javascript" async="async"></script>
118
118
  #
119
119
  # @example Subresource Integrity
120
120
  #
121
- # <%= js "application" %>
121
+ # <%= javascript_tag "application" %>
122
122
  #
123
123
  # # <script src="/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.js"
124
124
  # # type="text/javascript" integrity="sha384-oqVu...Y8wC" crossorigin="anonymous"></script>
125
125
  #
126
126
  # @example Subresource Integrity for 3rd Party Scripts
127
127
  #
128
- # <%= js "https://example.com/assets/example.js", integrity: "sha384-oqVu...Y8wC" %>
128
+ # <%= javascript_tag "https://example.com/assets/example.js", integrity: "sha384-oqVu...Y8wC" %>
129
129
  #
130
130
  # # <script src="https://example.com/assets/example.js" type="text/javascript"
131
131
  # # integrity="sha384-oqVu...Y8wC" crossorigin="anonymous"></script>
132
132
  #
133
133
  # @example Deferred Execution
134
134
  #
135
- # <%= js "application", defer: true %>
135
+ # <%= javascript_tag "application", defer: true %>
136
136
  #
137
137
  # # <script src="/assets/application.js" type="text/javascript" defer="defer"></script>
138
138
  #
139
139
  # @example Absolute URL
140
140
  #
141
- # <%= js "https://code.jquery.com/jquery-2.1.4.min.js" %>
141
+ # <%= javascript_tag "https://code.jquery.com/jquery-2.1.4.min.js" %>
142
142
  #
143
143
  # # <script src="https://code.jquery.com/jquery-2.1.4.min.js" type="text/javascript"></script>
144
144
  #
145
145
  # @example Fingerprint Mode
146
146
  #
147
- # <%= js "application" %>
147
+ # <%= javascript_tag "application" %>
148
148
  #
149
149
  # # <script src="/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.js" type="text/javascript"></script>
150
150
  #
151
151
  # @example CDN Mode
152
152
  #
153
- # <%= js "application" %>
153
+ # <%= javascript_tag "application" %>
154
154
  #
155
155
  # # <script src="https://assets.bookshelf.org/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.js"
156
156
  # # type="text/javascript"></script>
157
- def javascript(*source_paths, **options)
157
+ def javascript_tag(*source_paths, **options)
158
158
  options = options.reject { |k, _| k.to_sym == :src }
159
159
 
160
160
  _safe_tags(*source_paths) do |source|
@@ -173,14 +173,6 @@ module Hanami
173
173
  end
174
174
  end
175
175
 
176
- # @api public
177
- # @since 2.1.0
178
- alias_method :js, :javascript
179
-
180
- # @api public
181
- # @since 2.1.0
182
- alias_method :javascript_tag, :javascript
183
-
184
176
  # Generate `link` tag for given source(s)
185
177
  #
186
178
  # It accepts one or more strings representing the name of the asset, if it
@@ -211,51 +203,51 @@ module Hanami
211
203
  #
212
204
  # @example Single Asset
213
205
  #
214
- # <%= css "application" %>
206
+ # <%= stylesheet_tag "application" %>
215
207
  #
216
208
  # # <link href="/assets/application.css" type="text/css" rel="stylesheet">
217
209
  #
218
210
  # @example Multiple Assets
219
211
  #
220
- # <%= css "application", "dashboard" %>
212
+ # <%= stylesheet_tag "application", "dashboard" %>
221
213
  #
222
214
  # # <link href="/assets/application.css" type="text/css" rel="stylesheet">
223
215
  # # <link href="/assets/dashboard.css" type="text/css" rel="stylesheet">
224
216
  #
225
217
  # @example Subresource Integrity
226
218
  #
227
- # <%= css "application" %>
219
+ # <%= stylesheet_tag "application" %>
228
220
  #
229
221
  # # <link href="/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.css"
230
222
  # # type="text/css" integrity="sha384-oqVu...Y8wC" crossorigin="anonymous"></script>
231
223
  #
232
224
  # @example Subresource Integrity for 3rd Party Assets
233
225
  #
234
- # <%= css "https://example.com/assets/example.css", integrity: "sha384-oqVu...Y8wC" %>
226
+ # <%= stylesheet_tag "https://example.com/assets/example.css", integrity: "sha384-oqVu...Y8wC" %>
235
227
  #
236
228
  # # <link href="https://example.com/assets/example.css"
237
229
  # # type="text/css" rel="stylesheet" integrity="sha384-oqVu...Y8wC" crossorigin="anonymous"></script>
238
230
  #
239
231
  # @example Absolute URL
240
232
  #
241
- # <%= css "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" %>
233
+ # <%= stylesheet_tag "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" %>
242
234
  #
243
235
  # # <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"
244
236
  # # type="text/css" rel="stylesheet">
245
237
  #
246
238
  # @example Fingerprint Mode
247
239
  #
248
- # <%= css "application" %>
240
+ # <%= stylesheet_tag "application" %>
249
241
  #
250
242
  # # <link href="/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.css" type="text/css" rel="stylesheet">
251
243
  #
252
244
  # @example CDN Mode
253
245
  #
254
- # <%= css "application" %>
246
+ # <%= stylesheet_tag "application" %>
255
247
  #
256
248
  # # <link href="https://assets.bookshelf.org/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.css"
257
249
  # # type="text/css" rel="stylesheet">
258
- def stylesheet(*source_paths, **options)
250
+ def stylesheet_tag(*source_paths, **options)
259
251
  options = options.reject { |k, _| k.to_sym == :href }
260
252
 
261
253
  _safe_tags(*source_paths) do |source_path|
@@ -275,14 +267,6 @@ module Hanami
275
267
  end
276
268
  end
277
269
 
278
- # @api public
279
- # @since 2.1.0
280
- alias_method :css, :stylesheet
281
-
282
- # @api public
283
- # @since 2.1.0
284
- alias_method :stylesheet_link_tag, :stylesheet
285
-
286
270
  # Generate `img` tag for given source
287
271
  #
288
272
  # It accepts one string representing the name of the asset, if it comes
@@ -313,40 +297,40 @@ module Hanami
313
297
  #
314
298
  # @example Basic Usage
315
299
  #
316
- # <%= image "logo.png" %>
300
+ # <%= image_tag "logo.png" %>
317
301
  #
318
302
  # # <img src="/assets/logo.png" alt="Logo">
319
303
  #
320
304
  # @example Custom alt Attribute
321
305
  #
322
- # <%= image "logo.png", alt: "Application Logo" %>
306
+ # <%= image_tag "logo.png", alt: "Application Logo" %>
323
307
  #
324
308
  # # <img src="/assets/logo.png" alt="Application Logo">
325
309
  #
326
310
  # @example Custom HTML Attributes
327
311
  #
328
- # <%= image "logo.png", id: "logo", class: "image" %>
312
+ # <%= image_tag "logo.png", id: "logo", class: "image" %>
329
313
  #
330
314
  # # <img src="/assets/logo.png" alt="Logo" id="logo" class="image">
331
315
  #
332
316
  # @example Absolute URL
333
317
  #
334
- # <%= image "https://example-cdn.com/images/logo.png" %>
318
+ # <%= image_tag "https://example-cdn.com/images/logo.png" %>
335
319
  #
336
320
  # # <img src="https://example-cdn.com/images/logo.png" alt="Logo">
337
321
  #
338
322
  # @example Fingerprint Mode
339
323
  #
340
- # <%= image "logo.png" %>
324
+ # <%= image_tag "logo.png" %>
341
325
  #
342
326
  # # <img src="/assets/logo-28a6b886de2372ee3922fcaf3f78f2d8.png" alt="Logo">
343
327
  #
344
328
  # @example CDN Mode
345
329
  #
346
- # <%= image "logo.png" %>
330
+ # <%= image_tag "logo.png" %>
347
331
  #
348
332
  # # <img src="https://assets.bookshelf.org/assets/logo-28a6b886de2372ee3922fcaf3f78f2d8.png" alt="Logo">
349
- def image(source, options = {})
333
+ def image_tag(source, options = {})
350
334
  options = options.reject { |k, _| k.to_sym == :src }
351
335
  attributes = {
352
336
  src: asset_url(source),
@@ -357,10 +341,6 @@ module Hanami
357
341
  tag.img(**attributes)
358
342
  end
359
343
 
360
- # @api public
361
- # @since 2.1.0
362
- alias_method :image_tag, :image
363
-
364
344
  # Generate `link` tag application favicon.
365
345
  #
366
346
  # If no argument is given, it assumes `favico.ico` from the application.
@@ -388,35 +368,35 @@ module Hanami
388
368
  #
389
369
  # @example Basic Usage
390
370
  #
391
- # <%= favicon %>
371
+ # <%= favicon_tag %>
392
372
  #
393
373
  # # <link href="/assets/favicon.ico" rel="shortcut icon" type="image/x-icon">
394
374
  #
395
375
  # @example Custom Path
396
376
  #
397
- # <%= favicon "fav.ico" %>
377
+ # <%= favicon_tag "fav.ico" %>
398
378
  #
399
379
  # # <link href="/assets/fav.ico" rel="shortcut icon" type="image/x-icon">
400
380
  #
401
381
  # @example Custom HTML Attributes
402
382
  #
403
- # <%= favicon "favicon.ico", id: "fav" %>
383
+ # <%= favicon_tag "favicon.ico", id: "fav" %>
404
384
  #
405
385
  # # <link id: "fav" href="/assets/favicon.ico" rel="shortcut icon" type="image/x-icon">
406
386
  #
407
387
  # @example Fingerprint Mode
408
388
  #
409
- # <%= favicon %>
389
+ # <%= favicon_tag %>
410
390
  #
411
391
  # # <link href="/assets/favicon-28a6b886de2372ee3922fcaf3f78f2d8.ico" rel="shortcut icon" type="image/x-icon">
412
392
  #
413
393
  # @example CDN Mode
414
394
  #
415
- # <%= favicon %>
395
+ # <%= favicon_tag %>
416
396
  #
417
397
  # # <link href="https://assets.bookshelf.org/assets/favicon-28a6b886de2372ee3922fcaf3f78f2d8.ico"
418
398
  # rel="shortcut icon" type="image/x-icon">
419
- def favicon(source = DEFAULT_FAVICON, options = {})
399
+ def favicon_tag(source = DEFAULT_FAVICON, options = {})
420
400
  options = options.reject { |k, _| k.to_sym == :href }
421
401
 
422
402
  attributes = {
@@ -429,10 +409,6 @@ module Hanami
429
409
  tag.link(**attributes)
430
410
  end
431
411
 
432
- # @api public
433
- # @since 2.1.0
434
- alias_method :favicon_link_tag, :favicon
435
-
436
412
  # Generate `video` tag for given source
437
413
  #
438
414
  # It accepts one string representing the name of the asset, if it comes
@@ -466,19 +442,19 @@ module Hanami
466
442
  #
467
443
  # @example Basic Usage
468
444
  #
469
- # <%= video "movie.mp4" %>
445
+ # <%= video_tag "movie.mp4" %>
470
446
  #
471
447
  # # <video src="/assets/movie.mp4"></video>
472
448
  #
473
449
  # @example Absolute URL
474
450
  #
475
- # <%= video "https://example-cdn.com/assets/movie.mp4" %>
451
+ # <%= video_tag "https://example-cdn.com/assets/movie.mp4" %>
476
452
  #
477
453
  # # <video src="https://example-cdn.com/assets/movie.mp4"></video>
478
454
  #
479
455
  # @example Custom HTML Attributes
480
456
  #
481
- # <%= video("movie.mp4", autoplay: true, controls: true) %>
457
+ # <%= video_tag("movie.mp4", autoplay: true, controls: true) %>
482
458
  #
483
459
  # # <video src="/assets/movie.mp4" autoplay="autoplay" controls="controls"></video>
484
460
  #
@@ -509,36 +485,32 @@ module Hanami
509
485
  #
510
486
  # @example Without Any Argument
511
487
  #
512
- # <%= video %>
488
+ # <%= video_tag %>
513
489
  #
514
490
  # # ArgumentError
515
491
  #
516
492
  # @example Without src And Without Block
517
493
  #
518
- # <%= video(content: true) %>
494
+ # <%= video_tag(content: true) %>
519
495
  #
520
496
  # # ArgumentError
521
497
  #
522
498
  # @example Fingerprint Mode
523
499
  #
524
- # <%= video "movie.mp4" %>
500
+ # <%= video_tag "movie.mp4" %>
525
501
  #
526
502
  # # <video src="/assets/movie-28a6b886de2372ee3922fcaf3f78f2d8.mp4"></video>
527
503
  #
528
504
  # @example CDN Mode
529
505
  #
530
- # <%= video "movie.mp4" %>
506
+ # <%= video_tag "movie.mp4" %>
531
507
  #
532
508
  # # <video src="https://assets.bookshelf.org/assets/movie-28a6b886de2372ee3922fcaf3f78f2d8.mp4"></video>
533
- def video(source = nil, options = {}, &blk)
509
+ def video_tag(source = nil, options = {}, &blk)
534
510
  options = _source_options(source, options, &blk)
535
511
  tag.video(**options, &blk)
536
512
  end
537
513
 
538
- # @api public
539
- # @since 2.1.0
540
- alias_method :video_tag, :video
541
-
542
514
  # Generate `audio` tag for given source
543
515
  #
544
516
  # It accepts one string representing the name of the asset, if it comes
@@ -572,19 +544,19 @@ module Hanami
572
544
  #
573
545
  # @example Basic Usage
574
546
  #
575
- # <%= audio "song.ogg" %>
547
+ # <%= audio_tag "song.ogg" %>
576
548
  #
577
549
  # # <audio src="/assets/song.ogg"></audio>
578
550
  #
579
551
  # @example Absolute URL
580
552
  #
581
- # <%= audio "https://example-cdn.com/assets/song.ogg" %>
553
+ # <%= audio_tag "https://example-cdn.com/assets/song.ogg" %>
582
554
  #
583
555
  # # <audio src="https://example-cdn.com/assets/song.ogg"></audio>
584
556
  #
585
557
  # @example Custom HTML Attributes
586
558
  #
587
- # <%= audio("song.ogg", autoplay: true, controls: true) %>
559
+ # <%= audio_tag("song.ogg", autoplay: true, controls: true) %>
588
560
  #
589
561
  # # <audio src="/assets/song.ogg" autoplay="autoplay" controls="controls"></audio>
590
562
  #
@@ -615,36 +587,32 @@ module Hanami
615
587
  #
616
588
  # @example Without Any Argument
617
589
  #
618
- # <%= audio %>
590
+ # <%= audio_tag %>
619
591
  #
620
592
  # # ArgumentError
621
593
  #
622
594
  # @example Without src And Without Block
623
595
  #
624
- # <%= audio(controls: true) %>
596
+ # <%= audio_tag(controls: true) %>
625
597
  #
626
598
  # # ArgumentError
627
599
  #
628
600
  # @example Fingerprint Mode
629
601
  #
630
- # <%= audio "song.ogg" %>
602
+ # <%= audio_tag "song.ogg" %>
631
603
  #
632
604
  # # <audio src="/assets/song-28a6b886de2372ee3922fcaf3f78f2d8.ogg"></audio>
633
605
  #
634
606
  # @example CDN Mode
635
607
  #
636
- # <%= audio "song.ogg" %>
608
+ # <%= audio_tag "song.ogg" %>
637
609
  #
638
610
  # # <audio src="https://assets.bookshelf.org/assets/song-28a6b886de2372ee3922fcaf3f78f2d8.ogg"></audio>
639
- def audio(source = nil, options = {}, &blk)
611
+ def audio_tag(source = nil, options = {}, &blk)
640
612
  options = _source_options(source, options, &blk)
641
613
  tag.audio(**options, &blk)
642
614
  end
643
615
 
644
- # @api public
645
- # @since 2.1.0
646
- alias_method :audio_tag, :audio
647
-
648
616
  # It generates the relative or absolute URL for the given asset.
649
617
  # It automatically decides if it has to use the relative or absolute
650
618
  # depending on the configuration and current environment.
data/lib/hanami/routes.rb CHANGED
@@ -60,6 +60,35 @@ module Hanami
60
60
  end
61
61
  end
62
62
 
63
+ # Wrapper class for the (otherwise opaque) proc returned from {.routes}, adding an `#empty?`
64
+ # method that returns true if no routes were defined.
65
+ #
66
+ # This is useful when needing to determine behaviour based on the presence of user-defined
67
+ # routes, such as determining whether to show the Hanami welcome page in {Slice#load_router}.
68
+ #
69
+ # @api private
70
+ # @since 2.1.0
71
+ class RoutesProc < DelegateClass(Proc)
72
+ # @api private
73
+ # @since 2.1.0
74
+ def self.empty
75
+ new(proc {}, empty: true)
76
+ end
77
+
78
+ # @api private
79
+ # @since 2.1.0
80
+ def initialize(proc, empty: false)
81
+ @empty = empty
82
+ super(proc)
83
+ end
84
+
85
+ # @api private
86
+ # @since 2.1.0
87
+ def empty?
88
+ !!@empty
89
+ end
90
+ end
91
+
63
92
  # @api private
64
93
  def self.routes
65
94
  @routes ||= build_routes
@@ -68,9 +97,9 @@ module Hanami
68
97
  class << self
69
98
  # @api private
70
99
  def build_routes(definitions = self.definitions)
71
- return if definitions.empty?
100
+ return RoutesProc.empty if definitions.empty?
72
101
 
73
- proc do
102
+ routes_proc = proc do
74
103
  definitions.each do |(name, args, kwargs, block)|
75
104
  if block
76
105
  public_send(name, *args, **kwargs, &block)
@@ -79,6 +108,8 @@ module Hanami
79
108
  end
80
109
  end
81
110
  end
111
+
112
+ RoutesProc.new(routes_proc)
82
113
  end
83
114
 
84
115
  # @api private