hanami-assets 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +49 -25
- data/bin/hanami-assets +4 -4
- data/hanami-assets.gemspec +7 -7
- data/lib/hanami/assets/bundler/asset.rb +98 -0
- data/lib/hanami/assets/bundler/compressor.rb +61 -0
- data/lib/hanami/assets/bundler/manifest_entry.rb +62 -0
- data/lib/hanami/assets/bundler.rb +35 -62
- data/lib/hanami/assets/cache.rb +58 -15
- data/lib/hanami/assets/compiler.rb +66 -45
- data/lib/hanami/assets/compilers/less.rb +29 -0
- data/lib/hanami/assets/compilers/sass.rb +46 -0
- data/lib/hanami/assets/compressors/sass_stylesheet.rb +2 -2
- data/lib/hanami/assets/config/global_sources.rb +1 -1
- data/lib/hanami/assets/config/manifest.rb +23 -3
- data/lib/hanami/assets/config/sources.rb +8 -3
- data/lib/hanami/assets/configuration.rb +90 -23
- data/lib/hanami/assets/helpers.rb +81 -9
- data/lib/hanami/assets/precompiler.rb +31 -8
- data/lib/hanami/assets/version.rb +1 -1
- data/lib/hanami/assets.rb +12 -10
- metadata +15 -11
@@ -12,50 +12,58 @@ module Hanami
|
|
12
12
|
# Framework configuration
|
13
13
|
#
|
14
14
|
# @since 0.1.0
|
15
|
-
class Configuration
|
15
|
+
class Configuration # rubocop:disable Metrics/ClassLength
|
16
16
|
# @since 0.1.0
|
17
17
|
# @api private
|
18
|
-
DEFAULT_SCHEME
|
18
|
+
DEFAULT_SCHEME = 'http'.freeze
|
19
19
|
|
20
20
|
# @since 0.1.0
|
21
21
|
# @api private
|
22
|
-
DEFAULT_HOST
|
22
|
+
DEFAULT_HOST = 'localhost'.freeze
|
23
23
|
|
24
24
|
# @since 0.1.0
|
25
25
|
# @api private
|
26
|
-
DEFAULT_PORT
|
26
|
+
DEFAULT_PORT = '2300'.freeze
|
27
27
|
|
28
28
|
# @since 0.1.0
|
29
29
|
# @api private
|
30
|
-
DEFAULT_PUBLIC_DIRECTORY
|
30
|
+
DEFAULT_PUBLIC_DIRECTORY = 'public'.freeze
|
31
31
|
|
32
32
|
# @since 0.1.0
|
33
33
|
# @api private
|
34
|
-
DEFAULT_MANIFEST
|
34
|
+
DEFAULT_MANIFEST = 'assets.json'.freeze
|
35
35
|
|
36
36
|
# @since 0.1.0
|
37
37
|
# @api private
|
38
|
-
DEFAULT_PREFIX
|
38
|
+
DEFAULT_PREFIX = '/assets'.freeze
|
39
39
|
|
40
40
|
# @since 0.1.0
|
41
41
|
# @api private
|
42
|
-
URL_SEPARATOR
|
42
|
+
URL_SEPARATOR = '/'.freeze
|
43
43
|
|
44
44
|
# @since 0.1.0
|
45
45
|
# @api private
|
46
|
-
HTTP_SCHEME
|
46
|
+
HTTP_SCHEME = 'http'.freeze
|
47
47
|
|
48
48
|
# @since 0.1.0
|
49
49
|
# @api private
|
50
|
-
HTTP_PORT
|
50
|
+
HTTP_PORT = '80'.freeze
|
51
51
|
|
52
52
|
# @since 0.1.0
|
53
53
|
# @api private
|
54
|
-
HTTPS_SCHEME
|
54
|
+
HTTPS_SCHEME = 'https'.freeze
|
55
55
|
|
56
56
|
# @since 0.1.0
|
57
57
|
# @api private
|
58
|
-
HTTPS_PORT
|
58
|
+
HTTPS_PORT = '443'.freeze
|
59
|
+
|
60
|
+
# @since 0.3.0
|
61
|
+
# @api private
|
62
|
+
DEFAULT_SUBRESOURCE_INTEGRITY_ALGORITHM = :sha256
|
63
|
+
|
64
|
+
# @since 0.3.0
|
65
|
+
# @api private
|
66
|
+
SUBRESOURCE_INTEGRITY_SEPARATOR = ' '.freeze
|
59
67
|
|
60
68
|
# Return a copy of the configuration of the framework instance associated
|
61
69
|
# with the given class.
|
@@ -72,7 +80,7 @@ module Hanami
|
|
72
80
|
# @since 0.1.0
|
73
81
|
# @api private
|
74
82
|
def self.for(base)
|
75
|
-
# TODO this implementation is similar to Hanami::Controller::Configuration consider to extract it into Hanami::Utils
|
83
|
+
# TODO: this implementation is similar to Hanami::Controller::Configuration consider to extract it into Hanami::Utils
|
76
84
|
namespace = Utils::String.new(base).namespace
|
77
85
|
framework = Utils::Class.load_from_pattern!("(#{namespace}|Hanami)::Assets")
|
78
86
|
framework.configuration
|
@@ -120,6 +128,22 @@ module Hanami
|
|
120
128
|
end
|
121
129
|
end
|
122
130
|
|
131
|
+
# Subresource integrity mode
|
132
|
+
#
|
133
|
+
# Determine if the helpers should generate the integrity attribute for an
|
134
|
+
# asset. Usually this is turned on in production mode.
|
135
|
+
#
|
136
|
+
# @since 0.3.0
|
137
|
+
def subresource_integrity(*values)
|
138
|
+
if values.empty?
|
139
|
+
@subresource_integrity
|
140
|
+
elsif values.length == 1
|
141
|
+
@subresource_integrity = values.first
|
142
|
+
else
|
143
|
+
@subresource_integrity = values
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
123
147
|
# CDN mode
|
124
148
|
#
|
125
149
|
# Determine if the helpers should always generate absolute URL.
|
@@ -130,7 +154,7 @@ module Hanami
|
|
130
154
|
if value.nil?
|
131
155
|
@cdn
|
132
156
|
else
|
133
|
-
@cdn = !!value
|
157
|
+
@cdn = !!value # rubocop:disable Style/DoubleNegation
|
134
158
|
end
|
135
159
|
end
|
136
160
|
|
@@ -352,6 +376,13 @@ module Hanami
|
|
352
376
|
sources.files
|
353
377
|
end
|
354
378
|
|
379
|
+
# @since 0.3.0
|
380
|
+
# @api private
|
381
|
+
def source(file)
|
382
|
+
pathname = Pathname.new(file)
|
383
|
+
pathname.absolute? ? pathname : find(file)
|
384
|
+
end
|
385
|
+
|
355
386
|
# Find a file from sources
|
356
387
|
#
|
357
388
|
# @since 0.1.0
|
@@ -365,9 +396,11 @@ module Hanami
|
|
365
396
|
# @since 0.1.0
|
366
397
|
# @api private
|
367
398
|
def asset_path(source)
|
368
|
-
cdn
|
369
|
-
asset_url(source)
|
399
|
+
if cdn
|
400
|
+
asset_url(source)
|
401
|
+
else
|
370
402
|
compile_path(source)
|
403
|
+
end
|
371
404
|
end
|
372
405
|
|
373
406
|
# Absolute URL
|
@@ -375,7 +408,33 @@ module Hanami
|
|
375
408
|
# @since 0.1.0
|
376
409
|
# @api private
|
377
410
|
def asset_url(source)
|
378
|
-
"#{
|
411
|
+
"#{@base_url}#{compile_path(source)}"
|
412
|
+
end
|
413
|
+
|
414
|
+
# An array of digest algorithms to use for generating asset subresource
|
415
|
+
# integrity checks
|
416
|
+
#
|
417
|
+
# @since 0.3.0
|
418
|
+
def subresource_integrity_algorithms
|
419
|
+
if @subresource_integrity == true
|
420
|
+
[DEFAULT_SUBRESOURCE_INTEGRITY_ALGORITHM]
|
421
|
+
else
|
422
|
+
# Using Array() allows us to accept Array or Symbol, and '|| nil' lets
|
423
|
+
# us return an empty array when @subresource_integrity is `false`
|
424
|
+
Array(@subresource_integrity || nil)
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
# Subresource integrity attribute
|
429
|
+
#
|
430
|
+
# @since 0.3.0
|
431
|
+
# @api private
|
432
|
+
def subresource_integrity_value(source)
|
433
|
+
if subresource_integrity
|
434
|
+
digest_manifest.subresource_integrity_values(
|
435
|
+
prefix.join(source)
|
436
|
+
).join(SUBRESOURCE_INTEGRITY_SEPARATOR)
|
437
|
+
end
|
379
438
|
end
|
380
439
|
|
381
440
|
# Load Javascript compressor
|
@@ -414,13 +473,14 @@ module Hanami
|
|
414
473
|
|
415
474
|
# @since 0.1.0
|
416
475
|
# @api private
|
417
|
-
def duplicate
|
476
|
+
def duplicate # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
418
477
|
Configuration.new.tap do |c|
|
419
478
|
c.root = root
|
420
479
|
c.scheme = scheme
|
421
480
|
c.host = host
|
422
481
|
c.port = port
|
423
482
|
c.prefix = prefix
|
483
|
+
c.subresource_integrity = subresource_integrity
|
424
484
|
c.cdn = cdn
|
425
485
|
c.compile = compile
|
426
486
|
c.public_directory = public_directory
|
@@ -433,14 +493,17 @@ module Hanami
|
|
433
493
|
|
434
494
|
# @since 0.1.0
|
435
495
|
# @api private
|
436
|
-
def reset!
|
496
|
+
def reset! # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
437
497
|
@scheme = DEFAULT_SCHEME
|
438
498
|
@host = DEFAULT_HOST
|
439
499
|
@port = DEFAULT_PORT
|
440
500
|
|
441
501
|
@prefix = Utils::PathPrefix.new(DEFAULT_PREFIX)
|
502
|
+
@subresource_integrity = false
|
442
503
|
@cdn = false
|
504
|
+
@digest = false
|
443
505
|
@compile = false
|
506
|
+
@base_url = nil
|
444
507
|
@destination_directory = nil
|
445
508
|
@digest_manifest = Config::NullDigestManifest.new(self)
|
446
509
|
|
@@ -458,7 +521,7 @@ module Hanami
|
|
458
521
|
#
|
459
522
|
# @since 0.1.0
|
460
523
|
def load!
|
461
|
-
if digest && manifest_path.exist?
|
524
|
+
if (digest || subresource_integrity) && manifest_path.exist?
|
462
525
|
@digest_manifest = Config::DigestManifest.new(
|
463
526
|
JSON.load(manifest_path.read),
|
464
527
|
manifest_path
|
@@ -470,6 +533,10 @@ module Hanami
|
|
470
533
|
|
471
534
|
protected
|
472
535
|
|
536
|
+
# @since 0.3.0
|
537
|
+
# @api private
|
538
|
+
attr_writer :subresource_integrity
|
539
|
+
|
473
540
|
# @since 0.1.0
|
474
541
|
# @api private
|
475
542
|
attr_writer :cdn
|
@@ -524,15 +591,15 @@ module Hanami
|
|
524
591
|
# @api private
|
525
592
|
def compile_path(source)
|
526
593
|
result = prefix.join(source)
|
527
|
-
result = digest_manifest.
|
594
|
+
result = digest_manifest.target(result) if digest
|
528
595
|
result.to_s
|
529
596
|
end
|
530
597
|
|
531
598
|
# @since 0.1.0
|
532
599
|
# @api private
|
533
600
|
def url_port
|
534
|
-
(
|
535
|
-
(scheme == HTTPS_SCHEME && port == HTTPS_PORT
|
601
|
+
((scheme == HTTP_SCHEME && port == HTTP_PORT) || # rubocop:disable Style/MultilineTernaryOperator
|
602
|
+
(scheme == HTTPS_SCHEME && port == HTTPS_PORT)) ? nil : port.to_i
|
536
603
|
end
|
537
604
|
end
|
538
605
|
end
|
@@ -13,7 +13,7 @@ module Hanami
|
|
13
13
|
# @since 0.1.0
|
14
14
|
#
|
15
15
|
# @see http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/HtmlHelper
|
16
|
-
module Helpers
|
16
|
+
module Helpers # rubocop:disable Metrics/ModuleLength
|
17
17
|
# @since 0.1.0
|
18
18
|
# @api private
|
19
19
|
NEW_LINE_SEPARATOR = "\n".freeze
|
@@ -54,6 +54,14 @@ module Hanami
|
|
54
54
|
# @api private
|
55
55
|
DEFAULT_FAVICON = 'favicon.ico'.freeze
|
56
56
|
|
57
|
+
# @since 0.3.0
|
58
|
+
# @api private
|
59
|
+
CROSSORIGIN_ANONYMOUS = 'anonymous'.freeze
|
60
|
+
|
61
|
+
# @since 0.3.0
|
62
|
+
# @api private
|
63
|
+
ABSOLUTE_URL_MATCHER = URI::Parser.new.make_regexp
|
64
|
+
|
57
65
|
include Hanami::Helpers::HtmlHelper
|
58
66
|
|
59
67
|
# Inject helpers into the given class
|
@@ -108,6 +116,30 @@ module Hanami
|
|
108
116
|
# # <script src="/assets/application.js" type="text/javascript"></script>
|
109
117
|
# # <script src="/assets/dashboard.js" type="text/javascript"></script>
|
110
118
|
#
|
119
|
+
# @example Asynchronous Execution
|
120
|
+
#
|
121
|
+
# <%= javascript 'application', async: true %>
|
122
|
+
#
|
123
|
+
# # <script src="/assets/application.js" type="text/javascript" async="async"></script>
|
124
|
+
#
|
125
|
+
# @example Subresource Integrity
|
126
|
+
#
|
127
|
+
# <%= javascript 'application' %>
|
128
|
+
#
|
129
|
+
# # <script src="/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.js" type="text/javascript" integrity="sha384-oqVu...Y8wC" crossorigin="anonymous"></script>
|
130
|
+
#
|
131
|
+
# @example Subresource Integrity for 3rd Party Scripts
|
132
|
+
#
|
133
|
+
# <%= javascript 'https://example.com/assets/example.js', integrity: 'sha384-oqVu...Y8wC' %>
|
134
|
+
#
|
135
|
+
# # <script src="https://example.com/assets/example.js" type="text/javascript" integrity="sha384-oqVu...Y8wC" crossorigin="anonymous"></script>
|
136
|
+
#
|
137
|
+
# @example Deferred Execution
|
138
|
+
#
|
139
|
+
# <%= javascript 'application', defer: true %>
|
140
|
+
#
|
141
|
+
# # <script src="/assets/application.js" type="text/javascript" defer="defer"></script>
|
142
|
+
#
|
111
143
|
# @example Absolute URL
|
112
144
|
#
|
113
145
|
# <%= javascript 'https://code.jquery.com/jquery-2.1.4.min.js' %>
|
@@ -125,9 +157,18 @@ module Hanami
|
|
125
157
|
# <%= javascript 'application' %>
|
126
158
|
#
|
127
159
|
# # <script src="https://assets.bookshelf.org/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.js" type="text/javascript"></script>
|
128
|
-
def javascript(*sources)
|
160
|
+
def javascript(*sources, **options)
|
129
161
|
_safe_tags(*sources) do |source|
|
130
|
-
|
162
|
+
tag_options = options.dup
|
163
|
+
tag_options[:src] ||= _typed_asset_path(source, JAVASCRIPT_EXT)
|
164
|
+
tag_options[:type] ||= JAVASCRIPT_MIME_TYPE
|
165
|
+
|
166
|
+
if _subresource_integrity? || tag_options.include?(:integrity)
|
167
|
+
tag_options[:integrity] ||= _subresource_integrity_value(source, JAVASCRIPT_EXT)
|
168
|
+
tag_options[:crossorigin] ||= CROSSORIGIN_ANONYMOUS
|
169
|
+
end
|
170
|
+
|
171
|
+
html.script(**tag_options).to_s
|
131
172
|
end
|
132
173
|
end
|
133
174
|
|
@@ -169,6 +210,18 @@ module Hanami
|
|
169
210
|
# # <link href="/assets/application.css" type="text/css" rel="stylesheet">
|
170
211
|
# # <link href="/assets/dashboard.css" type="text/css" rel="stylesheet">
|
171
212
|
#
|
213
|
+
# @example Subresource Integrity
|
214
|
+
#
|
215
|
+
# <%= stylesheet 'application' %>
|
216
|
+
#
|
217
|
+
# # <link href="/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.css" type="text/css" integrity="sha384-oqVu...Y8wC" crossorigin="anonymous"></script>
|
218
|
+
#
|
219
|
+
# @example Subresource Integrity for 3rd Party Assets
|
220
|
+
#
|
221
|
+
# <%= stylesheet 'https://example.com/assets/example.css', integrity: 'sha384-oqVu...Y8wC' %>
|
222
|
+
#
|
223
|
+
# # <link href="https://example.com/assets/example.css" type="text/css" rel="stylesheet" integrity="sha384-oqVu...Y8wC" crossorigin="anonymous"></script>
|
224
|
+
#
|
172
225
|
# @example Absolute URL
|
173
226
|
#
|
174
227
|
# <%= stylesheet 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css' %>
|
@@ -186,9 +239,19 @@ module Hanami
|
|
186
239
|
# <%= stylesheet 'application' %>
|
187
240
|
#
|
188
241
|
# # <link href="https://assets.bookshelf.org/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.css" type="text/css" rel="stylesheet">
|
189
|
-
def stylesheet(*sources)
|
242
|
+
def stylesheet(*sources, **options) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
190
243
|
_safe_tags(*sources) do |source|
|
191
|
-
|
244
|
+
tag_options = options.dup
|
245
|
+
tag_options[:href] ||= _typed_asset_path(source, STYLESHEET_EXT)
|
246
|
+
tag_options[:type] ||= STYLESHEET_MIME_TYPE
|
247
|
+
tag_options[:rel] ||= STYLESHEET_REL
|
248
|
+
|
249
|
+
if _subresource_integrity? || tag_options.include?(:integrity)
|
250
|
+
tag_options[:integrity] ||= _subresource_integrity_value(source, STYLESHEET_EXT)
|
251
|
+
tag_options[:crossorigin] ||= CROSSORIGIN_ANONYMOUS
|
252
|
+
end
|
253
|
+
|
254
|
+
html.link(**tag_options).to_s
|
192
255
|
end
|
193
256
|
end
|
194
257
|
|
@@ -670,7 +733,7 @@ module Hanami
|
|
670
733
|
# @api private
|
671
734
|
def _asset_url(source)
|
672
735
|
_push_promise(
|
673
|
-
_absolute_url?(source) ?
|
736
|
+
_absolute_url?(source) ? # rubocop:disable Style/MultilineTernaryOperator
|
674
737
|
source : yield
|
675
738
|
)
|
676
739
|
end
|
@@ -678,14 +741,23 @@ module Hanami
|
|
678
741
|
# @since 0.1.0
|
679
742
|
# @api private
|
680
743
|
def _typed_asset_path(source, ext)
|
681
|
-
source = "#{
|
744
|
+
source = "#{source}#{ext}" unless source =~ /#{Regexp.escape(ext)}\z/
|
682
745
|
asset_path(source)
|
683
746
|
end
|
684
747
|
|
748
|
+
def _subresource_integrity?
|
749
|
+
!!self.class.assets_configuration.subresource_integrity # rubocop:disable Style/DoubleNegation
|
750
|
+
end
|
751
|
+
|
752
|
+
def _subresource_integrity_value(source, ext)
|
753
|
+
source = "#{source}#{ext}" unless source =~ /#{Regexp.escape(ext)}\z/
|
754
|
+
self.class.assets_configuration.subresource_integrity_value(source) unless _absolute_url?(source)
|
755
|
+
end
|
756
|
+
|
685
757
|
# @since 0.1.0
|
686
758
|
# @api private
|
687
759
|
def _absolute_url?(source)
|
688
|
-
|
760
|
+
ABSOLUTE_URL_MATCHER.match(source)
|
689
761
|
end
|
690
762
|
|
691
763
|
# @since 0.1.0
|
@@ -702,7 +774,7 @@ module Hanami
|
|
702
774
|
|
703
775
|
# @since 0.1.0
|
704
776
|
# @api private
|
705
|
-
def _source_options(src, options, &
|
777
|
+
def _source_options(src, options, &_blk)
|
706
778
|
options ||= {}
|
707
779
|
|
708
780
|
if src.respond_to?(:to_hash)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'fileutils'
|
1
2
|
require 'hanami/assets/compiler'
|
2
3
|
|
3
4
|
module Hanami
|
@@ -30,22 +31,35 @@ module Hanami
|
|
30
31
|
# @since 0.1.0
|
31
32
|
# @api private
|
32
33
|
def run
|
33
|
-
|
34
|
+
clear_assets_directory
|
34
35
|
precompile
|
35
36
|
end
|
36
37
|
|
37
38
|
private
|
38
39
|
|
39
|
-
# @since 0.
|
40
|
+
# @since 0.3.0
|
40
41
|
# @api private
|
41
|
-
def
|
42
|
-
|
43
|
-
|
42
|
+
def clear_assets_directory
|
43
|
+
delete @configuration.manifest_path
|
44
|
+
delete @configuration.destination_directory
|
45
|
+
end
|
46
|
+
|
47
|
+
# @since 0.3.0
|
48
|
+
# @api private
|
49
|
+
def clear_manifest(manifest)
|
50
|
+
JSON.load(manifest).each do |_, asset_hash|
|
51
|
+
asset_file_name = @configuration.public_directory.join(asset_hash['target'])
|
52
|
+
asset_file_name.unlink if asset_file_name.exist?
|
53
|
+
end
|
54
|
+
rescue JSON::ParserError
|
55
|
+
$stderr.puts 'Non JSON manifest found and unlinked.'
|
56
|
+
ensure
|
57
|
+
manifest.unlink
|
44
58
|
end
|
45
59
|
|
46
60
|
# @since 0.1.0
|
47
61
|
# @api private
|
48
|
-
def precompile
|
62
|
+
def precompile # rubocop:disable Metrics/MethodLength
|
49
63
|
applications.each do |duplicate|
|
50
64
|
config = if duplicate.respond_to?(:configuration)
|
51
65
|
duplicate.configuration
|
@@ -64,8 +78,17 @@ module Hanami
|
|
64
78
|
# @since 0.1.0
|
65
79
|
# @api private
|
66
80
|
def applications
|
67
|
-
@duplicates.empty?
|
68
|
-
[@configuration]
|
81
|
+
if @duplicates.empty?
|
82
|
+
[@configuration]
|
83
|
+
else
|
84
|
+
@duplicates
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# @since 0.3.0
|
89
|
+
# @api private
|
90
|
+
def delete(path)
|
91
|
+
FileUtils.rm_rf(path) if path.exist?
|
69
92
|
end
|
70
93
|
end
|
71
94
|
end
|
data/lib/hanami/assets.rb
CHANGED
@@ -93,22 +93,22 @@ module Hanami
|
|
93
93
|
# Hanami::Assets.sources << '/path/to/emberjs/assets'
|
94
94
|
def self.sources
|
95
95
|
synchronize do
|
96
|
-
@@sources ||= Config::GlobalSources.new
|
96
|
+
@@sources ||= Config::GlobalSources.new # rubocop:disable Style/ClassVars
|
97
97
|
end
|
98
98
|
end
|
99
99
|
|
100
100
|
# Duplicate the framework and generate modules for the target application
|
101
101
|
#
|
102
|
-
# @param
|
102
|
+
# @param _mod [Module] the Ruby namespace of the application
|
103
103
|
# @param blk [Proc] an optional block to configure the framework
|
104
104
|
#
|
105
105
|
# @return [Module] a copy of Hanami::Assets
|
106
106
|
#
|
107
|
-
#
|
107
|
+
# @since 0.1.0
|
108
108
|
#
|
109
109
|
# @see Hanami::Assets#dupe
|
110
110
|
# @see Hanami::Assets::Configuration
|
111
|
-
def self.duplicate(
|
111
|
+
def self.duplicate(_mod, &blk)
|
112
112
|
dupe.tap do |duplicated|
|
113
113
|
duplicated.configure(&blk) if block_given?
|
114
114
|
duplicates << duplicated
|
@@ -143,16 +143,18 @@ module Hanami
|
|
143
143
|
# @see Hanami::Assets#dupe
|
144
144
|
def self.duplicates
|
145
145
|
synchronize do
|
146
|
-
@@duplicates ||=
|
146
|
+
@@duplicates ||= [] # rubocop:disable Style/ClassVars
|
147
147
|
end
|
148
148
|
end
|
149
149
|
|
150
|
-
|
150
|
+
class << self
|
151
|
+
private
|
151
152
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
153
|
+
# @since 0.1.0
|
154
|
+
# @api private
|
155
|
+
def synchronize(&blk)
|
156
|
+
Mutex.new.synchronize(&blk)
|
157
|
+
end
|
156
158
|
end
|
157
159
|
end
|
158
160
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hanami-assets
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luca Guidi
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2016-
|
13
|
+
date: 2016-07-22 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: hanami-utils
|
@@ -18,28 +18,28 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - "~>"
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: '0.
|
21
|
+
version: '0.8'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
26
26
|
- - "~>"
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
version: '0.
|
28
|
+
version: '0.8'
|
29
29
|
- !ruby/object:Gem::Dependency
|
30
30
|
name: hanami-helpers
|
31
31
|
requirement: !ruby/object:Gem::Requirement
|
32
32
|
requirements:
|
33
33
|
- - "~>"
|
34
34
|
- !ruby/object:Gem::Version
|
35
|
-
version: '0.
|
35
|
+
version: '0.4'
|
36
36
|
type: :runtime
|
37
37
|
prerelease: false
|
38
38
|
version_requirements: !ruby/object:Gem::Requirement
|
39
39
|
requirements:
|
40
40
|
- - "~>"
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: '0.
|
42
|
+
version: '0.4'
|
43
43
|
- !ruby/object:Gem::Dependency
|
44
44
|
name: tilt
|
45
45
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,14 +80,14 @@ dependencies:
|
|
80
80
|
requirements:
|
81
81
|
- - "~>"
|
82
82
|
- !ruby/object:Gem::Version
|
83
|
-
version: '
|
83
|
+
version: '11'
|
84
84
|
type: :development
|
85
85
|
prerelease: false
|
86
86
|
version_requirements: !ruby/object:Gem::Requirement
|
87
87
|
requirements:
|
88
88
|
- - "~>"
|
89
89
|
- !ruby/object:Gem::Version
|
90
|
-
version: '
|
90
|
+
version: '11'
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: minitest
|
93
93
|
requirement: !ruby/object:Gem::Requirement
|
@@ -203,8 +203,13 @@ files:
|
|
203
203
|
- hanami-assets.gemspec
|
204
204
|
- lib/hanami/assets.rb
|
205
205
|
- lib/hanami/assets/bundler.rb
|
206
|
+
- lib/hanami/assets/bundler/asset.rb
|
207
|
+
- lib/hanami/assets/bundler/compressor.rb
|
208
|
+
- lib/hanami/assets/bundler/manifest_entry.rb
|
206
209
|
- lib/hanami/assets/cache.rb
|
207
210
|
- lib/hanami/assets/compiler.rb
|
211
|
+
- lib/hanami/assets/compilers/less.rb
|
212
|
+
- lib/hanami/assets/compilers/sass.rb
|
208
213
|
- lib/hanami/assets/compressors/abstract.rb
|
209
214
|
- lib/hanami/assets/compressors/builtin_javascript.rb
|
210
215
|
- lib/hanami/assets/compressors/builtin_stylesheet.rb
|
@@ -236,7 +241,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
236
241
|
requirements:
|
237
242
|
- - ">="
|
238
243
|
- !ruby/object:Gem::Version
|
239
|
-
version: 2.
|
244
|
+
version: 2.2.0
|
240
245
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
241
246
|
requirements:
|
242
247
|
- - ">="
|
@@ -244,9 +249,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
244
249
|
version: '0'
|
245
250
|
requirements: []
|
246
251
|
rubyforge_project:
|
247
|
-
rubygems_version: 2.
|
252
|
+
rubygems_version: 2.6.4
|
248
253
|
signing_key:
|
249
254
|
specification_version: 4
|
250
255
|
summary: Assets management
|
251
256
|
test_files: []
|
252
|
-
has_rdoc:
|