class Sprockets::Asset - sprockets-2.11.3 Documentation

# 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)
      # drop precision to 1 second, same pattern followed elsewhere
      @mtime        = Time.at(environment.stat(pathname).mtime.to_i)
      @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.to_i
      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 49
    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']
        @mtime = Time.at(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.
      #
      # Note: to_i is used in eql? and write_to we assume fidelity of 1 second
      #  if people save files more frequently than 1 second sprockets may
      #  not pick it up, by design
      if mtime.to_i >= stat.mtime.to_i
        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