class Sprockets::Asset

`Asset` is the base class for `BundledAsset` and `StaticAsset`.

Attributes

bytesize[R]
content_type[R]
digest[R]
length[R]
logical_path[R]
mtime[R]
pathname[R]

Public Class Methods

from_hash(environment, hash) click to toggle source

Internal initializer to load `Asset` from serialized `Hash`.

# File lib/sprockets/asset.rb, line 8
def self.from_hash(environment, hash)
  return unless hash.is_a?(Hash)

  klass = case hash['class']
    when 'BundledAsset'
      BundledAsset
    when 'ProcessedAsset'
      ProcessedAsset
    when 'StaticAsset'
      StaticAsset
    else
      nil
    end

  if klass
    asset = klass.allocate
    asset.init_with(environment, hash)
    asset
  end
rescue UnserializeError
  nil
end
new(environment, logical_path, pathname) click to toggle source
# File lib/sprockets/asset.rb, line 35
def initialize(environment, logical_path, pathname)
  raise ArgumentError, "Asset logical path has no extension: #{logical_path}" if File.extname(logical_path) == ""

  @root         = environment.root
  @logical_path = logical_path.to_s
  @pathname     = Pathname.new(pathname)
  @content_type = environment.content_type_of(pathname)
  @mtime        = environment.stat(pathname).mtime
  @length       = environment.stat(pathname).size
  @digest       = environment.file_digest(pathname).hexdigest
end

Public Instance Methods

==(other)
Alias for: eql?
body() click to toggle source

`body` is aliased to source by default if it can't have any dependencies.

# File lib/sprockets/asset.rb, line 107
def body
  source
end
dependencies() click to toggle source

Return an `Array` of `Asset` files that are declared dependencies.

# File lib/sprockets/asset.rb, line 91
def dependencies
  []
end
digest_path() click to toggle source

Return logical path with digest spliced in.

"foo/bar-37b51d194a7513e45b56f6524f2d51f2.js"
# File lib/sprockets/asset.rb, line 86
def digest_path
  logical_path.sub(/\.(\w+)$/) { |ext| "-#{digest}#{ext}" }
end
each() { |to_s| ... } click to toggle source

Add enumerator to allow `Asset` instances to be used as Rack compatible body objects.

# File lib/sprockets/asset.rb, line 118
def each
  yield to_s
end
encode_with(coder) click to toggle source

Copy serialized attributes to the coder object

# File lib/sprockets/asset.rb, line 72
def encode_with(coder)
  coder['class']        = self.class.name.sub(/Sprockets::/, '')
  coder['logical_path'] = logical_path
  coder['pathname']     = relativize_root_path(pathname).to_s
  coder['content_type'] = content_type
  coder['mtime']        = mtime.iso8601
  coder['length']       = length
  coder['digest']       = digest
end
eql?(other) click to toggle source

Assets are equal if they share the same path, mtime and digest.

# File lib/sprockets/asset.rb, line 185
def eql?(other)
  other.class == self.class &&
    other.logical_path == self.logical_path &&
    other.mtime.to_i == self.mtime.to_i &&
    other.digest == self.digest
end
Also aliased as: ==
fresh?(environment) click to toggle source

Checks if Asset is fresh by comparing the actual mtime and digest to the inmemory model.

Used to test if cached models need to be rebuilt.

# File lib/sprockets/asset.rb, line 126
def fresh?(environment)
  # Check current mtime and digest
  dependency_fresh?(environment, self)
end
hash() click to toggle source
# File lib/sprockets/asset.rb, line 180
def hash
  digest.hash
end
init_with(environment, coder) click to toggle source

Initialize `Asset` from serialized `Hash`.

# File lib/sprockets/asset.rb, line 48
def init_with(environment, coder)
  @root = environment.root

  @logical_path = coder['logical_path']
  @content_type = coder['content_type']
  @digest       = coder['digest']

  if pathname = coder['pathname']
    # Expand `$root` placeholder and wrapper string in a `Pathname`
    @pathname = Pathname.new(expand_root_path(pathname))
  end

  if mtime = coder['mtime']
    # Parse time string
    @mtime = Time.parse(mtime)
  end

  if length = coder['length']
    # Convert length to an `Integer`
    @length = Integer(length)
  end
end
inspect() click to toggle source

Pretty inspect

# File lib/sprockets/asset.rb, line 172
def inspect
  "#<#{self.class}:0x#{object_id.to_s(16)} " +
    "pathname=#{pathname.to_s.inspect}, " +
    "mtime=#{mtime.inspect}, " +
    "digest=#{digest.inspect}" +
    ">"
end
stale?(environment) click to toggle source

Checks if Asset is stale by comparing the actual mtime and digest to the inmemory model.

Subclass must override `fresh?` or `stale?`.

# File lib/sprockets/asset.rb, line 135
def stale?(environment)
  !fresh?(environment)
end
to_a() click to toggle source

Expand asset into an `Array` of parts.

Appending all of an assets body parts together should give you the asset's contents as a whole.

This allows you to link to individual files for debugging purposes.

# File lib/sprockets/asset.rb, line 102
def to_a
  [self]
end
to_s() click to toggle source

Return `String` of concatenated source.

# File lib/sprockets/asset.rb, line 112
def to_s
  source
end
write_to(filename, options = {}) click to toggle source

Save asset to disk.

# File lib/sprockets/asset.rb, line 140
def write_to(filename, options = {})
  # Gzip contents if filename has '.gz'
  options[:compress] ||= File.extname(filename) == '.gz'

  FileUtils.mkdir_p File.dirname(filename)

  File.open("#{filename}+", 'wb') do |f|
    if options[:compress]
      # Run contents through `Zlib`
      gz = Zlib::GzipWriter.new(f, Zlib::BEST_COMPRESSION)
      gz.mtime = mtime.to_i
      gz.write to_s
      gz.close
    else
      # Write out as is
      f.write to_s
    end
  end

  # Atomic write
  FileUtils.mv("#{filename}+", filename)

  # Set mtime correctly
  File.utime(mtime, mtime, filename)

  nil
ensure
  # Ensure tmp file gets cleaned up
  FileUtils.rm("#{filename}+") if File.exist?("#{filename}+")
end

Protected Instance Methods

dependency_fresh?(environment, dep) click to toggle source

Check if dependency is fresh.

`dep` is a `Hash` with `path`, `mtime` and `hexdigest` keys.

A `Hash` is used rather than other `Asset` object because we want to test non-asset files and directories.

# File lib/sprockets/asset.rb, line 229
def dependency_fresh?(environment, dep)
  path, mtime, hexdigest = dep.pathname.to_s, dep.mtime, dep.digest

  stat = environment.stat(path)

  # If path no longer exists, its definitely stale.
  if stat.nil?
    return false
  end

  # Compare dependency mtime to the actual mtime. If the
  # dependency mtime is newer than the actual mtime, the file
  # hasn't changed since we created this `Asset` instance.
  #
  # However, if the mtime is newer it doesn't mean the asset is
  # stale. Many deployment environments may recopy or recheckout
  # assets on each deploy. In this case the mtime would be the
  # time of deploy rather than modified time.
  if mtime >= stat.mtime
    return true
  end

  digest = environment.file_digest(path)

  # If the mtime is newer, do a full digest comparsion. Return
  # fresh if the digests match.
  if hexdigest == digest.hexdigest
    return true
  end

  # Otherwise, its stale.
  false
end
dependency_paths() click to toggle source

Internal: String paths that are marked as dependencies after processing.

Default to an empty `Array`.

# File lib/sprockets/asset.rb, line 197
def dependency_paths
  @dependency_paths ||= []
end
expand_root_path(path) click to toggle source

Replace `$root` placeholder with actual environment root.

# File lib/sprockets/asset.rb, line 214
def expand_root_path(path)
  path.to_s.sub(/^\$root/, @root)
end
relative_pathname() click to toggle source

Get pathname with its root stripped.

# File lib/sprockets/asset.rb, line 209
def relative_pathname
  @relative_pathname ||= Pathname.new(relativize_root_path(pathname))
end
relativize_root_path(path) click to toggle source

Replace actual environment root with `$root` placeholder.

# File lib/sprockets/asset.rb, line 219
def relativize_root_path(path)
  path.to_s.sub(/^#{Regexp.escape(@root)}/, '$root')
end
required_assets() click to toggle source

Internal: `ProccessedAsset`s that are required after processing.

Default to an empty `Array`.

# File lib/sprockets/asset.rb, line 204
def required_assets
  @required_assets ||= []
end