Class: Sprockets::Asset

Inherits:
Object
  • Object
show all
Defined in:
lib/sprockets/asset.rb

Overview

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

Direct Known Subclasses

BundledAsset, ProcessedAsset, StaticAsset

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(environment, logical_path, pathname) ⇒ Asset

Returns a new instance of Asset

Raises:


35
36
37
38
39
40
41
42
43
44
45
46
# 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

Instance Attribute Details

#content_typeObject (readonly)

Returns the value of attribute content_type


32
33
34
# File 'lib/sprockets/asset.rb', line 32

def content_type
  @content_type
end

#digestObject (readonly)

Returns the value of attribute digest


32
33
34
# File 'lib/sprockets/asset.rb', line 32

def digest
  @digest
end

#lengthObject (readonly) Also known as: bytesize

Returns the value of attribute length


32
33
34
# File 'lib/sprockets/asset.rb', line 32

def length
  @length
end

#logical_pathObject (readonly)

Returns the value of attribute logical_path


31
32
33
# File 'lib/sprockets/asset.rb', line 31

def logical_path
  @logical_path
end

#mtimeObject (readonly)

Returns the value of attribute mtime


32
33
34
# File 'lib/sprockets/asset.rb', line 32

def mtime
  @mtime
end

#pathnameObject (readonly)

Returns the value of attribute pathname


31
32
33
# File 'lib/sprockets/asset.rb', line 31

def pathname
  @pathname
end

Class Method Details

.from_hash(environment, hash) ⇒ Object

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


8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 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

Instance Method Details

#bodyObject

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


107
108
109
# File 'lib/sprockets/asset.rb', line 107

def body
  source
end

#dependenciesObject

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


91
92
93
# File 'lib/sprockets/asset.rb', line 91

def dependencies
  []
end

#digest_pathObject

Return logical path with digest spliced in.

"foo/bar-37b51d194a7513e45b56f6524f2d51f2.js"

86
87
88
# File 'lib/sprockets/asset.rb', line 86

def digest_path
  logical_path.sub(/\.(\w+)$/) { |ext| "-#{digest}#{ext}" }
end

#each {|to_s| ... } ⇒ Object

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

Yields:


118
119
120
# File 'lib/sprockets/asset.rb', line 118

def each
  yield to_s
end

#encode_with(coder) ⇒ Object

Copy serialized attributes to the coder object


72
73
74
75
76
77
78
79
80
# 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) ⇒ Boolean Also known as: ==

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

Returns:

  • (Boolean)

185
186
187
188
189
190
# 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

#fresh?(environment) ⇒ Boolean

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.

Returns:

  • (Boolean)

126
127
128
129
# File 'lib/sprockets/asset.rb', line 126

def fresh?(environment)
  # Check current mtime and digest
  dependency_fresh?(environment, self)
end

#hashObject


180
181
182
# File 'lib/sprockets/asset.rb', line 180

def hash
  digest.hash
end

#init_with(environment, coder) ⇒ Object

Initialize `Asset` from serialized `Hash`.


49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# 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

#inspectObject

Pretty inspect


172
173
174
175
176
177
178
# 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) ⇒ Boolean

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

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

Returns:

  • (Boolean)

135
136
137
# File 'lib/sprockets/asset.rb', line 135

def stale?(environment)
  !fresh?(environment)
end

#to_aObject

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.


102
103
104
# File 'lib/sprockets/asset.rb', line 102

def to_a
  [self]
end

#to_sObject

Return `String` of concatenated source.


112
113
114
# File 'lib/sprockets/asset.rb', line 112

def to_s
  source
end

#write_to(filename, options = {}) ⇒ Object

Save asset to disk.


140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# 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