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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 15727c44014a8955a11e3ca6fee4f113768447b9
4
- data.tar.gz: e9bbfc0c852365081730a441afa657ba8ef6aa45
3
+ metadata.gz: 6ac62b03f4a875750283f436f0c830152e9decba
4
+ data.tar.gz: 31d8b0704edd9bf86756ebe3ca481226e12f1c73
5
5
  SHA512:
6
- metadata.gz: dcae9c85fa64d98e67da40d615c7e1c50df244ed7317a4968e4b35fa0e97f5709700e9ecf9e70c16db4c7966a4cd4852b6a6df48d30b0cc9efdd712ef5af9b8b
7
- data.tar.gz: bbd26c301fe64b96173607b0311abc479e594b9b8e51c1745bc10c9d65b04d517d6d73ac22c22174885ca0b12b4a1695e14094b63e3091445c53f773d3e22cde
6
+ metadata.gz: 906de34660db373299b9e779a770c67a7192b209927050f4743f4b58510df4e4be9c8f51c13a4db2b3b1a8b6c89628f6fee087526cbd31b51071bfcd78500539
7
+ data.tar.gz: fd378bbdf3479319c9d8b0a5e1aa53384551eef44b7c9c6ed746397c4114d3efb78c25f14711d5221194ae19bf44c5d450a3a882b8b30ea6516061b44b9d7884
data/CHANGELOG.md CHANGED
@@ -1,6 +1,20 @@
1
1
  # Hanami::Assets
2
2
  Assets management for Ruby web applications
3
3
 
4
+ ## v0.3.0 - 2016-07-22
5
+ ### Added
6
+ - [Matthew Gibbons & Sean Collins] Subresource Integrity (SRI)
7
+ - [Matthew Gibbons & Sean Collins] Allow `javascript` and `stylesheet` helpers to accept a Hash representing HTML attributes. Eg. `<%= javascript 'application', async: true %>`
8
+
9
+ ### Fixed
10
+ - [Alexander Gräfe] Safely precompile assets from directories with a dot in their name.
11
+ - [Luca Guidi] Detect changes for Sass/SCSS dependencies.
12
+ - [Maxim Dorofienko & Luca Guidi] Preserve static assets under public directory, by removing only assets directory and manifest at the precompile time.
13
+
14
+ ### Changed
15
+ – [Luca Guidi] Drop support for Ruby 2.0 and 2.1. Official support for JRuby 9.0.5.0+.
16
+ - [Luca Guidi] Don't create digest version of files under public directory, but only for precompiled files.
17
+
4
18
  ## v0.2.1 - 2016-02-05
5
19
  ### Changed
6
20
  - [Derk-Jan Karrenbeld] Don't precompile `.map` files
data/README.md CHANGED
@@ -51,9 +51,9 @@ $ gem install hanami-assets
51
51
 
52
52
  ### Helpers
53
53
 
54
- The framework offers assets specific helpers to be used in templates.
54
+ `Hanami::Assets` provides asset-specific helpers to be used in templates.
55
55
  They resolve one or multiple sources into corresponding HTML tags.
56
- Those sources can be the name of the local asset or an absolute URL.
56
+ Those sources can be either a name of a local asset or an absolute URL.
57
57
 
58
58
  Given the following template:
59
59
 
@@ -73,7 +73,7 @@ Given the following template:
73
73
  </html>
74
74
  ```
75
75
 
76
- It will output this markup.
76
+ It will output this markup:
77
77
 
78
78
  ```html
79
79
  <!doctype HTML>
@@ -124,7 +124,7 @@ For advanced configurations, please have a look at
124
124
 
125
125
  ### Available Helpers
126
126
 
127
- This gems ships with the following helpers:
127
+ This gem ships with the following helpers:
128
128
 
129
129
  * `javascript`
130
130
  * `stylesheet`
@@ -191,10 +191,10 @@ that file would be copied into the public directory instead of the one under
191
191
  `Hanami::Assets` is able to run assets preprocessors and **lazily compile** them
192
192
  under `public/assets` (by default), before the markup is generated.
193
193
 
194
- Imagine to have `main.css.scss` under `app/assets/stylesheets` and `reset.css` under
194
+ Imagine you have `main.css.scss` under `app/assets/stylesheets` and `reset.css` under
195
195
  `vendor/stylesheets`.
196
196
 
197
- **The extensions structure is important.**
197
+ **The two extensions are important.**
198
198
  The first one is mandatory and it's used to understand which asset type we are
199
199
  handling: `.css` for stylesheets.
200
200
  The second one is optional and it's for a preprocessor: `.scss` for Sass.
@@ -213,13 +213,13 @@ Hanami::Assets.configure do
213
213
  end
214
214
  ```
215
215
 
216
- When from a template you do:
216
+ And in a template you can use the `stylesheet` helper:
217
217
 
218
218
  ```erb
219
219
  <%= stylesheet 'reset', 'main' %>
220
220
  ```
221
221
 
222
- Your public directory will have the following structure.
222
+ Your public directory will look like this:
223
223
 
224
224
  ```shell
225
225
  % tree public
@@ -231,23 +231,25 @@ public/
231
231
 
232
232
  ### Preprocessors engines
233
233
 
234
- `Hanami::Assets` uses [Tilt](https://github.com/rtomayko/tilt) to provide support for the most common preprocessors, such as [Sass](http://sass-lang.com/) (including `sassc-ruby`), [Less](http://lesscss.org/), ES6, [JSX](https://jsx.github.io/), [CoffeScript](http://coffeescript.org), [Opal](http://opalrb.org), [Handlebars](http://handlebarsjs.com), [JBuilder](https://github.com/rails/jbuilder).
234
+ `Hanami::Assets` uses [Tilt](https://github.com/rtomayko/tilt) to provide support for the most common preprocessors, such as [Sass](http://sass-lang.com/) (including `sassc-ruby`), [Less](http://lesscss.org/), [ES6](https://babeljs.io/), [JSX](https://jsx.github.io/), [CoffeScript](http://coffeescript.org), [Opal](http://opalrb.org), [Handlebars](http://handlebarsjs.com), [JBuilder](https://github.com/rails/jbuilder).
235
235
 
236
- In order to use one or more of them, be sure to include the corresponding gem into your `Gemfile` and require the library.
236
+ In order to use one or more of them, be sure to add the corresponding gem to your `Gemfile` and require the library.
237
237
 
238
238
  #### EcmaScript 6
239
239
 
240
- We strongly suggest to use [EcmaScript 6](http://es6-features.org/) for your next project.
241
- It isn't fully [supported](https://kangax.github.io/compat-table/es6/) yet by browser vendors, but it's the future of JavaScript.
240
+ We strongly suggest you use [EcmaScript 6](http://es6-features.org/) for your next project.
241
+ It isn't fully [supported](https://kangax.github.io/compat-table/es6/) yet by browsers, but it's the future of JavaScript.
242
242
 
243
- As of today, you need to transpile ES6 code into something understandable by current browsers, which is ES5.
244
- For this purpose we support [Babel](https://babeljs.io).
243
+ As of today, you need to 'transpile' ES6 code into ES5, which current browsers understand.
244
+ The most popular tool for this is [Babel](https://babeljs.io), which we support.
245
245
 
246
246
  ### Deployment
247
247
 
248
248
  `Hanami::Assets` ships with an executable (`hanami-assets`), which can be used to precompile assets and make them cacheable by browsers (via checksum suffix).
249
249
 
250
- Let's say we have an application that has main file that requires the entire code (`config/environment.rb`), a gem that brings Ember.js code, and the following sources:
250
+ __NOTE__: If you're using `Hanami::Assets` with the full `Hanami` framework, you should use `bundle exec hanami assets precompile` instead of `hanami-assets`.
251
+
252
+ Let's say we have an application that has a main file that requires the entire codebase (`config/environment.rb`), a gem that brings in Ember.js code, and the following sources:
251
253
 
252
254
  ```shell
253
255
  % tree .
@@ -321,14 +323,14 @@ public
321
323
 
322
324
  #### Compressors
323
325
 
324
- Minification is a process that shrink file size in production, by removing unnecessary spaces and characters.
325
- The goal of this step, is to have lighter assets to be served faster to the browsers.
326
+ Minification is a process that shrinks file size in production, by removing unnecessary spaces and characters.
327
+ The goal of this step is to have lighter assets, which will be served faster to browsers.
326
328
 
327
- Hanami supports JavaScript and stylesheets minifiers.
329
+ Hanami supports JavaScript and stylesheet minifiers.
328
330
 
329
331
  Because this framework relies on external gems for minification, this feature is **turned off by default**.
330
332
 
331
- To do so we need to specify which gem we want to use and add it to our `Gemfile`.
333
+ To use minification, we need to specify which gem we want to use and add it to our `Gemfile`.
332
334
 
333
335
  ##### JavaScript Compressors
334
336
 
@@ -347,7 +349,7 @@ end
347
349
 
348
350
  ##### Stylesheet Compressors
349
351
 
350
- Hanami can use the following compressors (aka minifiers) for Stylesheet.
352
+ Hanami can use the following compressors (aka minifiers) for stylesheets.
351
353
 
352
354
  * `:builtin` - Ruby based compressor. It doesn't require any external gem. It's fast, but not an efficient compressor.
353
355
  * `:yui` - [YUI Compressor](http://yui.github.io/yuicompressor), it depends on [`yui-compressor`](https://rubygems.org/gems/yui-compressor) gem and it requires Java 1.4+
@@ -372,7 +374,9 @@ end
372
374
 
373
375
  ### Digest Mode
374
376
 
375
- This is a mode that can be activated via the configuration and it's suitable for production environments.
377
+ This is a mode that can be activated via configuration and it's suitable for production environments.
378
+ When generating files, it adds a string to the end of each file name, which is a cachesum of its contents.
379
+ This lets you leverage caching while still ensuring that clients get the most up-to-date assets (this is known as *cache busting*).
376
380
 
377
381
  ```ruby
378
382
  Hanami::Assets.configure do
@@ -390,9 +394,29 @@ Once turned on, it will look at `/public/assets.json`, and helpers such as `java
390
394
  <script src="/assets/application-d1829dc353b734e3adc24855693b70f9.js" type="text/javascript"></script>
391
395
  ```
392
396
 
397
+ ### Subresource Integrity (SRI) Mode
398
+
399
+ This is a mode that can be activated via the configuration and it's suitable for production environments.
400
+
401
+ ```ruby
402
+ Hanami::Assets.configure do
403
+ subresource_integrity true
404
+ end
405
+ ```
406
+
407
+ Once turned on, it will look at `/public/assets.json`, and helpers such as `javascript` will include an `integrity` and `crossorigin` attribute.
408
+
409
+ ```erb
410
+ <%= javascript 'application' %>
411
+ ```
412
+
413
+ ```html
414
+ <script src="/assets/application-d1829dc353b734e3adc24855693b70f9.js" type="text/javascript" integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC" crossorigin="anonymous"></script>
415
+ ```
416
+
393
417
  ### CDN Mode
394
418
 
395
- A Hanami project can serve assets via CDN.
419
+ A Hanami project can serve assets via a Content Delivery Network (CDN).
396
420
 
397
421
  ```ruby
398
422
  Hanami::Assets.configure do
@@ -403,7 +427,7 @@ Hanami::Assets.configure do
403
427
  end
404
428
  ```
405
429
 
406
- Since now on, helpers will return the CDN absolute URL for the asset.
430
+ From now on, helpers will return the absolute URL for the asset, hosted on the CDN specified.
407
431
 
408
432
  ```erb
409
433
  <%= javascript 'application' %>
@@ -417,7 +441,7 @@ Since now on, helpers will return the CDN absolute URL for the asset.
417
441
 
418
442
  Developers can maintain gems that distribute assets for Hanami. For instance `hanami-ember` or `hanami-jquery`.
419
443
 
420
- As a gem developer, you must add one or more paths, where the assets are stored inside the gem.
444
+ To do this, inside your gem you have tell `Hanami::Assets` where to look for assets:
421
445
 
422
446
  ```ruby
423
447
  # lib/hanami/jquery.rb
@@ -428,7 +452,7 @@ Hanami::Assets.sources << '/path/to/jquery'
428
452
 
429
453
  * Make sure you have one of [ExecJS](https://github.com/rails/execjs)
430
454
  supported runtime on your machine.
431
- * Java 1.4+
455
+ * Java 1.4+ (for YUI Compressor and Google Closure Compiler)
432
456
 
433
457
  ```sh
434
458
  bundle exec rake test
data/bin/hanami-assets CHANGED
@@ -5,16 +5,16 @@ require 'pathname'
5
5
 
6
6
  options = {}
7
7
  OptionParser.new do |opts|
8
- opts.banner = "Usage: hanami-assets --config=path/to/config.rb"
8
+ opts.banner = 'Usage: hanami-assets --config=path/to/config.rb'
9
9
 
10
- opts.on("-c", "--config FILE", "Path to config") do |c|
10
+ opts.on('-c', '--config FILE', 'Path to config') do |c|
11
11
  options[:config] = c
12
12
  end
13
13
  end.parse!
14
14
 
15
- config = options.fetch(:config) { raise ArgumentError.new("You must specify a configuration file") }
15
+ config = options.fetch(:config) { raise ArgumentError.new('You must specify a configuration file') }
16
16
  config = Pathname.new(config)
17
- config.exist? or raise ArgumentError.new("Cannot find configuration file: #{ config }")
17
+ config.exist? or raise ArgumentError.new("Cannot find configuration file: #{config}") # rubocop:disable Style/AndOr
18
18
 
19
19
  require 'hanami/assets'
20
20
  load config
@@ -8,23 +8,23 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Hanami::Assets::VERSION
9
9
  spec.authors = ['Luca Guidi', 'Trung Lê', 'Alfonso Uceda']
10
10
  spec.email = ['me@lucaguidi.com', 'trung.le@ruby-journal.com', 'uceda73@gmail.com']
11
- spec.summary = %q{Assets management}
12
- spec.description = %q{Assets management for Ruby web applications}
11
+ spec.summary = 'Assets management'
12
+ spec.description = 'Assets management for Ruby web applications'
13
13
  spec.homepage = 'http://hanamirb.org'
14
14
  spec.license = 'MIT'
15
15
 
16
- spec.files = `git ls-files -- lib/* bin/* CHANGELOG.md LICENSE.md README.md hanami-assets.gemspec`.split($/)
16
+ spec.files = `git ls-files -- lib/* bin/* CHANGELOG.md LICENSE.md README.md hanami-assets.gemspec`.split($/) # rubocop:disable Style/SpecialGlobalVars
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ['lib']
20
- spec.required_ruby_version = '>= 2.0.0'
20
+ spec.required_ruby_version = '>= 2.2.0'
21
21
 
22
- spec.add_runtime_dependency 'hanami-utils', '~> 0.7'
23
- spec.add_runtime_dependency 'hanami-helpers', '~> 0.3'
22
+ spec.add_runtime_dependency 'hanami-utils', '~> 0.8'
23
+ spec.add_runtime_dependency 'hanami-helpers', '~> 0.4'
24
24
  spec.add_runtime_dependency 'tilt', '~> 2.0', '>= 2.0.2'
25
25
 
26
26
  spec.add_development_dependency 'bundler', '~> 1.6'
27
- spec.add_development_dependency 'rake', '~> 10'
27
+ spec.add_development_dependency 'rake', '~> 11'
28
28
  spec.add_development_dependency 'minitest', '~> 5'
29
29
 
30
30
  spec.add_development_dependency 'yui-compressor', '~> 0.12'
@@ -0,0 +1,98 @@
1
+ require 'openssl'
2
+
3
+ module Hanami
4
+ module Assets
5
+ # Bundle assets from a single application.
6
+ #
7
+ # @since 0.1.0
8
+ # @api private
9
+ class Bundler
10
+ # @since 0.3.0
11
+ # @api private
12
+ class Asset
13
+ # @since 0.3.0
14
+ # @api private
15
+ attr_reader :path
16
+
17
+ # @since 0.3.0
18
+ # @api private
19
+ attr_reader :configuration
20
+
21
+ # @since 0.3.0
22
+ # @api private
23
+ WILDCARD_EXT = '.*'.freeze
24
+
25
+ # Return a new instance
26
+ #
27
+ # @since 0.3.0
28
+ # @api private
29
+ def initialize(path, configuration)
30
+ @path = path
31
+ @configuration = configuration
32
+ end
33
+
34
+ # @since 0.3.0
35
+ # @api private
36
+ def expanded_path
37
+ ::File.expand_path(@path)
38
+ end
39
+
40
+ # @since 0.3.0
41
+ # @api private
42
+ def fingerprinted_target
43
+ ::File.join(directory, "#{filename}-#{fingerprint}#{extension}")
44
+ end
45
+
46
+ # @since 0.3.0
47
+ # @api private
48
+ def expanded_fingerprinted_target
49
+ ::File.expand_path(fingerprinted_target)
50
+ end
51
+
52
+ # @since 0.3.0
53
+ # @api private
54
+ def base64_digest(algorithm)
55
+ raw_digest(algorithm).base64digest
56
+ end
57
+
58
+ private
59
+
60
+ # @since 0.3.0
61
+ # @api private
62
+ def directory
63
+ ::File.dirname(@path)
64
+ end
65
+
66
+ # @since 0.3.0
67
+ # @api private
68
+ def filename
69
+ ::File.basename(@path, WILDCARD_EXT)
70
+ end
71
+
72
+ # @since 0.3.0
73
+ # @api private
74
+ def extension
75
+ ::File.extname(@path)
76
+ end
77
+
78
+ # @since 0.3.0
79
+ # @api private
80
+ def fingerprint
81
+ raw_digest(:md5).hexdigest
82
+ end
83
+
84
+ # @since 0.3.0
85
+ # @api private
86
+ def raw_digest(algorithm)
87
+ OpenSSL::Digest.new(algorithm.to_s, contents)
88
+ end
89
+
90
+ # @since 0.3.0
91
+ # @api private
92
+ def contents
93
+ ::File.read(@path)
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,61 @@
1
+ module Hanami
2
+ module Assets
3
+ class Bundler
4
+ # Compresses a JS or CSS file
5
+ #
6
+ # @since 0.3.0
7
+ # @api private
8
+ class Compressor
9
+ # @since 0.3.0
10
+ # @api private
11
+ JAVASCRIPT_EXT = '.js'.freeze
12
+
13
+ # @since 0.3.0
14
+ # @api private
15
+ STYLESHEET_EXT = '.css'.freeze
16
+
17
+ # Return a new instance
18
+ #
19
+ # @since 0.3.0
20
+ # @api private
21
+ def initialize(path, configuration)
22
+ @path = path
23
+ @configuration = configuration
24
+ end
25
+
26
+ # @return [String, nil] the compressed contents of the file OR nil if it's not compressable
27
+ #
28
+ # @since 0.3.0
29
+ # @api private
30
+ def compress
31
+ case File.extname(@path)
32
+ when JAVASCRIPT_EXT then _compress(compressor(:js))
33
+ when STYLESHEET_EXT then _compress(compressor(:css))
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ # @since 0.3.0
40
+ # @api private
41
+ def compressor(type)
42
+ @configuration.__send__(:"#{ type }_compressor")
43
+ end
44
+
45
+ # @since 0.3.0
46
+ # @api private
47
+ def _compress(compressor)
48
+ compressor.compress(@path)
49
+ rescue => e
50
+ warn(
51
+ [
52
+ "Skipping compression of: `#{@path}'",
53
+ "Reason: #{e}\n",
54
+ "\t#{e.backtrace.join("\n\t")}\n\n"
55
+ ].join("\n")
56
+ )
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,62 @@
1
+ module Hanami
2
+ module Assets
3
+ class Bundler
4
+ # Constructs a hash for a single asset's manifest file entry
5
+ #
6
+ # @since 0.3.0
7
+ # @api private
8
+ class ManifestEntry
9
+ # @since 0.3.0
10
+ # @api private
11
+ SUBRESOURCE_INTEGRITY_SEPARATOR = '-'.freeze
12
+
13
+ # Return a new instance
14
+ #
15
+ # @since 0.3.0
16
+ # @api private
17
+ def initialize(asset)
18
+ @asset = asset
19
+ end
20
+
21
+ # A single entry for this asset, to go into manifest file
22
+ # @since 0.3.0
23
+ # @api private
24
+ def entry
25
+ { name => values }
26
+ end
27
+
28
+ private
29
+
30
+ # @since 0.3.0
31
+ # @api private
32
+ def name
33
+ _convert_to_url(@asset.expanded_path)
34
+ end
35
+
36
+ # @since 0.3.0
37
+ # @api private
38
+ def values
39
+ Hash[
40
+ target: _convert_to_url(@asset.expanded_fingerprinted_target),
41
+ sri: subresource_integrity_values
42
+ ]
43
+ end
44
+
45
+ # @since 0.3.0
46
+ # @api private
47
+ def subresource_integrity_values
48
+ @asset.configuration.subresource_integrity_algorithms.map do |algorithm|
49
+ [algorithm, @asset.base64_digest(algorithm)].join(SUBRESOURCE_INTEGRITY_SEPARATOR)
50
+ end
51
+ end
52
+
53
+ # @since 0.3.0
54
+ # @api private
55
+ def _convert_to_url(path)
56
+ path.sub(@asset.configuration.public_directory.to_s, URL_REPLACEMENT)
57
+ .gsub(File::SEPARATOR, URL_SEPARATOR)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -1,7 +1,10 @@
1
- require 'digest'
2
1
  require 'fileutils'
3
2
  require 'json'
4
3
 
4
+ require 'hanami/assets/bundler/compressor'
5
+ require 'hanami/assets/bundler/asset'
6
+ require 'hanami/assets/bundler/manifest_entry'
7
+
5
8
  module Hanami
6
9
  module Assets
7
10
  # Bundle assets from a single application.
@@ -11,19 +14,7 @@ module Hanami
11
14
  class Bundler
12
15
  # @since 0.1.0
13
16
  # @api private
14
- DEFAULT_PERMISSIONS = 0644
15
-
16
- # @since 0.1.0
17
- # @api private
18
- JAVASCRIPT_EXT = '.js'.freeze
19
-
20
- # @since 0.1.0
21
- # @api private
22
- STYLESHEET_EXT = '.css'.freeze
23
-
24
- # @since 0.1.0
25
- # @api private
26
- WILDCARD_EXT = '.*'.freeze
17
+ DEFAULT_PERMISSIONS = 0o644
27
18
 
28
19
  # @since 0.1.0
29
20
  # @api private
@@ -45,7 +36,7 @@ module Hanami
45
36
  # @since 0.1.0
46
37
  # @api private
47
38
  def initialize(configuration, duplicates)
48
- @manifest = Hash.new
39
+ @manifest = Hash[]
49
40
  @configuration = configuration
50
41
  @configurations = if duplicates.empty?
51
42
  [@configuration]
@@ -60,6 +51,7 @@ module Hanami
60
51
  #
61
52
  # * Compress
62
53
  # * Create a checksum version
54
+ # * Generate an integrity digest
63
55
  #
64
56
  # At the end it will generate a digest manifest
65
57
  #
@@ -67,78 +59,57 @@ module Hanami
67
59
  # @see Hanami::Assets::Configuration#manifest
68
60
  # @see Hanami::Assets::Configuration#manifest_path
69
61
  def run
70
- assets.each do |asset|
71
- next if ::File.directory?(asset)
72
-
73
- compress(asset)
74
- checksum(asset)
62
+ assets.each do |path|
63
+ unless File.directory?(path)
64
+ configuration = _configuration_for(path)
65
+ process(Asset.new(path, configuration))
66
+ end
75
67
  end
76
68
 
77
- generate_manifest
69
+ write_manifest_file
78
70
  end
79
71
 
80
72
  private
81
73
 
82
- # @since 0.1.0
74
+ # @since 0.3.0
83
75
  # @api private
84
- def assets
85
- Dir.glob("#{ public_directory }#{ ::File::SEPARATOR }**#{ ::File::SEPARATOR }*")
76
+ def process(asset)
77
+ compress_in_place!(asset)
78
+ copy_to_fingerprinted_location!(asset)
79
+ @manifest.merge!(ManifestEntry.new(asset).entry)
86
80
  end
87
81
 
88
- # @since 0.1.0
82
+ # @since 0.3.0
89
83
  # @api private
90
- def compress(asset)
91
- case File.extname(asset)
92
- when JAVASCRIPT_EXT then _compress(compressor(:js, asset), asset)
93
- when STYLESHEET_EXT then _compress(compressor(:css, asset), asset)
94
- end
84
+ def copy_to_fingerprinted_location!(asset)
85
+ FileUtils.cp(asset.path, asset.fingerprinted_target)
86
+ _set_permissions(asset.fingerprinted_target)
95
87
  end
96
88
 
97
- # @since 0.1.0
89
+ # @since 0.3.0
98
90
  # @api private
99
- def checksum(asset)
100
- digest = Digest::MD5.file(asset)
101
- filename, ext = ::File.basename(asset, WILDCARD_EXT), ::File.extname(asset)
102
- directory = ::File.dirname(asset)
103
- target = [directory, "#{ filename }-#{ digest }#{ ext }"].join(::File::SEPARATOR)
104
-
105
- FileUtils.cp(asset, target)
106
- _set_permissions(target)
107
-
108
- store_manifest(asset, target)
91
+ def compress_in_place!(asset)
92
+ compressed = Compressor.new(asset.path, asset.configuration).compress
93
+ _write(asset.path, compressed) unless compressed.nil?
109
94
  end
110
95
 
111
- # @since 0.1.0
96
+ # @since 0.3.0
112
97
  # @api private
113
- def generate_manifest
98
+ def write_manifest_file
114
99
  _write(@configuration.manifest_path, JSON.dump(@manifest))
115
100
  end
116
101
 
117
102
  # @since 0.1.0
118
103
  # @api private
119
- def store_manifest(asset, target)
120
- @manifest[_convert_to_url(::File.expand_path(asset))] = _convert_to_url(::File.expand_path(target))
121
- end
122
-
123
- # @since 0.1.0
124
- # @api private
125
- def compressor(type, asset)
126
- _configuration_for(asset).__send__(:"#{ type }_compressor")
127
- end
128
-
129
- # @since 0.1.0
130
- # @api private
131
- def _compress(compressor, asset)
132
- _write(asset, compressor.compress(asset))
133
- rescue => e
134
- warn "Skipping compression of: `#{ asset }'\nReason: #{ e }\n\t#{ e.backtrace.join("\n\t") }\n\n"
104
+ def assets
105
+ Dir.glob("#{@configuration.destination_directory}#{::File::SEPARATOR}**#{::File::SEPARATOR}*")
135
106
  end
136
107
 
137
108
  # @since 0.1.0
138
109
  # @api private
139
110
  def _convert_to_url(path)
140
- path.sub(public_directory.to_s, URL_REPLACEMENT).
141
- gsub(File::SEPARATOR, URL_SEPARATOR)
111
+ path.sub(public_directory.to_s, URL_REPLACEMENT)
112
+ .gsub(File::SEPARATOR, URL_SEPARATOR)
142
113
  end
143
114
 
144
115
  # @since 0.1.0
@@ -156,10 +127,12 @@ module Hanami
156
127
  ::File.chmod(DEFAULT_PERMISSIONS, path)
157
128
  end
158
129
 
130
+ # @since 0.3.0
131
+ # @api private
159
132
  def _configuration_for(asset)
160
133
  url = _convert_to_url(asset)
161
134
 
162
- @configurations.find {|config| url.start_with?(config.prefix) } ||
135
+ @configurations.find { |config| url.start_with?(config.prefix) } ||
163
136
  @configuration
164
137
  end
165
138