sprockets 2.6.0 → 4.2.2

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 (100) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +118 -0
  3. data/{LICENSE → MIT-LICENSE} +2 -2
  4. data/README.md +541 -289
  5. data/bin/sprockets +20 -7
  6. data/lib/rake/sprocketstask.rb +34 -17
  7. data/lib/sprockets/add_source_map_comment_to_asset_processor.rb +60 -0
  8. data/lib/sprockets/asset.rb +158 -210
  9. data/lib/sprockets/autoload/babel.rb +8 -0
  10. data/lib/sprockets/autoload/closure.rb +8 -0
  11. data/lib/sprockets/autoload/coffee_script.rb +8 -0
  12. data/lib/sprockets/autoload/eco.rb +8 -0
  13. data/lib/sprockets/autoload/ejs.rb +8 -0
  14. data/lib/sprockets/autoload/jsminc.rb +8 -0
  15. data/lib/sprockets/autoload/sass.rb +8 -0
  16. data/lib/sprockets/autoload/sassc.rb +8 -0
  17. data/lib/sprockets/autoload/uglifier.rb +8 -0
  18. data/lib/sprockets/autoload/yui.rb +8 -0
  19. data/lib/sprockets/autoload/zopfli.rb +7 -0
  20. data/lib/sprockets/autoload.rb +16 -0
  21. data/lib/sprockets/babel_processor.rb +66 -0
  22. data/lib/sprockets/base.rb +89 -378
  23. data/lib/sprockets/bower.rb +61 -0
  24. data/lib/sprockets/bundle.rb +105 -0
  25. data/lib/sprockets/cache/file_store.rb +190 -14
  26. data/lib/sprockets/cache/memory_store.rb +84 -0
  27. data/lib/sprockets/cache/null_store.rb +54 -0
  28. data/lib/sprockets/cache.rb +271 -0
  29. data/lib/sprockets/cached_environment.rb +64 -0
  30. data/lib/sprockets/closure_compressor.rb +48 -0
  31. data/lib/sprockets/coffee_script_processor.rb +39 -0
  32. data/lib/sprockets/compressing.rb +134 -0
  33. data/lib/sprockets/configuration.rb +79 -0
  34. data/lib/sprockets/context.rb +166 -150
  35. data/lib/sprockets/dependencies.rb +74 -0
  36. data/lib/sprockets/digest_utils.rb +197 -0
  37. data/lib/sprockets/directive_processor.rb +241 -215
  38. data/lib/sprockets/eco_processor.rb +33 -0
  39. data/lib/sprockets/ejs_processor.rb +32 -0
  40. data/lib/sprockets/encoding_utils.rb +261 -0
  41. data/lib/sprockets/environment.rb +23 -64
  42. data/lib/sprockets/erb_processor.rb +43 -0
  43. data/lib/sprockets/errors.rb +5 -13
  44. data/lib/sprockets/exporters/base.rb +71 -0
  45. data/lib/sprockets/exporters/file_exporter.rb +24 -0
  46. data/lib/sprockets/exporters/zlib_exporter.rb +33 -0
  47. data/lib/sprockets/exporters/zopfli_exporter.rb +14 -0
  48. data/lib/sprockets/exporting.rb +73 -0
  49. data/lib/sprockets/file_reader.rb +16 -0
  50. data/lib/sprockets/http_utils.rb +135 -0
  51. data/lib/sprockets/jsminc_compressor.rb +32 -0
  52. data/lib/sprockets/jst_processor.rb +36 -19
  53. data/lib/sprockets/loader.rb +347 -0
  54. data/lib/sprockets/manifest.rb +228 -112
  55. data/lib/sprockets/manifest_utils.rb +48 -0
  56. data/lib/sprockets/mime.rb +78 -31
  57. data/lib/sprockets/npm.rb +52 -0
  58. data/lib/sprockets/path_dependency_utils.rb +77 -0
  59. data/lib/sprockets/path_digest_utils.rb +48 -0
  60. data/lib/sprockets/path_utils.rb +367 -0
  61. data/lib/sprockets/paths.rb +43 -19
  62. data/lib/sprockets/preprocessors/default_source_map.rb +49 -0
  63. data/lib/sprockets/processing.rb +146 -164
  64. data/lib/sprockets/processor_utils.rb +170 -0
  65. data/lib/sprockets/resolve.rb +295 -0
  66. data/lib/sprockets/sass_cache_store.rb +20 -15
  67. data/lib/sprockets/sass_compressor.rb +55 -10
  68. data/lib/sprockets/sass_functions.rb +3 -70
  69. data/lib/sprockets/sass_importer.rb +3 -29
  70. data/lib/sprockets/sass_processor.rb +313 -0
  71. data/lib/sprockets/sassc_compressor.rb +56 -0
  72. data/lib/sprockets/sassc_processor.rb +297 -0
  73. data/lib/sprockets/server.rb +159 -91
  74. data/lib/sprockets/source_map_processor.rb +66 -0
  75. data/lib/sprockets/source_map_utils.rb +483 -0
  76. data/lib/sprockets/transformers.rb +173 -0
  77. data/lib/sprockets/uglifier_compressor.rb +66 -0
  78. data/lib/sprockets/unloaded_asset.rb +139 -0
  79. data/lib/sprockets/uri_tar.rb +99 -0
  80. data/lib/sprockets/uri_utils.rb +194 -0
  81. data/lib/sprockets/utils/gzip.rb +99 -0
  82. data/lib/sprockets/utils.rb +193 -52
  83. data/lib/sprockets/version.rb +2 -1
  84. data/lib/sprockets/yui_compressor.rb +56 -0
  85. data/lib/sprockets.rb +217 -75
  86. metadata +272 -117
  87. data/lib/sprockets/asset_attributes.rb +0 -131
  88. data/lib/sprockets/bundled_asset.rb +0 -80
  89. data/lib/sprockets/caching.rb +0 -96
  90. data/lib/sprockets/charset_normalizer.rb +0 -41
  91. data/lib/sprockets/eco_template.rb +0 -38
  92. data/lib/sprockets/ejs_template.rb +0 -37
  93. data/lib/sprockets/engines.rb +0 -74
  94. data/lib/sprockets/index.rb +0 -99
  95. data/lib/sprockets/processed_asset.rb +0 -152
  96. data/lib/sprockets/processor.rb +0 -32
  97. data/lib/sprockets/safety_colons.rb +0 -28
  98. data/lib/sprockets/sass_template.rb +0 -60
  99. data/lib/sprockets/scss_template.rb +0 -13
  100. data/lib/sprockets/static_asset.rb +0 -58
data/bin/sprockets CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ $VERBOSE = nil
2
3
 
3
4
  require 'sprockets'
4
5
  require 'optparse'
@@ -11,7 +12,7 @@ unless ARGV.delete("--noenv")
11
12
  end
12
13
  end
13
14
 
14
- filenames = []
15
+ paths = []
15
16
  environment = Sprockets::Environment.new(Dir.pwd)
16
17
  manifest = nil
17
18
 
@@ -40,9 +41,21 @@ OptionParser.new do |opts|
40
41
  manifest = Sprockets::Manifest.new(environment, directory)
41
42
  end
42
43
 
44
+ opts.on("--css-compressor=COMPRESSOR", "Use CSS compressor") do |compressor|
45
+ environment.css_compressor = compressor.to_sym
46
+ end
47
+
48
+ opts.on("--js-compressor=COMPRESSOR", "Use JavaScript compressor") do |compressor|
49
+ environment.js_compressor = compressor.to_sym
50
+ end
51
+
43
52
  opts.on("--noenv", "Disables .sprocketsrc file") do
44
53
  end
45
54
 
55
+ opts.on("--cache=DIRECTORY", "Enables the FileStore cache using the specified directory") do |directory|
56
+ environment.cache = Sprockets::Cache::FileStore.new(directory)
57
+ end
58
+
46
59
  opts.on_tail("-h", "--help", "Shows this help message") do
47
60
  opts.show_usage
48
61
  end
@@ -55,8 +68,8 @@ OptionParser.new do |opts|
55
68
  opts.show_usage if ARGV.empty?
56
69
 
57
70
  begin
58
- opts.order(ARGV) do |filename|
59
- filenames << File.expand_path(filename)
71
+ opts.order(ARGV) do |path|
72
+ paths << path
60
73
  end
61
74
  rescue OptionParser::ParseError => e
62
75
  opts.warn e.message
@@ -66,14 +79,14 @@ end
66
79
 
67
80
  if environment.paths.empty?
68
81
  warn "No load paths given"
69
- warn "Usage: sprockets -Ijavascripts/ filename"
82
+ warn "Usage: sprockets -Ijavascripts/ path"
70
83
  exit 1
71
84
  end
72
85
 
73
86
  if manifest
74
- manifest.compile(filenames)
75
- elsif filenames.length == 1
76
- puts environment.find_asset(filenames.first).to_s
87
+ manifest.compile(paths)
88
+ elsif paths.length == 1
89
+ puts environment.find_asset(paths.first).to_s
77
90
  else
78
91
  warn "Only one file can be compiled to stdout at a time"
79
92
  exit 1
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'rake'
2
3
  require 'rake/tasklib'
3
4
 
@@ -37,6 +38,25 @@ module Rake
37
38
  end
38
39
  attr_writer :environment
39
40
 
41
+ # Returns cached cached environment
42
+ def cached
43
+ @cached ||= environment.cached if environment
44
+ end
45
+ alias_method :index, :cached
46
+
47
+ # `Manifest` instance used for already compiled assets.
48
+ #
49
+ # Will be created by default if an environment and output
50
+ # directory are given
51
+ def manifest
52
+ if !@manifest.is_a?(Sprockets::Manifest) && @manifest.respond_to?(:call)
53
+ @manifest = @manifest.call
54
+ else
55
+ @manifest
56
+ end
57
+ end
58
+ attr_writer :manifest
59
+
40
60
  # Directory to write compiled assets too. As well as the manifest file.
41
61
  #
42
62
  # t.output = "./public/assets"
@@ -49,9 +69,12 @@ module Rake
49
69
  #
50
70
  attr_accessor :assets
51
71
 
52
- # Number of old assets to keep.
72
+ # Minimum number of old assets to keep. See Sprockets::Manifest#clean for more information.
53
73
  attr_accessor :keep
54
74
 
75
+ # Assets created within this age will be kept. See Sprockets::Manifest#clean for more information.
76
+ attr_accessor :age
77
+
55
78
  # Logger to use during rake tasks. Defaults to using stderr.
56
79
  #
57
80
  # t.logger = Logger.new($stdout)
@@ -79,9 +102,11 @@ module Rake
79
102
  def initialize(name = :assets)
80
103
  @name = name
81
104
  @environment = lambda { Sprockets::Environment.new(Dir.pwd) }
105
+ @manifest = lambda { Sprockets::Manifest.new(cached, output) }
82
106
  @logger = Logger.new($stderr)
83
107
  @logger.level = Logger::INFO
84
108
  @keep = 2
109
+ @age = 3600
85
110
 
86
111
  yield self if block_given?
87
112
 
@@ -104,37 +129,29 @@ module Rake
104
129
  end
105
130
  end
106
131
 
107
- task :clobber => ["clobber_#{name}"]
132
+ task clobber: ["clobber_#{name}"]
108
133
 
109
134
  desc name == :assets ? "Clean old assets" : "Clean old #{name} assets"
110
135
  task "clean_#{name}" do
111
136
  with_logger do
112
- manifest.clean(keep)
137
+ manifest.clean(keep, age)
113
138
  end
114
139
  end
115
140
 
116
- task :clean => ["clean_#{name}"]
141
+ task clean: ["clean_#{name}"]
117
142
  end
118
143
 
119
144
  private
120
- # Returns cached indexed environment
121
- def index
122
- @index ||= environment.index
123
- end
124
-
125
- # Returns manifest for tasks
126
- def manifest
127
- @manifest ||= Sprockets::Manifest.new(index, output)
128
- end
129
-
130
145
  # Sub out environment logger with our rake task logger that
131
146
  # writes to stderr.
132
147
  def with_logger
133
- old_logger = index.logger
134
- index.logger = @logger
148
+ if env = manifest.environment
149
+ old_logger = env.logger
150
+ env.logger = @logger
151
+ end
135
152
  yield
136
153
  ensure
137
- index.logger = old_logger
154
+ env.logger = old_logger if env
138
155
  end
139
156
  end
140
157
  end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+ require 'sprockets/uri_utils'
3
+ require 'sprockets/path_utils'
4
+
5
+ module Sprockets
6
+ # This is a processor designed to add a source map "comment"
7
+ # to the bottom of a css or JS file that is serving a source
8
+ # map. An example of a comment might look like this
9
+ #
10
+ # //# application.js-80af0efcc960fc2ac93eda2f7b12e3db40ab360bf6ea269ceed3bea3678326f9.map
11
+ #
12
+ # As an asset is built it gets source map information added
13
+ # to the `asset.to_hash[:metadata][:map]` key. This contains all the
14
+ # information that is needed to build a source map file.
15
+ #
16
+ # To add this comment we must have an asset we can link to.
17
+ # To do this we ensure that the original asset is loaded, then
18
+ # we use a use a special mime type. For example `application/js-sourcemap+json`
19
+ # for a JS source map.
20
+ #
21
+ # This will trigger a new asset to be loaded and generated by the
22
+ # `SourceMapProcessor` processor.
23
+ #
24
+ # Finally once we have that file, we can generate a link to it
25
+ # with it's full fingerprint. This is done and then
26
+ # added to the original asset as a comment at the bottom.
27
+ #
28
+ class AddSourceMapCommentToAssetProcessor
29
+ def self.call(input)
30
+
31
+ case input[:content_type]
32
+ when "application/javascript"
33
+ comment = "\n//# sourceMappingURL=%s"
34
+ map_type = "application/js-sourcemap+json"
35
+ when "text/css"
36
+ comment = "\n/*# sourceMappingURL=%s */"
37
+ map_type = "application/css-sourcemap+json"
38
+ else
39
+ fail input[:content_type]
40
+ end
41
+
42
+ env = input[:environment]
43
+
44
+ uri, _ = env.resolve!(input[:filename], accept: input[:content_type])
45
+ asset = env.load(uri)
46
+
47
+ uri, _ = env.resolve!(input[:filename], accept: map_type)
48
+ map = env.load(uri)
49
+
50
+ uri, params = URIUtils.parse_asset_uri(input[:uri])
51
+ uri = env.expand_from_root(params[:index_alias]) if params[:index_alias]
52
+ path = PathUtils.relative_path_from(PathUtils.split_subpath(input[:load_path], uri), map.digest_path)
53
+
54
+ asset.metadata.merge(
55
+ data: asset.source + (comment % path) + "\n",
56
+ links: asset.links + [asset.uri, map.uri]
57
+ )
58
+ end
59
+ end
60
+ end
@@ -1,264 +1,212 @@
1
- require 'time'
2
- require 'set'
1
+ # frozen_string_literal: true
2
+ require 'fileutils'
3
+ require 'sprockets/digest_utils'
3
4
 
4
5
  module Sprockets
5
- # `Asset` is the base class for `BundledAsset` and `StaticAsset`.
6
6
  class Asset
7
- # Internal initializer to load `Asset` from serialized `Hash`.
8
- def self.from_hash(environment, hash)
9
- return unless hash.is_a?(Hash)
7
+ attr_reader :logical_path
10
8
 
11
- klass = case hash['class']
12
- when 'BundledAsset'
13
- BundledAsset
14
- when 'ProcessedAsset'
15
- ProcessedAsset
16
- when 'StaticAsset'
17
- StaticAsset
18
- else
19
- nil
20
- end
21
-
22
- if klass
23
- asset = klass.allocate
24
- asset.init_with(environment, hash)
25
- asset
26
- end
27
- rescue UnserializeError
28
- nil
29
- end
30
-
31
- attr_reader :logical_path, :pathname
32
- attr_reader :content_type, :mtime, :length, :digest
33
- alias_method :bytesize, :length
34
-
35
- def initialize(environment, logical_path, pathname)
36
- raise ArgumentError, "Asset logical path has no extension: #{logical_path}" if File.extname(logical_path) == ""
37
-
38
- @root = environment.root
39
- @logical_path = logical_path.to_s
40
- @pathname = Pathname.new(pathname)
41
- @content_type = environment.content_type_of(pathname)
42
- @mtime = environment.stat(pathname).mtime
43
- @length = environment.stat(pathname).size
44
- @digest = environment.file_digest(pathname).hexdigest
9
+ # Private: Initialize Asset wrapper from attributes Hash.
10
+ #
11
+ # Asset wrappers should not be initialized directly, only
12
+ # Environment#find_asset should vend them.
13
+ #
14
+ # attributes - Hash of ivars
15
+ #
16
+ # Returns Asset.
17
+ def initialize(attributes = {})
18
+ @attributes = attributes
19
+ @content_type = attributes[:content_type]
20
+ @filename = attributes[:filename]
21
+ @id = attributes[:id]
22
+ @load_path = attributes[:load_path]
23
+ @logical_path = attributes[:logical_path]
24
+ @metadata = attributes[:metadata]
25
+ @name = attributes[:name]
26
+ @source = attributes[:source]
27
+ @uri = attributes[:uri]
28
+ end
29
+
30
+ # Internal: Return all internal instance variables as a hash.
31
+ #
32
+ # Returns a Hash.
33
+ def to_hash
34
+ @attributes
45
35
  end
46
36
 
47
- # Initialize `Asset` from serialized `Hash`.
48
- def init_with(environment, coder)
49
- @root = environment.root
50
-
51
- @logical_path = coder['logical_path']
52
- @content_type = coder['content_type']
53
- @digest = coder['digest']
54
-
55
- if pathname = coder['pathname']
56
- # Expand `$root` placeholder and wrapper string in a `Pathname`
57
- @pathname = Pathname.new(expand_root_path(pathname))
58
- end
37
+ # Public: Metadata accumulated from pipeline process.
38
+ #
39
+ # The API status of the keys is dependent on the pipeline processors
40
+ # itself. So some values maybe considered public and others internal.
41
+ # See the pipeline processor documentation itself.
42
+ #
43
+ # Returns Hash.
44
+ attr_reader :metadata
59
45
 
60
- if mtime = coder['mtime']
61
- # Parse time string
62
- @mtime = Time.parse(mtime)
63
- end
46
+ # Public: Returns String path of asset.
47
+ attr_reader :filename
64
48
 
65
- if length = coder['length']
66
- # Convert length to an `Integer`
67
- @length = Integer(length)
68
- end
69
- end
49
+ # Internal: Unique asset object ID.
50
+ #
51
+ # Returns a String.
52
+ attr_reader :id
70
53
 
71
- # Copy serialized attributes to the coder object
72
- def encode_with(coder)
73
- coder['class'] = self.class.name.sub(/Sprockets::/, '')
74
- coder['logical_path'] = logical_path
75
- coder['pathname'] = relativize_root_path(pathname).to_s
76
- coder['content_type'] = content_type
77
- coder['mtime'] = mtime.iso8601
78
- coder['length'] = length
79
- coder['digest'] = digest
80
- end
54
+ # Public: Internal URI to lookup asset by.
55
+ #
56
+ # NOT a publicly accessible URL.
57
+ #
58
+ # Returns URI.
59
+ attr_reader :uri
81
60
 
82
- # Return logical path with digest spliced in.
61
+ # Public: Return logical path with digest spliced in.
83
62
  #
84
63
  # "foo/bar-37b51d194a7513e45b56f6524f2d51f2.js"
85
64
  #
65
+ # Returns String.
86
66
  def digest_path
87
- logical_path.sub(/\.(\w+)$/) { |ext| "-#{digest}#{ext}" }
67
+ if DigestUtils.already_digested?(@name)
68
+ logical_path
69
+ else
70
+ logical_path.sub(/\.(\w+)$/) { |ext| "-#{etag}#{ext}" }
71
+ end
88
72
  end
89
73
 
90
- # Return an `Array` of `Asset` files that are declared dependencies.
91
- def dependencies
92
- []
74
+ # Public: Return load path + logical path with digest spliced in.
75
+ #
76
+ # Returns String.
77
+ def full_digest_path
78
+ File.join(@load_path, digest_path)
93
79
  end
94
80
 
95
- # Expand asset into an `Array` of parts.
81
+ # Public: Returns String MIME type of asset. Returns nil if type is unknown.
82
+ attr_reader :content_type
83
+
84
+ # Public: Get all externally linked asset filenames from asset.
96
85
  #
97
- # Appending all of an assets body parts together should give you
98
- # the asset's contents as a whole.
86
+ # All linked assets should be compiled anytime this asset is.
99
87
  #
100
- # This allows you to link to individual files for debugging
101
- # purposes.
102
- def to_a
103
- [self]
88
+ # Returns Set of String asset URIs.
89
+ def links
90
+ metadata[:links] || Set.new
104
91
  end
105
92
 
106
- # `body` is aliased to source by default if it can't have any dependencies.
107
- def body
108
- source
93
+ # Public: Return `String` of concatenated source.
94
+ #
95
+ # Returns String.
96
+ def source
97
+ if @source
98
+ @source
99
+ else
100
+ # File is read everytime to avoid memory bloat of large binary files
101
+ File.binread(filename)
102
+ end
109
103
  end
110
104
 
111
- # Return `String` of concatenated source.
105
+ # Public: Alias for #source.
106
+ #
107
+ # Returns String.
112
108
  def to_s
113
109
  source
114
110
  end
115
111
 
116
- # Add enumerator to allow `Asset` instances to be used as Rack
117
- # compatible body objects.
118
- def each
119
- yield to_s
112
+ # Public: Get charset of source.
113
+ #
114
+ # Returns a String charset name or nil if binary.
115
+ def charset
116
+ metadata[:charset]
120
117
  end
121
118
 
122
- # Checks if Asset is fresh by comparing the actual mtime and
123
- # digest to the inmemory model.
124
- #
125
- # Used to test if cached models need to be rebuilt.
126
- def fresh?(environment)
127
- # Check current mtime and digest
128
- dependency_fresh?(environment, self)
119
+ # Public: Returns Integer length of source.
120
+ def length
121
+ metadata[:length]
129
122
  end
123
+ alias_method :bytesize, :length
130
124
 
131
- # Checks if Asset is stale by comparing the actual mtime and
132
- # digest to the inmemory model.
133
- #
134
- # Subclass must override `fresh?` or `stale?`.
135
- def stale?(environment)
136
- !fresh?(environment)
125
+ # Public: Returns String byte digest of source.
126
+ def digest
127
+ metadata[:digest]
137
128
  end
138
129
 
139
- # Save asset to disk.
140
- def write_to(filename, options = {})
141
- # Gzip contents if filename has '.gz'
142
- options[:compress] ||= File.extname(filename) == '.gz'
130
+ # Private: Return the version of the environment where the asset was generated.
131
+ def environment_version
132
+ metadata[:environment_version]
133
+ end
143
134
 
144
- FileUtils.mkdir_p File.dirname(filename)
135
+ # Public: Returns String hexdigest of source.
136
+ def hexdigest
137
+ DigestUtils.pack_hexdigest(digest)
138
+ end
139
+
140
+ # Public: ETag String of Asset.
141
+ def etag
142
+ version = environment_version
145
143
 
146
- File.open("#{filename}+", 'wb') do |f|
147
- if options[:compress]
148
- # Run contents through `Zlib`
149
- gz = Zlib::GzipWriter.new(f, Zlib::BEST_COMPRESSION)
150
- gz.mtime = mtime.to_i
151
- gz.write to_s
152
- gz.close
153
- else
154
- # Write out as is
155
- f.write to_s
156
- f.close
157
- end
144
+ if version && version != ""
145
+ DigestUtils.hexdigest(version + digest)
146
+ else
147
+ DigestUtils.pack_hexdigest(digest)
158
148
  end
149
+ end
150
+
151
+ # Public: Returns String base64 digest of source.
152
+ def base64digest
153
+ DigestUtils.pack_base64digest(digest)
154
+ end
155
+
156
+ # Public: A "named information" URL for subresource integrity.
157
+ def integrity
158
+ DigestUtils.integrity_uri(digest)
159
+ end
160
+
161
+ # Public: Add enumerator to allow `Asset` instances to be used as Rack
162
+ # compatible body objects.
163
+ #
164
+ # block
165
+ # part - String body chunk
166
+ #
167
+ # Returns nothing.
168
+ def each
169
+ yield to_s
170
+ end
159
171
 
160
- # Atomic write
161
- FileUtils.mv("#{filename}+", filename)
172
+ # Deprecated: Save asset to disk.
173
+ #
174
+ # filename - String target
175
+ #
176
+ # Returns nothing.
177
+ def write_to(filename)
178
+ FileUtils.mkdir_p File.dirname(filename)
162
179
 
163
- # Set mtime correctly
164
- File.utime(mtime, mtime, filename)
180
+ PathUtils.atomic_write(filename) do |f|
181
+ f.write source
182
+ end
165
183
 
166
184
  nil
167
- ensure
168
- # Ensure tmp file gets cleaned up
169
- FileUtils.rm("#{filename}+") if File.exist?("#{filename}+")
170
185
  end
171
186
 
172
- # Pretty inspect
187
+ # Public: Pretty inspect
188
+ #
189
+ # Returns String.
173
190
  def inspect
174
- "#<#{self.class}:0x#{object_id.to_s(16)} " +
175
- "pathname=#{pathname.to_s.inspect}, " +
176
- "mtime=#{mtime.inspect}, " +
177
- "digest=#{digest.inspect}" +
178
- ">"
191
+ "#<#{self.class}:#{object_id.to_s(16)} #{uri.inspect}>"
179
192
  end
180
193
 
194
+ # Public: Implements Object#hash so Assets can be used as a Hash key or
195
+ # in a Set.
196
+ #
197
+ # Returns Integer hash of the id.
181
198
  def hash
182
- digest.hash
199
+ id.hash
183
200
  end
184
201
 
185
- # Assets are equal if they share the same path, mtime and digest.
202
+ # Public: Compare assets.
203
+ #
204
+ # Assets are equal if they share the same path and digest.
205
+ #
206
+ # Returns true or false.
186
207
  def eql?(other)
187
- other.class == self.class &&
188
- other.logical_path == self.logical_path &&
189
- other.mtime.to_i == self.mtime.to_i &&
190
- other.digest == self.digest
208
+ self.class == other.class && self.id == other.id
191
209
  end
192
210
  alias_method :==, :eql?
193
-
194
- protected
195
- # Internal: String paths that are marked as dependencies after processing.
196
- #
197
- # Default to an empty `Array`.
198
- def dependency_paths
199
- @dependency_paths ||= []
200
- end
201
-
202
- # Internal: `ProccessedAsset`s that are required after processing.
203
- #
204
- # Default to an empty `Array`.
205
- def required_assets
206
- @required_assets ||= []
207
- end
208
-
209
- # Get pathname with its root stripped.
210
- def relative_pathname
211
- @relative_pathname ||= Pathname.new(relativize_root_path(pathname))
212
- end
213
-
214
- # Replace `$root` placeholder with actual environment root.
215
- def expand_root_path(path)
216
- path.to_s.sub(/^\$root/, @root)
217
- end
218
-
219
- # Replace actual environment root with `$root` placeholder.
220
- def relativize_root_path(path)
221
- path.to_s.sub(/^#{Regexp.escape(@root)}/, '$root')
222
- end
223
-
224
- # Check if dependency is fresh.
225
- #
226
- # `dep` is a `Hash` with `path`, `mtime` and `hexdigest` keys.
227
- #
228
- # A `Hash` is used rather than other `Asset` object because we
229
- # want to test non-asset files and directories.
230
- def dependency_fresh?(environment, dep)
231
- path, mtime, hexdigest = dep.pathname.to_s, dep.mtime, dep.digest
232
-
233
- stat = environment.stat(path)
234
-
235
- # If path no longer exists, its definitely stale.
236
- if stat.nil?
237
- return false
238
- end
239
-
240
- # Compare dependency mime to the actual mtime. If the
241
- # dependency mtime is newer than the actual mtime, the file
242
- # hasn't changed since we created this `Asset` instance.
243
- #
244
- # However, if the mtime is newer it doesn't mean the asset is
245
- # stale. Many deployment environments may recopy or recheckout
246
- # assets on each deploy. In this case the mtime would be the
247
- # time of deploy rather than modified time.
248
- if mtime >= stat.mtime
249
- return true
250
- end
251
-
252
- digest = environment.file_digest(path)
253
-
254
- # If the mtime is newer, do a full digest comparsion. Return
255
- # fresh if the digests match.
256
- if hexdigest == digest.hexdigest
257
- return true
258
- end
259
-
260
- # Otherwise, its stale.
261
- false
262
- end
263
211
  end
264
212
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+ require 'babel/transpiler'
3
+
4
+ module Sprockets
5
+ module Autoload
6
+ Babel = ::Babel
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+ require 'closure-compiler'
3
+
4
+ module Sprockets
5
+ module Autoload
6
+ Closure = ::Closure
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+ require 'coffee_script'
3
+
4
+ module Sprockets
5
+ module Autoload
6
+ CoffeeScript = ::CoffeeScript
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+ require 'eco'
3
+
4
+ module Sprockets
5
+ module Autoload
6
+ Eco = ::Eco
7
+ end
8
+ end