hanami-assets 1.1.1 → 1.2.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d71de2dd9edf00f8046d10907f60b555b0391d3079bc81b58bd88ec68d7eaf4
4
- data.tar.gz: 823426740462f9e3d5a5357de6d6fe15d761dec2130e4e0363fe51f8b4ffebd7
3
+ metadata.gz: dee96814cdbdc9c4b0bf4519052da244585da7ce22f1ee9d002ef2bfde88344d
4
+ data.tar.gz: 7a0607dac9d21de73b5052c5b02efb7e1cf316fb278cc19fee6a197780dfb890
5
5
  SHA512:
6
- metadata.gz: c6de7ae4f3605ea0ea0a823f14699ba8b6c4358652fb377e70af78fb5147ae33554352de2d40ba168c8039836f359c8769f44107d107cd1aa4cda7e04c6fb06b
7
- data.tar.gz: fd1f5db6af660bfd1893495ce5059f915d8855c8b404fc648515dbadbcfc55d800f83867f9417f32a88399a86887d2a6b1da1cac07bd5b7e0af3233c697437c7
6
+ metadata.gz: 8a984c83ee52c5d75c9175376090b1f00bad151ca63d354d2dd626ae955defeebd685999726be12f5b884bbd6fcb5b3c49304fa8ed2425f9de1cb74708b39270
7
+ data.tar.gz: 13217797668cc3bba5369fbabd88f69796a16752193f0fbf57f270f990e1e332ec71616dc0c751a25691e1517845dc621ca5a3038032b4b2fac38e929fcf2a4f
data/CHANGELOG.md CHANGED
@@ -1,6 +1,12 @@
1
1
  # Hanami::Assets
2
2
  Assets management for Ruby web applications
3
3
 
4
+ ## v1.2.0.beta1 - 2018-02-28
5
+ ### Added
6
+ - [Luca Guidi] Collect assets informations for Early Hints (103)
7
+ - [Luca Guidi] Send automatically javascripts and stylesheets via Push Promise / Early Hints
8
+ - [Luca Guidi] Add the ability to send audio, video, and generic assets for Push Promise / Early Hints
9
+
4
10
  ## v1.1.1 - 2018-02-27
5
11
  ### Added
6
12
  - [Luca Guidi] Official support for Ruby: MRI 2.5
@@ -20,8 +20,8 @@ Gem::Specification.new do |spec|
20
20
  spec.require_paths = ['lib']
21
21
  spec.required_ruby_version = '>= 2.3.0'
22
22
 
23
- spec.add_runtime_dependency 'hanami-utils', '~> 1.1'
24
- spec.add_runtime_dependency 'hanami-helpers', '~> 1.1'
23
+ spec.add_runtime_dependency 'hanami-utils', '1.2.0.beta1'
24
+ spec.add_runtime_dependency 'hanami-helpers', '1.2.0.beta1'
25
25
  spec.add_runtime_dependency 'tilt', '~> 2.0', '>= 2.0.2'
26
26
 
27
27
  spec.add_development_dependency 'bundler'
@@ -412,6 +412,18 @@ module Hanami
412
412
  "#{@base_url}#{compile_path(source)}"
413
413
  end
414
414
 
415
+ # Check if the given source is linked via Cross-Origin policy.
416
+ # In other words, the given source, doesn't satisfy the Same-Origin policy.
417
+ #
418
+ # @see https://en.wikipedia.org/wiki/Same-origin_policy#Origin_determination_rules
419
+ # @see https://en.wikipedia.org/wiki/Same-origin_policy#document.domain_property
420
+ #
421
+ # @since 1.2.0
422
+ # @api private
423
+ def crossorigin?(source)
424
+ !source.start_with?(@base_url)
425
+ end
426
+
415
427
  # An array of crypographically secure hashing algorithms to use for
416
428
  # generating asset subresource integrity checks
417
429
  #
@@ -1,5 +1,4 @@
1
1
  require 'uri'
2
- require 'set'
3
2
  require 'hanami/helpers/html_helper'
4
3
  require 'hanami/utils/escape'
5
4
 
@@ -97,7 +96,11 @@ module Hanami
97
96
  # name of the algorithm, then a hyphen, then the hash value of the file.
98
97
  # If more than one algorithm is used, they'll be separated by a space.
99
98
  #
99
+ # It makes the script(s) eligible for HTTP/2 Push Promise/Early Hints.
100
+ # You can opt-out with inline option: `push: false`.
101
+ #
100
102
  # @param sources [Array<String>] one or more assets by name or absolute URL
103
+ # @param push [TrueClass, FalseClass] HTTP/2 Push Promise/Early Hints flag
101
104
  #
102
105
  # @return [Hanami::Utils::Escape::SafeString] the markup
103
106
  #
@@ -165,12 +168,17 @@ module Hanami
165
168
  # <%= javascript 'application' %>
166
169
  #
167
170
  # # <script src="https://assets.bookshelf.org/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.js" type="text/javascript"></script>
168
- def javascript(*sources, **options) # rubocop:disable Metrics/MethodLength
171
+ #
172
+ # @example Disable Push Promise/Early Hints
173
+ #
174
+ # <%= javascript 'application', push: false %>
175
+ # <%= javascript 'http://cdn.example.test/jquery.js', 'dashboard', push: false %>
176
+ def javascript(*sources, push: true, **options) # rubocop:disable Metrics/MethodLength
169
177
  options = options.reject { |k, _| k.to_sym == :src }
170
178
 
171
179
  _safe_tags(*sources) do |source|
172
180
  attributes = {
173
- src: _typed_asset_path(source, JAVASCRIPT_EXT),
181
+ src: _typed_asset_path(source, JAVASCRIPT_EXT, push: push, as: :script),
174
182
  type: JAVASCRIPT_MIME_TYPE
175
183
  }
176
184
  attributes.merge!(options)
@@ -199,7 +207,12 @@ module Hanami
199
207
  # If the "subresource integrity mode" is on, <tt>integriy</tt> is the
200
208
  # name of the algorithm, then a hyphen, then the hashed value of the file.
201
209
  # If more than one algorithm is used, they'll be separated by a space.
210
+ #
211
+ # It makes the script(s) eligible for HTTP/2 Push Promise/Early Hints.
212
+ # You can opt-out with inline option: `push: false`.
213
+ #
202
214
  # @param sources [Array<String>] one or more assets by name or absolute URL
215
+ # @param push [TrueClass, FalseClass] HTTP/2 Push Promise/Early Hints flag
203
216
  #
204
217
  # @return [Hanami::Utils::Escape::SafeString] the markup
205
218
  #
@@ -256,12 +269,17 @@ module Hanami
256
269
  # <%= stylesheet 'application' %>
257
270
  #
258
271
  # # <link href="https://assets.bookshelf.org/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.css" type="text/css" rel="stylesheet">
259
- def stylesheet(*sources, **options) # rubocop:disable Metrics/MethodLength
272
+ #
273
+ # @example Disable Push Promise/Early Hints
274
+ #
275
+ # <%= stylesheet 'application', push: false %>
276
+ # <%= stylesheet 'http://cdn.example.test/bootstrap.css', 'dashboard', push: false %>
277
+ def stylesheet(*sources, push: true, **options) # rubocop:disable Metrics/MethodLength
260
278
  options = options.reject { |k, _| k.to_sym == :href }
261
279
 
262
280
  _safe_tags(*sources) do |source|
263
281
  attributes = {
264
- href: _typed_asset_path(source, STYLESHEET_EXT),
282
+ href: _typed_asset_path(source, STYLESHEET_EXT, push: push, as: :style),
265
283
  type: STYLESHEET_MIME_TYPE,
266
284
  rel: STYLESHEET_REL
267
285
  }
@@ -292,6 +310,8 @@ module Hanami
292
310
  # application CDN.
293
311
  #
294
312
  # @param source [String] asset name or absolute URL
313
+ # @param options [Hash] HTML 5 attributes
314
+ # @option options [TrueClass, FalseClass] :push HTTP/2 Push Promise/Early Hints flag
295
315
  #
296
316
  # @return [Hanami::Utils::Helpers::HtmlBuilder] the builder
297
317
  #
@@ -341,11 +361,14 @@ module Hanami
341
361
  # <%= image 'logo.png' %>
342
362
  #
343
363
  # # <img src="https://assets.bookshelf.org/assets/logo-28a6b886de2372ee3922fcaf3f78f2d8.png" alt="Logo">
364
+ #
365
+ # @example Enable Push Promise/Early Hints
366
+ #
367
+ # <%= image 'logo.png', push: true %>
344
368
  def image(source, options = {})
345
369
  options = options.reject { |k, _| k.to_sym == :src }
346
-
347
370
  attributes = {
348
- src: asset_path(source),
371
+ src: asset_path(source, push: options.delete(:push) || false, as: :image),
349
372
  alt: Utils::String.titleize(::File.basename(source, WILDCARD_EXT))
350
373
  }
351
374
  attributes.merge!(options)
@@ -366,6 +389,8 @@ module Hanami
366
389
  # application CDN.
367
390
  #
368
391
  # @param source [String] asset name
392
+ # @param options [Hash] HTML 5 attributes
393
+ # @option options [TrueClass, FalseClass] :push HTTP/2 Push Promise/Early Hints flag
369
394
  #
370
395
  # @return [Hanami::Utils::Helpers::HtmlBuilder] the builder
371
396
  #
@@ -393,7 +418,7 @@ module Hanami
393
418
  #
394
419
  # @example Custom HTML Attributes
395
420
  #
396
- # <%= favicon id: 'fav' %>
421
+ # <%= favicon "favicon.ico", id: "fav" %>
397
422
  #
398
423
  # # <link id: "fav" href="/assets/favicon.ico" rel="shortcut icon" type="image/x-icon">
399
424
  #
@@ -408,11 +433,15 @@ module Hanami
408
433
  # <%= favicon %>
409
434
  #
410
435
  # # <link href="https://assets.bookshelf.org/assets/favicon-28a6b886de2372ee3922fcaf3f78f2d8.ico" rel="shortcut icon" type="image/x-icon">
436
+ #
437
+ # @example Enable Push Promise/Early Hints
438
+ #
439
+ # <%= favicon 'favicon.ico', push: true %>
411
440
  def favicon(source = DEFAULT_FAVICON, options = {})
412
441
  options = options.reject { |k, _| k.to_sym == :href }
413
442
 
414
443
  attributes = {
415
- href: asset_path(source),
444
+ href: asset_path(source, push: options.delete(:push) || false, as: :image),
416
445
  rel: FAVICON_REL,
417
446
  type: FAVICON_MIME_TYPE
418
447
  }
@@ -437,6 +466,8 @@ module Hanami
437
466
  # application CDN.
438
467
  #
439
468
  # @param source [String] asset name or absolute URL
469
+ # @param options [Hash] HTML 5 attributes
470
+ # @option options [TrueClass, FalseClass] :push HTTP/2 Push Promise/Early Hints flag
440
471
  #
441
472
  # @return [Hanami::Utils::Helpers::HtmlBuilder] the builder
442
473
  #
@@ -535,8 +566,20 @@ module Hanami
535
566
  # <%= video 'movie.mp4' %>
536
567
  #
537
568
  # # <video src="https://assets.bookshelf.org/assets/movie-28a6b886de2372ee3922fcaf3f78f2d8.mp4"></video>
569
+ #
570
+ # @example Enable Push Promise/Early Hints
571
+ #
572
+ # <%= video 'movie.mp4', push: true %>
573
+ #
574
+ # <%=
575
+ # video do
576
+ # text "Your browser does not support the video tag"
577
+ # source src: asset_path("movie.mp4", push: :video), type: "video/mp4"
578
+ # source src: asset_path("movie.ogg"), type: "video/ogg"
579
+ # end
580
+ # %>
538
581
  def video(source = nil, options = {}, &blk)
539
- options = _source_options(source, options, &blk)
582
+ options = _source_options(source, options, as: :video, &blk)
540
583
  html.video(blk, options)
541
584
  end
542
585
 
@@ -556,6 +599,8 @@ module Hanami
556
599
  # application CDN.
557
600
  #
558
601
  # @param source [String] asset name or absolute URL
602
+ # @param options [Hash] HTML 5 attributes
603
+ # @option options [TrueClass, FalseClass] :push HTTP/2 Push Promise/Early Hints flag
559
604
  #
560
605
  # @return [Hanami::Utils::Helpers::HtmlBuilder] the builder
561
606
  #
@@ -654,8 +699,20 @@ module Hanami
654
699
  # <%= audio 'song.ogg' %>
655
700
  #
656
701
  # # <audio src="https://assets.bookshelf.org/assets/song-28a6b886de2372ee3922fcaf3f78f2d8.ogg"></audio>
702
+ #
703
+ # @example Enable Push Promise/Early Hints
704
+ #
705
+ # <%= audio 'movie.mp4', push: true %>
706
+ #
707
+ # <%=
708
+ # audio do
709
+ # text "Your browser does not support the audio tag"
710
+ # source src: asset_path("song.ogg", push: :audio), type: "audio/ogg"
711
+ # source src: asset_path("song.wav"), type: "audio/wav"
712
+ # end
713
+ # %>
657
714
  def audio(source = nil, options = {}, &blk)
658
- options = _source_options(source, options, &blk)
715
+ options = _source_options(source, options, as: :audio, &blk)
659
716
  html.audio(blk, options)
660
717
  end
661
718
 
@@ -671,6 +728,8 @@ module Hanami
671
728
  # If CDN mode is on, it returns the absolute URL of the asset.
672
729
  #
673
730
  # @param source [String] the asset name
731
+ # @param push [TrueClass, FalseClass, Symbol] HTTP/2 Push Promise/Early Hints flag, or type
732
+ # @param as [Symbol] HTTP/2 Push Promise / Early Hints flag type
674
733
  #
675
734
  # @return [String] the asset path
676
735
  #
@@ -703,8 +762,12 @@ module Hanami
703
762
  # <%= asset_path 'application.js' %>
704
763
  #
705
764
  # # "https://assets.bookshelf.org/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.js"
706
- def asset_path(source)
707
- _asset_url(source) { _relative_url(source) }
765
+ #
766
+ # @example Enable Push Promise/Early Hints
767
+ #
768
+ # <%= asset_path "application.js", push: :script %>
769
+ def asset_path(source, push: false, as: nil)
770
+ _asset_url(source, push: push, as: as) { _relative_url(source) }
708
771
  end
709
772
 
710
773
  # It generates the absolute URL for the given source.
@@ -719,6 +782,8 @@ module Hanami
719
782
  # If CDN mode is on, it returns the absolute URL of the asset.
720
783
  #
721
784
  # @param source [String] the asset name
785
+ # @param push [TrueClass, FalseClass, Symbol] HTTP/2 Push Promise/Early Hints flag, or type
786
+ # @param as [Symbol] HTTP/2 Push Promise / Early Hints flag type
722
787
  #
723
788
  # @return [String] the asset URL
724
789
  #
@@ -751,8 +816,12 @@ module Hanami
751
816
  # <%= asset_url 'application.js' %>
752
817
  #
753
818
  # # "https://assets.bookshelf.org/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.js"
754
- def asset_url(source)
755
- _asset_url(source) { _absolute_url(source) }
819
+ #
820
+ # @example Enable Push Promise/Early Hints
821
+ #
822
+ # <%= asset_url "application.js", push: :script %>
823
+ def asset_url(source, push: false, as: nil)
824
+ _asset_url(source, push: push, as: as) { _absolute_url(source) }
756
825
  end
757
826
 
758
827
  private
@@ -769,18 +838,24 @@ module Hanami
769
838
 
770
839
  # @since 0.1.0
771
840
  # @api private
772
- def _asset_url(source)
773
- _push_promise(
774
- _absolute_url?(source) ? # rubocop:disable Style/MultilineTernaryOperator
775
- source : yield
776
- )
841
+ def _asset_url(source, push:, as:)
842
+ url = _absolute_url?(source) ? source : yield
843
+
844
+ case push
845
+ when Symbol
846
+ _push_promise(url, as: push)
847
+ when TrueClass
848
+ _push_promise(url, as: as)
849
+ end
850
+
851
+ url
777
852
  end
778
853
 
779
854
  # @since 0.1.0
780
855
  # @api private
781
- def _typed_asset_path(source, ext)
856
+ def _typed_asset_path(source, ext, push: false, as: nil)
782
857
  source = "#{source}#{ext}" if _append_extension?(source, ext)
783
- asset_path(source)
858
+ asset_path(source, push: push, as: as)
784
859
  end
785
860
 
786
861
  # @api private
@@ -800,6 +875,13 @@ module Hanami
800
875
  ABSOLUTE_URL_MATCHER.match(source)
801
876
  end
802
877
 
878
+ # @since 1.2.0
879
+ # @api private
880
+ def _crossorigin?(source)
881
+ return false unless _absolute_url?(source)
882
+ self.class.assets_configuration.crossorigin?(source)
883
+ end
884
+
803
885
  # @since 0.1.0
804
886
  # @api private
805
887
  def _relative_url(source)
@@ -814,13 +896,13 @@ module Hanami
814
896
 
815
897
  # @since 0.1.0
816
898
  # @api private
817
- def _source_options(src, options, &_blk)
899
+ def _source_options(src, options, as:, &_blk)
818
900
  options ||= {}
819
901
 
820
902
  if src.respond_to?(:to_hash)
821
903
  options = src.to_hash
822
904
  elsif src
823
- options[:src] = asset_path(src)
905
+ options[:src] = asset_path(src, push: options.delete(:push) || false, as: as)
824
906
  end
825
907
 
826
908
  if !options[:src] && !block_given?
@@ -832,11 +914,9 @@ module Hanami
832
914
 
833
915
  # @since 0.1.0
834
916
  # @api private
835
- def _push_promise(url)
836
- Mutex.new.synchronize do
837
- Thread.current[:__hanami_assets] ||= Set.new
838
- Thread.current[:__hanami_assets].add(url.to_s)
839
- end
917
+ def _push_promise(url, as: nil)
918
+ Thread.current[:__hanami_assets] ||= {}
919
+ Thread.current[:__hanami_assets][url.to_s] = { as: as, crossorigin: _crossorigin?(url) }
840
920
 
841
921
  url
842
922
  end
@@ -3,6 +3,6 @@ module Hanami
3
3
  # Defines the version
4
4
  #
5
5
  # @since 0.1.0
6
- VERSION = '1.1.1'.freeze
6
+ VERSION = '1.2.0.beta1'.freeze
7
7
  end
8
8
  end
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hanami-assets
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-02-27 00:00:00.000000000 Z
11
+ date: 2018-02-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hanami-utils
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: '1.1'
19
+ version: 1.2.0.beta1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: '1.1'
26
+ version: 1.2.0.beta1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: hanami-helpers
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - '='
32
32
  - !ruby/object:Gem::Version
33
- version: '1.1'
33
+ version: 1.2.0.beta1
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - '='
39
39
  - !ruby/object:Gem::Version
40
- version: '1.1'
40
+ version: 1.2.0.beta1
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: tilt
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -240,9 +240,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
240
240
  version: 2.3.0
241
241
  required_rubygems_version: !ruby/object:Gem::Requirement
242
242
  requirements:
243
- - - ">="
243
+ - - ">"
244
244
  - !ruby/object:Gem::Version
245
- version: '0'
245
+ version: 1.3.1
246
246
  requirements: []
247
247
  rubyforge_project:
248
248
  rubygems_version: 2.7.5