lotus-assets 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,19 @@
1
+ require 'lotus/assets/compressors/abstract'
2
+
3
+ module Lotus
4
+ module Assets
5
+ module Compressors
6
+ # No-op, it returns the asset contents without to compress them.
7
+ #
8
+ # @since 0.1.0
9
+ # @api private
10
+ class NullCompressor < Abstract
11
+ # @since 0.1.0
12
+ # @api private
13
+ def compress(filename)
14
+ read(filename)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,38 @@
1
+ require 'lotus/assets/compressors/stylesheet'
2
+ require 'sass'
3
+
4
+ module Lotus
5
+ module Assets
6
+ module Compressors
7
+ # Sass compressor for stylesheet
8
+ #
9
+ # It depends on <tt>sass</tt> gem.
10
+ #
11
+ # @since 0.1.0
12
+ # @api private
13
+ #
14
+ # @see http://sass-lang.com
15
+ # @see https://rubygems.org/gems/sass
16
+ class SassStylesheet < Stylesheet
17
+ # @since 0.1.0
18
+ # @api private
19
+ #
20
+ # FIXME This is the same logic that we have for Lotus::Assets::Compiler
21
+ SASS_CACHE_LOCATION = Pathname(Lotus.respond_to?(:root) ?
22
+ Lotus.root : Dir.pwd).join('tmp', 'sass-cache')
23
+ # @since 0.1.0
24
+ # @api private
25
+ def initialize
26
+ @compressor = Sass::Engine
27
+ end
28
+
29
+ # @since 0.1.0
30
+ # @api private
31
+ def compress(filename)
32
+ compressor.new(read(filename), filename: filename, syntax: :scss,
33
+ style: :compressed, cache_location: SASS_CACHE_LOCATION).render
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,77 @@
1
+ require 'lotus/assets/compressors/abstract'
2
+
3
+ module Lotus
4
+ module Assets
5
+ module Compressors
6
+ # Base class for stylesheet compressors
7
+ #
8
+ # @since 0.1.0
9
+ # @api private
10
+ class Stylesheet < Abstract
11
+ # Factory for Stylesheet compressors.
12
+ #
13
+ # It loads a compressor for the given name.
14
+ #
15
+ # @param engine_name [Symbol,String,NilClass,#compress] the name of the
16
+ # engine to load or an instance of an engine
17
+ #
18
+ # @return [Lotus::Assets::Compressors::Abstract] returns a concrete
19
+ # implementation of a compressor
20
+ #
21
+ # @raise [Lotus::Assets::Compressors::UnknownCompressorError] when the
22
+ # given name refers to an unknown compressor engine
23
+ #
24
+ # @since 0.1.0
25
+ # @api private
26
+ #
27
+ # @see Lotus::Assets::Compressors::Abstract#for
28
+ # @see Lotus::Assets::Configuration#stylesheet_compressor
29
+ #
30
+ # @example Basic Usage
31
+ # require 'lotus/assets'
32
+ # require 'lotus/assets/compressors/stylesheet'
33
+ #
34
+ # Lotus::Assets::Compressors::Stylesheet.for(:sass)
35
+ # # => #<Lotus::Assets::Compressors::SassStylesheet:0x007f8674cc4a50 ...>
36
+ #
37
+ # @example Null Compressor
38
+ # require 'lotus/assets'
39
+ # require 'lotus/assets/compressors/stylesheet'
40
+ #
41
+ # Lotus::Assets::Compressors::Stylesheet.for(nil)
42
+ # # => #<Lotus::Assets::Compressors::NullCompressor:0x007fa32a314258>
43
+ #
44
+ # @example Custom Compressor
45
+ # require 'lotus/assets'
46
+ # require 'lotus/assets/compressors/stylesheet'
47
+ #
48
+ # class CustomStylesheetCompressor
49
+ # def compress(filename)
50
+ # # ...
51
+ # end
52
+ # end
53
+ #
54
+ # Lotus::Assets::Compressors::Stylesheet.for(CustomStylesheetCompressor.new)
55
+ # # => #<CustomStylesheetCompressor:0x007fa32a2cdf10>
56
+ #
57
+ # @example Third Party Compressor
58
+ # require 'lotus/assets'
59
+ # require 'lotus/assets/compressors/stylesheet'
60
+ # require 'lotus/foo/compressor' # third party gem
61
+ #
62
+ # Lotus::Assets::Compressors::Stylesheet.for(:foo)
63
+ # # => #<Lotus::Assets::Compressors::FooStylesheet:0x007fa3dd9ed968>
64
+ #
65
+ # @example Unknown Engine
66
+ # require 'lotus/assets'
67
+ # require 'lotus/assets/compressors/stylesheet'
68
+ #
69
+ # Lotus::Assets::Compressors::Stylesheet.for(:wat)
70
+ # # => Lotus::Assets::Compressors::UnknownCompressorError: Unknown Stylesheet compressor: :wat
71
+ def self.for(engine_name)
72
+ super
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,25 @@
1
+ require 'lotus/assets/compressors/javascript'
2
+ require 'uglifier'
3
+
4
+ module Lotus
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 'lotus/assets/compressors/javascript'
2
+ require 'yui/compressor'
3
+
4
+ module Lotus
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 'lotus/assets/compressors/stylesheet'
2
+ require 'yui/compressor'
3
+
4
+ module Lotus
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 'lotus/utils/load_paths'
2
+
3
+ module Lotus
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>Lotus::Assets</tt>
11
+ # instances.
12
+ #
13
+ # @since 0.1.0
14
+ # @api private
15
+ #
16
+ # @see Lotus::Assets.duplicate
17
+ # @see http://www.rubydoc.info/gems/lotus-utils/Lotus/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
+ Lotus::Assets.configuration.sources << @paths
38
+ end
39
+
40
+ # @since 0.1.0
41
+ # @api private
42
+ def sync_duplicated_frameworks
43
+ Lotus::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 Lotus
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>Lotus::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>Lotus::Assets::MissingDigestManifestError</tt>.
40
+ #
41
+ # @since 0.1.0
42
+ # @api private
43
+ #
44
+ # @see Lotus::Assets::Configuration#manifest
45
+ # @see Lotus::Assets::Configuration#manifest_path
46
+ # @see Lotus::Assets::Configuration#digest
47
+ class NullDigestManifest < Utils::BasicObject
48
+ # Return a new instance
49
+ #
50
+ # @param configuration [Lotus::Assets::Configuration]
51
+ #
52
+ # @return [Lotus::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 [Lotus::Assets::MissingDigestManifestError]
61
+ #
62
+ # @since 0.1.0
63
+ # @api private
64
+ def method_missing(*)
65
+ ::Kernel.raise(
66
+ ::Lotus::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 [Lotus::Assets::Config::Manifest] a new instance
82
+ #
83
+ # @since 0.1.0
84
+ # @api private
85
+ #
86
+ # @see Lotus::Assets::Configuration#manifest
87
+ # @see Lotus::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 [Lotus::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 Lotus::Assets::MissingDigestAssetError.new(asset, @manifest_path)
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,77 @@
1
+ require 'lotus/utils/load_paths'
2
+
3
+ module Lotus
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 Lotus::Assets.duplicate
16
+ # @see http://www.rubydoc.info/gems/lotus-utils/Lotus/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