hanami-assets 0.2.1 → 0.3.0

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
  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