lib/sprockets/context.rb in sprockets-2.12.5 vs lib/sprockets/context.rb in sprockets-3.0.0.beta.1
- old
+ new
@@ -1,17 +1,15 @@
-require 'base64'
-require 'rack/utils'
-require 'sprockets/errors'
-require 'sprockets/utils'
require 'pathname'
+require 'rack/utils'
require 'set'
+require 'sprockets/errors'
module Sprockets
- # `Context` provides helper methods to all `Tilt` processors. They
- # are typically accessed by ERB templates. You can mix in custom
- # helpers by injecting them into `Environment#context_class`. Do not
- # mix them into `Context` directly.
+ # Deprecated: `Context` provides helper methods to all `Template` processors.
+ # They are typically accessed by ERB templates. You can mix in custom helpers
+ # by injecting them into `Environment#context_class`. Do not mix them into
+ # `Context` directly.
#
# environment.context_class.class_eval do
# include MyHelper
# def asset_url; end
# end
@@ -19,53 +17,56 @@
# <%= asset_url "foo.png" %>
#
# The `Context` also collects dependencies declared by
# assets. See `DirectiveProcessor` for an example of this.
class Context
- attr_reader :environment, :pathname
- attr_reader :_required_paths, :_stubbed_assets
- attr_reader :_dependency_paths, :_dependency_assets
- attr_writer :__LINE__
+ attr_reader :environment, :filename, :pathname
- def initialize(environment, logical_path, pathname)
- @environment = environment
- @logical_path = logical_path
- @pathname = pathname
- @__LINE__ = nil
+ def initialize(input)
+ @environment = input[:environment]
+ @metadata = input[:metadata]
+ @load_path = input[:load_path]
+ @logical_path = input[:name]
+ @filename = input[:filename]
+ @dirname = File.dirname(@filename)
+ @pathname = Pathname.new(@filename)
+ @content_type = input[:content_type]
- @_required_paths = []
- @_stubbed_assets = Set.new
- @_dependency_paths = Set.new
- @_dependency_assets = Set.new([pathname.to_s])
+ @required = Set.new(@metadata[:required])
+ @stubbed = Set.new(@metadata[:stubbed])
+ @links = Set.new(@metadata[:links])
+ @dependency_paths = Set.new(@metadata[:dependency_paths])
end
+ def metadata
+ { required: @required,
+ stubbed: @stubbed,
+ links: @links,
+ dependency_paths: @dependency_paths }
+ end
+
# Returns the environment path that contains the file.
#
# If `app/javascripts` and `app/stylesheets` are in your path, and
- # current file is `app/javascripts/foo/bar.js`, `root_path` would
+ # current file is `app/javascripts/foo/bar.js`, `load_path` would
# return `app/javascripts`.
- def root_path
- environment.paths.detect { |path| pathname.to_s[path] }
- end
+ attr_reader :load_path
+ alias_method :root_path, :load_path
# Returns logical path without any file extensions.
#
# 'app/javascripts/application.js'
# # => 'application'
#
- def logical_path
- @logical_path.chomp(File.extname(@logical_path))
- end
+ attr_reader :logical_path
# Returns content type of file
#
# 'application/javascript'
# 'text/css'
#
- def content_type
- environment.content_type_of(pathname)
- end
+ attr_reader :content_type
# Given a logical path, `resolve` will find and return the fully
# expanded path. Relative paths will also be resolved. An optional
# `:content_type` restriction can be supplied to restrict the
# search.
@@ -74,51 +75,36 @@
# # => "/path/to/app/javascripts/foo.js"
#
# resolve("./bar.js")
# # => "/path/to/app/javascripts/bar.js"
#
- def resolve(path, options = {}, &block)
- pathname = Pathname.new(path)
- attributes = environment.attributes_for(pathname)
+ def resolve(path, options = {})
+ options[:content_type] = self.content_type if options[:content_type] == :self
+ options[:accept] = options.delete(:content_type)
- if pathname.absolute?
- if environment.stat(pathname)
- pathname
+ if environment.absolute_path?(path)
+ path
+ elsif environment.relative_path?(path)
+ path = File.expand_path(path, @dirname)
+ if logical_path = @environment.split_subpath(load_path, path)
+ environment.resolve_in_load_path(load_path, logical_path, options)
else
- raise FileNotFound, "couldn't find file '#{pathname}'"
+ raise FileOutsidePaths, "#{path} isn't under path: #{load_path}"
end
-
- elsif content_type = options[:content_type]
- content_type = self.content_type if content_type == :self
-
- if attributes.format_extension
- if content_type != attributes.content_type
- raise ContentTypeMismatch, "#{path} is " +
- "'#{attributes.content_type}', not '#{content_type}'"
- end
- end
-
- resolve(path) do |candidate|
- if self.content_type == environment.content_type_of(candidate)
- return candidate
- end
- end
-
- raise FileNotFound, "couldn't find file '#{path}'"
else
- environment.resolve(path, {:base_path => self.pathname.dirname}.merge(options), &block)
+ environment.resolve(path, options)
end
end
# `depend_on` allows you to state a dependency on a file without
# including it.
#
# This is used for caching purposes. Any changes made to
# the dependency file with invalidate the cache of the
# source file.
def depend_on(path)
- @_dependency_paths << resolve(path).to_s
+ @dependency_paths << resolve(path).to_s
nil
end
# `depend_on_asset` allows you to state an asset dependency
# without including it.
@@ -126,12 +112,13 @@
# This is used for caching purposes. Any changes that would
# invalidate the dependency asset will invalidate the source
# file. Unlike `depend_on`, this will include recursively include
# the target asset's dependencies.
def depend_on_asset(path)
- filename = resolve(path).to_s
- @_dependency_assets << filename
+ if asset = @environment.find_asset(resolve(path))
+ @dependency_paths.merge(asset.metadata[:dependency_paths])
+ end
nil
end
# `require_asset` declares `path` as a dependency of the file. The
# dependency will be inserted before the file and will only be
@@ -141,69 +128,35 @@
# require assets.
#
# <%= require_asset "#{framework}.js" %>
#
def require_asset(path)
- pathname = resolve(path, :content_type => :self)
- depend_on_asset(pathname)
- @_required_paths << pathname.to_s
+ filename = resolve(path, accept: @content_type)
+ @required << @environment.resolve_asset_uri(filename, accept: @content_type, bundle: false)
nil
end
# `stub_asset` blacklists `path` from being included in the bundle.
# `path` must be an asset which may or may not already be included
# in the bundle.
def stub_asset(path)
- @_stubbed_assets << resolve(path, :content_type => :self).to_s
+ filename = resolve(path, accept: @content_type)
+ @stubbed << @environment.resolve_asset_uri(filename, accept: @content_type, bundle: false)
nil
end
- # Tests if target path is able to be safely required into the
- # current concatenation.
- def asset_requirable?(path)
- pathname = resolve(path)
- content_type = environment.content_type_of(pathname)
- stat = environment.stat(path)
- return false unless stat && stat.file?
- self.content_type.nil? || self.content_type == content_type
- end
-
- # Reads `path` and runs processors on the file.
+ # `link_asset` declares an external dependency on an asset without directly
+ # including it. The target asset is returned from this function making it
+ # easy to construct a link to it.
#
- # This allows you to capture the result of an asset and include it
- # directly in another.
- #
- # <%= evaluate "bar.js" %>
- #
- def evaluate(path, options = {})
- pathname = resolve(path)
- attributes = environment.attributes_for(pathname)
- processors = options[:processors] || attributes.processors
-
- if options[:data]
- result = options[:data]
- else
- if environment.respond_to?(:default_external_encoding)
- mime_type = environment.mime_types(pathname.extname)
- encoding = environment.encoding_for_mime_type(mime_type)
- result = Sprockets::Utils.read_unicode(pathname, encoding)
- else
- result = Sprockets::Utils.read_unicode(pathname)
- end
+ # Returns an Asset or nil.
+ def link_asset(path)
+ if asset = @environment.find_asset(resolve(path))
+ @dependency_paths.merge(asset.metadata[:dependency_paths])
+ @links << asset.uri
end
-
- processors.each do |processor|
- begin
- template = processor.new(pathname.to_s) { result }
- result = template.render(self, {})
- rescue Exception => e
- annotate_exception! e
- raise
- end
- end
-
- result
+ asset
end
# Returns a Base64-encoded `data:` URI with the contents of the
# asset at the specified path, and marks that path as a dependency
# of the current file.
@@ -214,13 +167,12 @@
#
# $('<img>').attr('src', '<%= asset_data_uri 'avatar.jpg' %>')
#
def asset_data_uri(path)
depend_on_asset(path)
- asset = environment.find_asset(path)
- base64 = Base64.encode64(asset.to_s).gsub(/\s+/, "")
- "data:#{asset.content_type};base64,#{Rack::Utils.escape(base64)}"
+ asset = environment.find_asset(path, accept_encoding: 'base64')
+ "data:#{asset.content_type};base64,#{Rack::Utils.escape(asset.to_s)}"
end
# Expands logical path to full url to asset.
#
# NOTE: This helper is currently not implemented and should be
@@ -241,49 +193,34 @@
raise NotImplementedError, message
end
# Expand logical image asset path.
def image_path(path)
- asset_path(path, :type => :image)
+ asset_path(path, type: :image)
end
# Expand logical video asset path.
def video_path(path)
- asset_path(path, :type => :video)
+ asset_path(path, type: :video)
end
# Expand logical audio asset path.
def audio_path(path)
- asset_path(path, :type => :audio)
+ asset_path(path, type: :audio)
end
# Expand logical font asset path.
def font_path(path)
- asset_path(path, :type => :font)
+ asset_path(path, type: :font)
end
# Expand logical javascript asset path.
def javascript_path(path)
- asset_path(path, :type => :javascript)
+ asset_path(path, type: :javascript)
end
# Expand logical stylesheet asset path.
def stylesheet_path(path)
- asset_path(path, :type => :stylesheet)
+ asset_path(path, type: :stylesheet)
end
-
- private
- # Annotates exception backtrace with the original template that
- # the exception was raised in.
- def annotate_exception!(exception)
- location = pathname.to_s
- location << ":#{@__LINE__}" if @__LINE__
-
- exception.extend(Sprockets::EngineError)
- exception.sprockets_annotation = " (in #{location})"
- end
-
- def logger
- environment.logger
- end
end
end