lotus-assets 0.0.0 → 0.1.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.
@@ -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