class Sprockets::Base
‘Base` class for `Environment` and `Index`.
def [](*args)
environment['application.js']
Preferred `find_asset` shorthand.
def [](*args) find_asset(*args) end
def attributes_for(path)
def attributes_for(path) AssetAttributes.new(self, path) end
def build_asset(logical_path, pathname, options)
def build_asset(logical_path, pathname, options) pathname = Pathname.new(pathname) # If there are any processors to run on the pathname, use # `BundledAsset`. Otherwise use `StaticAsset` and treat is as binary. if attributes_for(pathname).processors.any? if options[:bundle] == false circular_call_protection(pathname.to_s) do ProcessedAsset.new(index, logical_path, pathname) end else BundledAsset.new(index, logical_path, pathname) end else StaticAsset.new(index, logical_path, pathname) end end
def cache=(cache)
setters. Either `get(key)`/`set(key, value)`,
The cache store must implement a pair of getters and
Set persistent cache store
def cache=(cache) expire_index! @cache = cache end
def cache_key_for(path, options)
def cache_key_for(path, options) "#{path}:#{options[:bundle] ? '1' : '0'}" end
def circular_call_protection(path)
def circular_call_protection(path) reset = Thread.current[:sprockets_circular_calls].nil? calls = Thread.current[:sprockets_circular_calls] ||= Set.new if calls.include?(path) raise CircularDependencyError, "#{path} has already been required" end calls << path yield ensure Thread.current[:sprockets_circular_calls] = nil if reset end
def content_type_of(path)
def content_type_of(path) attributes_for(path).content_type end
def digest
digests. Any change in the environment digest will affect all of
The value also provides a seed digest for all `Asset`
cached assets.
than in the same. Two equal `Environment`s can share the same
useful for comparing environment states between processes rather
same digest value they can be treated as equal. This is more
This value serves two purposes. If two `Environment`s have the
Returns a `Digest` instance for the `Environment`.
def digest # Compute the initial digest using the implementation class. The # Sprockets release version and custom environment version are # mixed in. So any new releases will affect all your assets. @digest ||= digest_class.new.update(VERSION).update(version.to_s) # Returned a dupped copy so the caller can safely mutate it with `.update` @digest.dup end
def digest_class=(klass)
environment.digest_class = Digest::SHA1
`Digest::SHA1`.
`Digest::` implementation such as `Digest::MD5` or
Assign a `Digest` implementation class. This maybe any Ruby
def digest_class=(klass) expire_index! @digest_class = klass end
def each_entry(root, &block)
def each_entry(root, &block) return to_enum(__method__, root) unless block_given? root = Pathname.new(root) unless root.is_a?(Pathname) paths = [] entries(root).sort.each do |filename| path = root.join(filename) paths << path if stat(path).directory? each_entry(path) do |subpath| paths << subpath end end end paths.sort_by(&:to_s).each(&block) nil end
def each_file
def each_file return to_enum(__method__) unless block_given? paths.each do |root| each_entry(root) do |path| if !stat(path).directory? yield path end end end nil end
def each_logical_path(*args)
def each_logical_path(*args) return to_enum(__method__, *args) unless block_given? filters = args.flatten files = {} each_file do |filename| if logical_path = logical_path_for_filename(filename, filters) yield logical_path unless files[logical_path] files[logical_path] = true end end nil end
def entries(pathname)
Works like `Dir.entries`.
def entries(pathname) trail.entries(pathname) end
def expire_index!
def expire_index! raise NotImplementedError end
def file_digest(path)
Read and compute digest of filename.
def file_digest(path) if stat = self.stat(path) # If its a file, digest the contents if stat.file? digest.file(path.to_s) # If its a directive, digest the list of filenames elsif stat.directory? contents = self.entries(path).join(',') digest.update(contents) end end end
def find_asset(path, options = {})
def find_asset(path, options = {}) logical_path = path pathname = Pathname.new(path) if pathname.absolute? return unless stat(pathname) logical_path = attributes_for(pathname).logical_path else begin pathname = resolve(logical_path) rescue FileNotFound return nil end end build_asset(logical_path, pathname, options) end
def index
def index raise NotImplementedError end
def inspect
def inspect "#<#{self.class}:0x#{object_id.to_s(16)} " + "root=#{root.to_s.inspect}, " + "paths=#{paths.inspect}, " + "digest=#{digest.to_s.inspect}" + ">" end
def logical_path_for_filename(filename, filters)
def logical_path_for_filename(filename, filters) logical_path = attributes_for(filename).logical_path.to_s if matches_filter(filters, logical_path) return logical_path end # If filename is an index file, retest with alias if File.basename(logical_path)[/[^\.]+/, 0] == 'index' path = logical_path.sub(/\/index\./, '.') if matches_filter(filters, path) return path end end nil end
def matches_filter(filters, filename)
def matches_filter(filters, filename) return true if filters.empty? filters.any? do |filter| if filter.is_a?(Regexp) filter.match(filename) elsif filter.respond_to?(:call) filter.call(filename) else File.fnmatch(filter.to_s, filename) end end end
def stat(path)
Works like `File.stat`.
def stat(path) trail.stat(path) end
def version=(version)
environment.version = '2.0'
Assign an environment version.
def version=(version) expire_index! @version = version end