hanami-assets 0.0.0 → 0.2.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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  3. data/LICENSE.md +22 -0
  4. data/README.md +426 -9
  5. data/bin/hanami-assets +22 -0
  6. data/hanami-assets.gemspec +26 -12
  7. data/lib/hanami/assets.rb +153 -2
  8. data/lib/hanami/assets/bundler.rb +173 -0
  9. data/lib/hanami/assets/cache.rb +58 -0
  10. data/lib/hanami/assets/compiler.rb +212 -0
  11. data/lib/hanami/assets/compressors/abstract.rb +119 -0
  12. data/lib/hanami/assets/compressors/builtin_javascript.rb +36 -0
  13. data/lib/hanami/assets/compressors/builtin_stylesheet.rb +57 -0
  14. data/lib/hanami/assets/compressors/closure_javascript.rb +25 -0
  15. data/lib/hanami/assets/compressors/javascript.rb +77 -0
  16. data/lib/hanami/assets/compressors/jsmin.rb +283 -0
  17. data/lib/hanami/assets/compressors/null_compressor.rb +19 -0
  18. data/lib/hanami/assets/compressors/sass_stylesheet.rb +38 -0
  19. data/lib/hanami/assets/compressors/stylesheet.rb +77 -0
  20. data/lib/hanami/assets/compressors/uglifier_javascript.rb +25 -0
  21. data/lib/hanami/assets/compressors/yui_javascript.rb +25 -0
  22. data/lib/hanami/assets/compressors/yui_stylesheet.rb +25 -0
  23. data/lib/hanami/assets/config/global_sources.rb +50 -0
  24. data/lib/hanami/assets/config/manifest.rb +112 -0
  25. data/lib/hanami/assets/config/sources.rb +77 -0
  26. data/lib/hanami/assets/configuration.rb +539 -0
  27. data/lib/hanami/assets/helpers.rb +733 -0
  28. data/lib/hanami/assets/precompiler.rb +67 -0
  29. data/lib/hanami/assets/version.rb +4 -1
  30. metadata +189 -17
  31. data/.gitignore +0 -9
  32. data/Gemfile +0 -4
  33. data/Rakefile +0 -2
  34. data/bin/console +0 -14
  35. data/bin/setup +0 -8
@@ -0,0 +1,25 @@
1
+ require 'hanami/assets/compressors/javascript'
2
+ require 'uglifier'
3
+
4
+ module Hanami
5
+ module Assets
6
+ module Compressors
7
+ # Uglifier compressor for JavaScript
8
+ #
9
+ # It depends on <tt>uglifier</tt> gem
10
+ #
11
+ # @since 0.1.0
12
+ # @api private
13
+ #
14
+ # @see http://lisperator.net/uglifyjs
15
+ # @see https://rubygems.org/gems/uglifier
16
+ class UglifierJavascript < Javascript
17
+ # @since 0.1.0
18
+ # @api private
19
+ def initialize
20
+ @compressor = Uglifier.new
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ require 'hanami/assets/compressors/javascript'
2
+ require 'yui/compressor'
3
+
4
+ module Hanami
5
+ module Assets
6
+ module Compressors
7
+ # YUI Compressor for JavaScript
8
+ #
9
+ # It depends on <tt>yui-compressor</tt> gem
10
+ #
11
+ # @since 0.1.0
12
+ # @api private
13
+ #
14
+ # @see http://yui.github.io/yuicompressor
15
+ # @see https://rubygems.org/gems/yui-compressor
16
+ class YuiJavascript < Javascript
17
+ # @since 0.1.0
18
+ # @api private
19
+ def initialize
20
+ @compressor = YUI::JavaScriptCompressor.new(munge: true)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ require 'hanami/assets/compressors/stylesheet'
2
+ require 'yui/compressor'
3
+
4
+ module Hanami
5
+ module Assets
6
+ module Compressors
7
+ # YUI Compressor for stylesheet
8
+ #
9
+ # It depends on <tt>yui-compressor</tt> gem
10
+ #
11
+ # @since 0.1.0
12
+ # @api private
13
+ #
14
+ # @see http://yui.github.io/yuicompressor
15
+ # @see https://rubygems.org/gems/yui-compressor
16
+ class YuiStylesheet < Stylesheet
17
+ # @since 0.1.0
18
+ # @api private
19
+ def initialize
20
+ @compressor = YUI::CssCompressor.new
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,50 @@
1
+ require 'hanami/utils/load_paths'
2
+
3
+ module Hanami
4
+ module Assets
5
+ # Configuration settings
6
+ #
7
+ # @since 0.1.0
8
+ # @api private
9
+ module Config
10
+ # Global asset sources across all the duplicated <tt>Hanami::Assets</tt>
11
+ # instances.
12
+ #
13
+ # @since 0.1.0
14
+ # @api private
15
+ #
16
+ # @see Hanami::Assets.duplicate
17
+ # @see http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/LoadPaths
18
+ class GlobalSources < Utils::LoadPaths
19
+ # @since 0.1.0
20
+ # @api private
21
+ def push(*paths)
22
+ super
23
+
24
+ sync_configuration
25
+ sync_duplicated_frameworks
26
+ end
27
+
28
+ # @since 0.1.0
29
+ # @api private
30
+ alias_method :<<, :push
31
+
32
+ private
33
+
34
+ # @since 0.1.0
35
+ # @api private
36
+ def sync_configuration
37
+ Hanami::Assets.configuration.sources << @paths
38
+ end
39
+
40
+ # @since 0.1.0
41
+ # @api private
42
+ def sync_duplicated_frameworks
43
+ Hanami::Assets.duplicates.each do |duplicate|
44
+ duplicate.configuration.sources << @paths
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,112 @@
1
+ module Hanami
2
+ module Assets
3
+ # This error is raised when the application starts but can't be load the
4
+ # digest manifest.
5
+ #
6
+ # @since 0.1.0
7
+ # @api private
8
+ class MissingDigestManifestError < Error
9
+ def initialize(path)
10
+ super("Can't read manifest: #{ path }")
11
+ end
12
+ end
13
+
14
+ # This error is raised when an asset is referenced from the DOM, but it's
15
+ # not present in the digest manifest
16
+ #
17
+ # @since 0.1.0
18
+ # @api private
19
+ class MissingDigestAssetError < Error
20
+ def initialize(asset, manifest_path)
21
+ super("Can't find asset `#{ asset }' in manifest (#{ manifest_path })")
22
+ end
23
+ end
24
+
25
+ # Configuration settings
26
+ #
27
+ # @since 0.1.0
28
+ # @api private
29
+ module Config
30
+ # Default value for configuration's digest manifest.
31
+ #
32
+ # It indicates that the digest manifest wasn't loaded yet.
33
+ #
34
+ # At the load time, this should be replaced by an instance of
35
+ # <tt>Hanami::Assets::Config::Manifest</tt>.
36
+ #
37
+ # If for some reason that won't happen, the instance of this class is
38
+ # still referenced by the configuration and all the method invocations
39
+ # will raise a <tt>Hanami::Assets::MissingDigestManifestError</tt>.
40
+ #
41
+ # @since 0.1.0
42
+ # @api private
43
+ #
44
+ # @see Hanami::Assets::Configuration#manifest
45
+ # @see Hanami::Assets::Configuration#manifest_path
46
+ # @see Hanami::Assets::Configuration#digest
47
+ class NullDigestManifest < Utils::BasicObject
48
+ # Return a new instance
49
+ #
50
+ # @param configuration [Hanami::Assets::Configuration]
51
+ #
52
+ # @return [Hanami::Assets::Config::NullDigestManifest] a new instance
53
+ #
54
+ # @since 0.1.0
55
+ # @api private
56
+ def initialize(configuration)
57
+ @configuration = configuration
58
+ end
59
+
60
+ # @raise [Hanami::Assets::MissingDigestManifestError]
61
+ #
62
+ # @since 0.1.0
63
+ # @api private
64
+ def method_missing(*)
65
+ ::Kernel.raise(
66
+ ::Hanami::Assets::MissingDigestManifestError.new(@configuration.manifest_path)
67
+ )
68
+ end
69
+ end
70
+
71
+ # Digest manifest
72
+ #
73
+ # @since 0.1.0
74
+ # @api private
75
+ class DigestManifest
76
+ # Return a new instance
77
+ #
78
+ # @param assets [Hash] the content of the digest manifest
79
+ # @param manifest_path [Pathname] the path to the digest manifest
80
+ #
81
+ # @return [Hanami::Assets::Config::Manifest] a new instance
82
+ #
83
+ # @since 0.1.0
84
+ # @api private
85
+ #
86
+ # @see Hanami::Assets::Configuration#manifest
87
+ # @see Hanami::Assets::Configuration#manifest_path
88
+ def initialize(assets, manifest_path)
89
+ @assets = assets
90
+ @manifest_path = manifest_path
91
+ end
92
+
93
+ # Resolve the given asset into a digest path
94
+ #
95
+ # For a given path <tt>/assets/application.js</tt> it will return
96
+ # <tt>/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.js</tt>
97
+ #
98
+ # @param asset [#to_s] the relateive asset path
99
+ #
100
+ # @return [String] the digest path
101
+ #
102
+ # @raise [Hanami::Assets::MissingDigestAssetError] when the asset can't be
103
+ # found in manifest
104
+ def resolve(asset)
105
+ @assets.fetch(asset.to_s) do
106
+ raise Hanami::Assets::MissingDigestAssetError.new(asset, @manifest_path)
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,77 @@
1
+ require 'hanami/utils/load_paths'
2
+
3
+ module Hanami
4
+ module Assets
5
+ # Configuration settings
6
+ #
7
+ # @since 0.1.0
8
+ # @api private
9
+ module Config
10
+ # Source directories for a specific application
11
+ #
12
+ # @since 0.1.0
13
+ # @api private
14
+ #
15
+ # @see Hanami::Assets.duplicate
16
+ # @see http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/LoadPaths
17
+ #
18
+ # TODO The perf of this class is poor, consider to improve it.
19
+ class Sources < Utils::LoadPaths
20
+ # @since 0.1.0
21
+ # @api private
22
+ attr_writer :root
23
+
24
+ # @since 0.1.0
25
+ # @api private
26
+ def initialize(root)
27
+ super()
28
+ @root = root
29
+ end
30
+
31
+ # @since 0.1.0
32
+ # @api private
33
+ def map
34
+ Array.new.tap do |result|
35
+ each do |source|
36
+ result << yield(source)
37
+ end
38
+ end
39
+ end
40
+
41
+ # @since 0.1.0
42
+ # @api private
43
+ def find(filename)
44
+ result = files(filename).first
45
+ result = Pathname.new(result) unless result.nil?
46
+ result
47
+ end
48
+
49
+ # @since 0.1.0
50
+ # @api private
51
+ def files(name = nil)
52
+ result = []
53
+
54
+ Dir.glob(map {|source| "#{ source }#{ ::File::SEPARATOR }**#{ ::File::SEPARATOR }#{ name }*"}).each do |file|
55
+ next if ::File.directory?(file) || ::File.basename(file).match(/\A\_/)
56
+ result << file
57
+ end
58
+
59
+ result
60
+ end
61
+
62
+ # @since 0.1.0
63
+ # @api private
64
+ def to_a
65
+ map {|s| s }
66
+ end
67
+
68
+ private
69
+ # @since 0.1.0
70
+ # @api private
71
+ def realpath(path)
72
+ @root.join(path).realpath
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,539 @@
1
+ require 'pathname'
2
+ require 'json'
3
+ require 'hanami/utils/string'
4
+ require 'hanami/utils/class'
5
+ require 'hanami/utils/path_prefix'
6
+ require 'hanami/utils/basic_object'
7
+ require 'hanami/assets/config/manifest'
8
+ require 'hanami/assets/config/sources'
9
+
10
+ module Hanami
11
+ module Assets
12
+ # Framework configuration
13
+ #
14
+ # @since 0.1.0
15
+ class Configuration
16
+ # @since 0.1.0
17
+ # @api private
18
+ DEFAULT_SCHEME = 'http'.freeze
19
+
20
+ # @since 0.1.0
21
+ # @api private
22
+ DEFAULT_HOST = 'localhost'.freeze
23
+
24
+ # @since 0.1.0
25
+ # @api private
26
+ DEFAULT_PORT = '2300'.freeze
27
+
28
+ # @since 0.1.0
29
+ # @api private
30
+ DEFAULT_PUBLIC_DIRECTORY = 'public'.freeze
31
+
32
+ # @since 0.1.0
33
+ # @api private
34
+ DEFAULT_MANIFEST = 'assets.json'.freeze
35
+
36
+ # @since 0.1.0
37
+ # @api private
38
+ DEFAULT_PREFIX = '/assets'.freeze
39
+
40
+ # @since 0.1.0
41
+ # @api private
42
+ URL_SEPARATOR = '/'.freeze
43
+
44
+ # @since 0.1.0
45
+ # @api private
46
+ HTTP_SCHEME = 'http'.freeze
47
+
48
+ # @since 0.1.0
49
+ # @api private
50
+ HTTP_PORT = '80'.freeze
51
+
52
+ # @since 0.1.0
53
+ # @api private
54
+ HTTPS_SCHEME = 'https'.freeze
55
+
56
+ # @since 0.1.0
57
+ # @api private
58
+ HTTPS_PORT = '443'.freeze
59
+
60
+ # Return a copy of the configuration of the framework instance associated
61
+ # with the given class.
62
+ #
63
+ # When multiple instances of Hanami::Assets are used in the same
64
+ # application, we want to make sure that a controller or an action will
65
+ # receive the expected configuration.
66
+ #
67
+ # @param base [Class, Module] a controller or an action
68
+ #
69
+ # @return [Hanami::Assets::Configuration] the configuration associated
70
+ # to the given class.
71
+ #
72
+ # @since 0.1.0
73
+ # @api private
74
+ def self.for(base)
75
+ # TODO this implementation is similar to Hanami::Controller::Configuration consider to extract it into Hanami::Utils
76
+ namespace = Utils::String.new(base).namespace
77
+ framework = Utils::Class.load_from_pattern!("(#{namespace}|Hanami)::Assets")
78
+ framework.configuration
79
+ end
80
+
81
+ # @since 0.1.0
82
+ # @api private
83
+ attr_reader :digest_manifest
84
+
85
+ # Return a new instance
86
+ #
87
+ # @return [Hanami::Assets::Configuration] a new instance
88
+ #
89
+ # @since 0.1.0
90
+ # @api private
91
+ def initialize
92
+ reset!
93
+ end
94
+
95
+ # Compile mode
96
+ #
97
+ # Determine if compile assets from sources to destination.
98
+ # Usually this is turned off in production mode.
99
+ #
100
+ # @since 0.1.0
101
+ def compile(value = nil)
102
+ if value.nil?
103
+ @compile
104
+ else
105
+ @compile = value
106
+ end
107
+ end
108
+
109
+ # Digest mode
110
+ #
111
+ # Determine if the helpers should generate the digest path for an asset.
112
+ # Usually this is turned on in production mode.
113
+ #
114
+ # @since 0.1.0
115
+ def digest(value = nil)
116
+ if value.nil?
117
+ @digest
118
+ else
119
+ @digest = value
120
+ end
121
+ end
122
+
123
+ # CDN mode
124
+ #
125
+ # Determine if the helpers should always generate absolute URL.
126
+ # This is useful in production mode.
127
+ #
128
+ # @since 0.1.0
129
+ def cdn(value = nil)
130
+ if value.nil?
131
+ @cdn
132
+ else
133
+ @cdn = !!value
134
+ end
135
+ end
136
+
137
+ # JavaScript compressor
138
+ #
139
+ # Determine which compressor to use for JavaScript files during deploy.
140
+ #
141
+ # By default it's <tt>nil</tt>, that means it doesn't compress JavaScripts at deploy time.
142
+ #
143
+ # It accepts a <tt>Symbol</tt> or an object that respond to <tt>#compress(file)</tt>.
144
+ #
145
+ # The following symbols are accepted:
146
+ #
147
+ # * <tt>:builtin</tt> - Ruby based implementation of jsmin. It doesn't require any external gem.
148
+ # * <tt>:yui</tt> - YUI Compressor, it depends on <tt>yui-compressor</tt> gem and it requires Java 1.4+
149
+ # * <tt>:uglifier</tt> - UglifyJS, it depends on <tt>uglifier</tt> gem and it requires Node.js
150
+ # * <tt>:closure</tt> - Google Closure Compiler, it depends on <tt>closure-compiler</tt> gem and it requires Java
151
+ #
152
+ # @param value [Symbol,#compress] the compressor
153
+ #
154
+ # @since 0.1.0
155
+ #
156
+ # @see http://yui.github.io/yuicompressor
157
+ # @see https://rubygems.org/gems/yui-compressor
158
+ #
159
+ # @see http://lisperator.net/uglifyjs
160
+ # @see https://rubygems.org/gems/uglifier
161
+ #
162
+ # @see https://developers.google.com/closure/compiler
163
+ # @see https://rubygems.org/gems/closure-compiler
164
+ #
165
+ # @example YUI Compressor
166
+ # require 'hanami/assets'
167
+ #
168
+ # Hanami::Assets.configure do
169
+ # # ...
170
+ # javascript_compressor :yui
171
+ # end.load!
172
+ #
173
+ # @example Custom Compressor
174
+ # require 'hanami/assets'
175
+ #
176
+ # Hanami::Assets.configure do
177
+ # # ...
178
+ # javascript_compressor MyCustomJavascriptCompressor.new
179
+ # end.load!
180
+ def javascript_compressor(value = nil)
181
+ if value.nil?
182
+ @javascript_compressor
183
+ else
184
+ @javascript_compressor = value
185
+ end
186
+ end
187
+
188
+ # Stylesheet compressor
189
+ #
190
+ # Determine which compressor to use for Stylesheet files during deploy.
191
+ #
192
+ # By default it's <tt>nil</tt>, that means it doesn't compress Stylesheets at deploy time.
193
+ #
194
+ # It accepts a <tt>Symbol</tt> or an object that respond to <tt>#compress(file)</tt>.
195
+ #
196
+ # The following symbols are accepted:
197
+ #
198
+ # * <tt>:builtin</tt> - Ruby based compressor. It doesn't require any external gem. It's fast, but not an efficient compressor.
199
+ # * <tt>:yui</tt> - YUI-Compressor, it depends on <tt>yui-compressor</tt> gem and requires Java 1.4+
200
+ # * <tt>:sass</tt> - Sass, it depends on <tt>sass</tt> gem
201
+ #
202
+ # @param value [Symbol,#compress] the compressor
203
+ #
204
+ # @since 0.1.0
205
+ #
206
+ # @see http://yui.github.io/yuicompressor
207
+ # @see https://rubygems.org/gems/yui-compressor
208
+ #
209
+ # @see http://sass-lang.com
210
+ # @see https://rubygems.org/gems/sass
211
+ #
212
+ # @example YUI Compressor
213
+ # require 'hanami/assets'
214
+ #
215
+ # Hanami::Assets.configure do
216
+ # # ...
217
+ # stylesheet_compressor :yui
218
+ # end.load!
219
+ #
220
+ # @example Custom Compressor
221
+ # require 'hanami/assets'
222
+ #
223
+ # Hanami::Assets.configure do
224
+ # # ...
225
+ # stylesheet_compressor MyCustomStylesheetCompressor.new
226
+ # end.load!
227
+ def stylesheet_compressor(value = nil)
228
+ if value.nil?
229
+ @stylesheet_compressor
230
+ else
231
+ @stylesheet_compressor = value
232
+ end
233
+ end
234
+
235
+ # URL scheme for the application
236
+ #
237
+ # This is used to generate absolute URL from helpers.
238
+ #
239
+ # @since 0.1.0
240
+ def scheme(value = nil)
241
+ if value.nil?
242
+ @scheme
243
+ else
244
+ @scheme = value
245
+ end
246
+ end
247
+
248
+ # URL host for the application
249
+ #
250
+ # This is used to generate absolute URL from helpers.
251
+ #
252
+ # @since 0.1.0
253
+ def host(value = nil)
254
+ if value.nil?
255
+ @host
256
+ else
257
+ @host = value
258
+ end
259
+ end
260
+
261
+ # URL port for the application
262
+ #
263
+ # This is used to generate absolute URL from helpers.
264
+ #
265
+ # @since 0.1.0
266
+ def port(value = nil)
267
+ if value.nil?
268
+ @port
269
+ else
270
+ @port = value.to_s
271
+ end
272
+ end
273
+
274
+ # URL port for the application
275
+ #
276
+ # This is used to generate absolute or relative URL from helpers.
277
+ #
278
+ # @since 0.1.0
279
+ def prefix(value = nil)
280
+ if value.nil?
281
+ @prefix
282
+ else
283
+ @prefix = Utils::PathPrefix.new(value)
284
+ end
285
+ end
286
+
287
+ # Sources root
288
+ #
289
+ # @since 0.1.0
290
+ def root(value = nil)
291
+ if value.nil?
292
+ @root
293
+ else
294
+ @root = Pathname.new(value).realpath
295
+ sources.root = @root
296
+ end
297
+ end
298
+
299
+ # Application public directory
300
+ #
301
+ # @since 0.1.0
302
+ def public_directory(value = nil)
303
+ if value.nil?
304
+ @public_directory
305
+ else
306
+ @public_directory = Pathname.new(::File.expand_path(value))
307
+ end
308
+ end
309
+
310
+ # Destination directory
311
+ #
312
+ # It's the combination of <tt>public_directory</tt> and <tt>prefix</tt>.
313
+ #
314
+ # @since 0.1.0
315
+ # @api private
316
+ def destination_directory
317
+ @destination_directory ||= public_directory.join(*prefix.split(URL_SEPARATOR))
318
+ end
319
+
320
+ # Manifest path from public directory
321
+ #
322
+ # @since 0.1.0
323
+ def manifest(value = nil)
324
+ if value.nil?
325
+ @manifest
326
+ else
327
+ @manifest = value.to_s
328
+ end
329
+ end
330
+
331
+ # Absolute manifest path
332
+ #
333
+ # @since 0.1.0
334
+ # @api private
335
+ def manifest_path
336
+ public_directory.join(manifest)
337
+ end
338
+
339
+ # Application's assets sources
340
+ #
341
+ # @since 0.1.0
342
+ # @api private
343
+ def sources
344
+ @sources ||= Hanami::Assets::Config::Sources.new(root)
345
+ end
346
+
347
+ # Application's assets
348
+ #
349
+ # @since 0.1.0
350
+ # @api private
351
+ def files
352
+ sources.files
353
+ end
354
+
355
+ # Find a file from sources
356
+ #
357
+ # @since 0.1.0
358
+ # @api private
359
+ def find(file)
360
+ @sources.find(file)
361
+ end
362
+
363
+ # Relative URL
364
+ #
365
+ # @since 0.1.0
366
+ # @api private
367
+ def asset_path(source)
368
+ cdn ?
369
+ asset_url(source) :
370
+ compile_path(source)
371
+ end
372
+
373
+ # Absolute URL
374
+ #
375
+ # @since 0.1.0
376
+ # @api private
377
+ def asset_url(source)
378
+ "#{ @base_url }#{ compile_path(source) }"
379
+ end
380
+
381
+ # Load Javascript compressor
382
+ #
383
+ # @return [Hanami::Assets::Compressors::Javascript] a compressor
384
+ #
385
+ # @raise [Hanami::Assets::Compressors::UnknownCompressorError] when the
386
+ # given name refers to an unknown compressor engine
387
+ #
388
+ # @since 0.1.0
389
+ # @api private
390
+ #
391
+ # @see Hanami::Assets::Configuration#javascript_compressor
392
+ # @see Hanami::Assets::Compressors::Javascript#for
393
+ def js_compressor
394
+ require 'hanami/assets/compressors/javascript'
395
+ Hanami::Assets::Compressors::Javascript.for(javascript_compressor)
396
+ end
397
+
398
+ # Load Stylesheet compressor
399
+ #
400
+ # @return [Hanami::Assets::Compressors::Stylesheet] a compressor
401
+ #
402
+ # @raise [Hanami::Assets::Compressors::UnknownCompressorError] when the
403
+ # given name refers to an unknown compressor engine
404
+ #
405
+ # @since 0.1.0
406
+ # @api private
407
+ #
408
+ # @see Hanami::Assets::Configuration#stylesheet_compressor
409
+ # @see Hanami::Assets::Compressors::Stylesheet#for
410
+ def css_compressor
411
+ require 'hanami/assets/compressors/stylesheet'
412
+ Hanami::Assets::Compressors::Stylesheet.for(stylesheet_compressor)
413
+ end
414
+
415
+ # @since 0.1.0
416
+ # @api private
417
+ def duplicate
418
+ Configuration.new.tap do |c|
419
+ c.root = root
420
+ c.scheme = scheme
421
+ c.host = host
422
+ c.port = port
423
+ c.prefix = prefix
424
+ c.cdn = cdn
425
+ c.compile = compile
426
+ c.public_directory = public_directory
427
+ c.manifest = manifest
428
+ c.sources = sources.dup
429
+ c.javascript_compressor = javascript_compressor
430
+ c.stylesheet_compressor = stylesheet_compressor
431
+ end
432
+ end
433
+
434
+ # @since 0.1.0
435
+ # @api private
436
+ def reset!
437
+ @scheme = DEFAULT_SCHEME
438
+ @host = DEFAULT_HOST
439
+ @port = DEFAULT_PORT
440
+
441
+ @prefix = Utils::PathPrefix.new(DEFAULT_PREFIX)
442
+ @cdn = false
443
+ @compile = false
444
+ @destination_directory = nil
445
+ @digest_manifest = Config::NullDigestManifest.new(self)
446
+
447
+ @javascript_compressor = nil
448
+ @stylesheet_compressor = nil
449
+
450
+ root Dir.pwd
451
+ public_directory root.join(DEFAULT_PUBLIC_DIRECTORY)
452
+ manifest DEFAULT_MANIFEST
453
+ end
454
+
455
+ # Load the configuration
456
+ #
457
+ # This MUST be executed before to accept the first HTTP request
458
+ #
459
+ # @since 0.1.0
460
+ def load!
461
+ if digest && manifest_path.exist?
462
+ @digest_manifest = Config::DigestManifest.new(
463
+ JSON.load(manifest_path.read),
464
+ manifest_path
465
+ )
466
+ end
467
+
468
+ @base_url = URI::Generic.build(scheme: scheme, host: host, port: url_port).to_s
469
+ end
470
+
471
+ protected
472
+
473
+ # @since 0.1.0
474
+ # @api private
475
+ attr_writer :cdn
476
+
477
+ # @since 0.1.0
478
+ # @api private
479
+ attr_writer :compile
480
+
481
+ # @since 0.1.0
482
+ # @api private
483
+ attr_writer :scheme
484
+
485
+ # @since 0.1.0
486
+ # @api private
487
+ attr_writer :host
488
+
489
+ # @since 0.1.0
490
+ # @api private
491
+ attr_writer :port
492
+
493
+ # @since 0.1.0
494
+ # @api private
495
+ attr_writer :prefix
496
+
497
+ # @since 0.1.0
498
+ # @api private
499
+ attr_writer :root
500
+
501
+ # @since 0.1.0
502
+ # @api private
503
+ attr_writer :public_directory
504
+
505
+ # @since 0.1.0
506
+ # @api private
507
+ attr_writer :manifest
508
+
509
+ # @since 0.1.0
510
+ # @api private
511
+ attr_writer :sources
512
+
513
+ # @since 0.1.0
514
+ # @api private
515
+ attr_writer :javascript_compressor
516
+
517
+ # @since 0.1.0
518
+ # @api private
519
+ attr_writer :stylesheet_compressor
520
+
521
+ private
522
+
523
+ # @since 0.1.0
524
+ # @api private
525
+ def compile_path(source)
526
+ result = prefix.join(source)
527
+ result = digest_manifest.resolve(result) if digest
528
+ result.to_s
529
+ end
530
+
531
+ # @since 0.1.0
532
+ # @api private
533
+ def url_port
534
+ ( (scheme == HTTP_SCHEME && port == HTTP_PORT ) ||
535
+ (scheme == HTTPS_SCHEME && port == HTTPS_PORT ) ) ? nil : port.to_i
536
+ end
537
+ end
538
+ end
539
+ end