Class: Sprockets::Manifest

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

Overview

The Manifest logs the contents of assets compiled to a single directory. It records basic attributes about the asset for fast lookup without having to compile. A pointer from each logical path indicates with fingerprinted asset is the current one.

The JSON is part of the public API and should be considered stable. This should make it easy to read from other programming languages and processes that don’t have sprockets loaded. See ‘#assets` and `#files` for more infomation about the structure.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(environment, path) ⇒ Manifest

Create new Manifest associated with an ‘environment`. `path` is a full path to the manifest json file. The file may or may not already exist. The dirname of the `path` will be used to write compiled assets to. Otherwise, if the path is a directory, the filename will default to “manifest.json” in that directory.

Manifest.new(environment, "./public/assets/manifest.json")


25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/sprockets/manifest.rb', line 25

def initialize(environment, path)
  @environment = environment

  if File.extname(path) == ""
    @dir  = File.expand_path(path)
    @path = File.join(@dir, 'manifest.json')
  else
    @path = File.expand_path(path)
    @dir  = File.dirname(path)
  end

  data = nil

  begin
    if File.exist?(@path)
      data = MultiJson.decode(File.read(@path))
    end
  rescue MultiJson::DecodeError => e
    logger.error "#{@path} is invalid: #{e.class} #{e.message}"
  end

  @data = data.is_a?(Hash) ? data : {}
end

Instance Attribute Details

#dirObject (readonly)

Returns the value of attribute dir.



15
16
17
# File 'lib/sprockets/manifest.rb', line 15

def dir
  @dir
end

#environmentObject (readonly)

Returns the value of attribute environment.



15
16
17
# File 'lib/sprockets/manifest.rb', line 15

def environment
  @environment
end

#pathObject (readonly)

Returns the value of attribute path.



15
16
17
# File 'lib/sprockets/manifest.rb', line 15

def path
  @path
end

Instance Method Details

#assetsObject

Returns internal assets mapping. Keys are logical paths which map to the latest fingerprinted filename.

Logical path (String): Fingerprint path (String)

{ "application.js" => "application-2e8e9a7c6b0aafa0c9bdeec90ea30213.js",
  "jquery.js"      => "jquery-ae0908555a245f8266f77df5a8edca2e.js" }


57
58
59
# File 'lib/sprockets/manifest.rb', line 57

def assets
  @data['assets'] ||= {}
end

#clean(keep = 2) ⇒ Object

Cleanup old assets in the compile directory. By default it will keep the latest version plus 2 backups.



139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/sprockets/manifest.rb', line 139

def clean(keep = 2)
  self.assets.keys.each do |logical_path|
    # Get assets sorted by ctime, newest first
    assets = backups_for(logical_path)

    # Keep the last N backups
    assets = assets[keep..-1] || []

    # Remove old assets
    assets.each { |path, _| remove(path) }
  end
end

#clobberObject

Wipe directive



153
154
155
156
157
# File 'lib/sprockets/manifest.rb', line 153

def clobber
  FileUtils.rm_r(@dir) if File.exist?(@dir)
  logger.warn "Removed #{@dir}"
  nil
end

#compile(*args) ⇒ Object

Compile and write asset to directory. The asset is written to a fingerprinted filename like ‘application-2e8e9a7c6b0aafa0c9bdeec90ea30213.js`. An entry is also inserted into the manifest file.

compile("application.js")


85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/sprockets/manifest.rb', line 85

def compile(*args)
  paths = environment.each_logical_path(*args).to_a +
    args.flatten.select { |fn| Pathname.new(fn).absolute? }

  paths.each do |path|
    if asset = find_asset(path)
      files[asset.digest_path] = {
        'logical_path' => asset.logical_path,
        'mtime'        => asset.mtime.iso8601,
        'size'         => asset.bytesize,
        'digest'       => asset.digest
      }
      assets[asset.logical_path] = asset.digest_path

      target = File.join(dir, asset.digest_path)

      if File.exist?(target)
        logger.debug "Skipping #{target}, already exists"
      else
        logger.info "Writing #{target}"
        asset.write_to target
      end

      save
      asset
    end
  end
end

#filesObject

Returns internal file directory listing. Keys are filenames which map to an attributes array.

 Fingerprint path (String):
   logical_path: Logical path (String)
   mtime: ISO8601 mtime (String)
   digest: Base64 hex digest (String)

{ "application-2e8e9a7c6b0aafa0c9bdeec90ea30213.js" =>
    { 'logical_path' => "application.js",
      'mtime' => "2011-12-13T21:47:08-06:00",
      'digest' => "2e8e9a7c6b0aafa0c9bdeec90ea30213" } }


74
75
76
# File 'lib/sprockets/manifest.rb', line 74

def files
  @data['files'] ||= {}
end

#remove(filename) ⇒ Object

Removes file from directory and from manifest. ‘filename` must be the name with any directory path.

manifest.remove("application-2e8e9a7c6b0aafa0c9bdeec90ea30213.js")


119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/sprockets/manifest.rb', line 119

def remove(filename)
  path = File.join(dir, filename)
  logical_path = files[filename]['logical_path']

  if assets[logical_path] == filename
    assets.delete(logical_path)
  end

  files.delete(filename)
  FileUtils.rm(path) if File.exist?(path)

  save

  logger.warn "Removed #{filename}"

  nil
end