sprockets 2.12.5 → 3.0.0.beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of sprockets might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/LICENSE +2 -2
- data/README.md +61 -34
- data/lib/rake/sprocketstask.rb +5 -4
- data/lib/sprockets.rb +123 -85
- data/lib/sprockets/asset.rb +161 -200
- data/lib/sprockets/asset_uri.rb +64 -0
- data/lib/sprockets/base.rb +138 -373
- data/lib/sprockets/bower.rb +56 -0
- data/lib/sprockets/bundle.rb +32 -0
- data/lib/sprockets/cache.rb +220 -0
- data/lib/sprockets/cache/file_store.rb +145 -13
- data/lib/sprockets/cache/memory_store.rb +66 -0
- data/lib/sprockets/cache/null_store.rb +46 -0
- data/lib/sprockets/cached_environment.rb +103 -0
- data/lib/sprockets/closure_compressor.rb +30 -12
- data/lib/sprockets/coffee_script_template.rb +23 -0
- data/lib/sprockets/compressing.rb +20 -25
- data/lib/sprockets/configuration.rb +95 -0
- data/lib/sprockets/context.rb +68 -131
- data/lib/sprockets/directive_processor.rb +138 -179
- data/lib/sprockets/eco_template.rb +10 -19
- data/lib/sprockets/ejs_template.rb +10 -19
- data/lib/sprockets/encoding_utils.rb +246 -0
- data/lib/sprockets/engines.rb +40 -29
- data/lib/sprockets/environment.rb +10 -66
- data/lib/sprockets/erb_template.rb +23 -0
- data/lib/sprockets/errors.rb +5 -13
- data/lib/sprockets/http_utils.rb +97 -0
- data/lib/sprockets/jst_processor.rb +28 -15
- data/lib/sprockets/lazy_processor.rb +15 -0
- data/lib/sprockets/legacy.rb +23 -0
- data/lib/sprockets/legacy_proc_processor.rb +35 -0
- data/lib/sprockets/legacy_tilt_processor.rb +29 -0
- data/lib/sprockets/manifest.rb +128 -99
- data/lib/sprockets/mime.rb +114 -33
- data/lib/sprockets/path_utils.rb +179 -0
- data/lib/sprockets/paths.rb +13 -26
- data/lib/sprockets/processing.rb +198 -107
- data/lib/sprockets/resolve.rb +289 -0
- data/lib/sprockets/sass_compressor.rb +36 -17
- data/lib/sprockets/sass_template.rb +269 -46
- data/lib/sprockets/server.rb +113 -83
- data/lib/sprockets/transformers.rb +69 -0
- data/lib/sprockets/uglifier_compressor.rb +36 -15
- data/lib/sprockets/utils.rb +161 -44
- data/lib/sprockets/version.rb +1 -1
- data/lib/sprockets/yui_compressor.rb +37 -12
- metadata +64 -106
- data/lib/sprockets/asset_attributes.rb +0 -137
- data/lib/sprockets/bundled_asset.rb +0 -78
- data/lib/sprockets/caching.rb +0 -96
- data/lib/sprockets/charset_normalizer.rb +0 -41
- data/lib/sprockets/index.rb +0 -100
- data/lib/sprockets/processed_asset.rb +0 -152
- data/lib/sprockets/processor.rb +0 -32
- data/lib/sprockets/safety_colons.rb +0 -28
- data/lib/sprockets/sass_cache_store.rb +0 -29
- data/lib/sprockets/sass_functions.rb +0 -70
- data/lib/sprockets/sass_importer.rb +0 -30
- data/lib/sprockets/scss_template.rb +0 -13
- data/lib/sprockets/static_asset.rb +0 -60
    
        data/lib/sprockets/base.rb
    CHANGED
    
    | @@ -1,89 +1,19 @@ | |
| 1 | 
            -
            require 'sprockets/ | 
| 2 | 
            -
            require 'sprockets/ | 
| 3 | 
            -
            require 'sprockets/caching'
         | 
| 1 | 
            +
            require 'sprockets/asset'
         | 
| 2 | 
            +
            require 'sprockets/bower'
         | 
| 4 3 | 
             
            require 'sprockets/errors'
         | 
| 5 | 
            -
            require 'sprockets/ | 
| 4 | 
            +
            require 'sprockets/legacy'
         | 
| 5 | 
            +
            require 'sprockets/resolve'
         | 
| 6 6 | 
             
            require 'sprockets/server'
         | 
| 7 | 
            -
            require 'sprockets/static_asset'
         | 
| 8 | 
            -
            require 'multi_json'
         | 
| 9 | 
            -
            require 'pathname'
         | 
| 10 7 |  | 
| 11 8 | 
             
            module Sprockets
         | 
| 12 | 
            -
              # `Base` class for `Environment` and ` | 
| 9 | 
            +
              # `Base` class for `Environment` and `Cached`.
         | 
| 13 10 | 
             
              class Base
         | 
| 14 | 
            -
                include  | 
| 15 | 
            -
             | 
| 16 | 
            -
                 | 
| 17 | 
            -
                 | 
| 18 | 
            -
                 | 
| 19 | 
            -
                 | 
| 20 | 
            -
             | 
| 21 | 
            -
                # Assign a `Digest` implementation class. This may be any Ruby
         | 
| 22 | 
            -
                # `Digest::` implementation such as `Digest::MD5` or
         | 
| 23 | 
            -
                # `Digest::SHA1`.
         | 
| 24 | 
            -
                #
         | 
| 25 | 
            -
                #     environment.digest_class = Digest::SHA1
         | 
| 26 | 
            -
                #
         | 
| 27 | 
            -
                def digest_class=(klass)
         | 
| 28 | 
            -
                  expire_index!
         | 
| 29 | 
            -
                  @digest_class = klass
         | 
| 30 | 
            -
                end
         | 
| 31 | 
            -
             | 
| 32 | 
            -
                # The `Environment#version` is a custom value used for manually
         | 
| 33 | 
            -
                # expiring all asset caches.
         | 
| 34 | 
            -
                #
         | 
| 35 | 
            -
                # Sprockets is able to track most file and directory changes and
         | 
| 36 | 
            -
                # will take care of expiring the cache for you. However, its
         | 
| 37 | 
            -
                # impossible to know when any custom helpers change that you mix
         | 
| 38 | 
            -
                # into the `Context`.
         | 
| 39 | 
            -
                #
         | 
| 40 | 
            -
                # It would be wise to increment this value anytime you make a
         | 
| 41 | 
            -
                # configuration change to the `Environment` object.
         | 
| 42 | 
            -
                attr_reader :version
         | 
| 43 | 
            -
             | 
| 44 | 
            -
                # Assign an environment version.
         | 
| 45 | 
            -
                #
         | 
| 46 | 
            -
                #     environment.version = '2.0'
         | 
| 47 | 
            -
                #
         | 
| 48 | 
            -
                def version=(version)
         | 
| 49 | 
            -
                  expire_index!
         | 
| 50 | 
            -
                  @version = version
         | 
| 51 | 
            -
                end
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                # Returns a `Digest` instance for the `Environment`.
         | 
| 54 | 
            -
                #
         | 
| 55 | 
            -
                # This value serves two purposes. If two `Environment`s have the
         | 
| 56 | 
            -
                # same digest value they can be treated as equal. This is more
         | 
| 57 | 
            -
                # useful for comparing environment states between processes rather
         | 
| 58 | 
            -
                # than in the same. Two equal `Environment`s can share the same
         | 
| 59 | 
            -
                # cached assets.
         | 
| 60 | 
            -
                #
         | 
| 61 | 
            -
                # The value also provides a seed digest for all `Asset`
         | 
| 62 | 
            -
                # digests. Any change in the environment digest will affect all of
         | 
| 63 | 
            -
                # its assets.
         | 
| 64 | 
            -
                def digest
         | 
| 65 | 
            -
                  # Compute the initial digest using the implementation class. The
         | 
| 66 | 
            -
                  # Sprockets release version and custom environment version are
         | 
| 67 | 
            -
                  # mixed in. So any new releases will affect all your assets.
         | 
| 68 | 
            -
                  @digest ||= digest_class.new.update(VERSION).update(version.to_s)
         | 
| 69 | 
            -
             | 
| 70 | 
            -
                  # Returned a dupped copy so the caller can safely mutate it with `.update`
         | 
| 71 | 
            -
                  @digest.dup
         | 
| 72 | 
            -
                end
         | 
| 73 | 
            -
             | 
| 74 | 
            -
                # Get and set `Logger` instance.
         | 
| 75 | 
            -
                attr_accessor :logger
         | 
| 76 | 
            -
             | 
| 77 | 
            -
                # Get `Context` class.
         | 
| 78 | 
            -
                #
         | 
| 79 | 
            -
                # This class maybe mutated and mixed in with custom helpers.
         | 
| 80 | 
            -
                #
         | 
| 81 | 
            -
                #     environment.context_class.instance_eval do
         | 
| 82 | 
            -
                #       include MyHelpers
         | 
| 83 | 
            -
                #       def asset_url; end
         | 
| 84 | 
            -
                #     end
         | 
| 85 | 
            -
                #
         | 
| 86 | 
            -
                attr_reader :context_class
         | 
| 11 | 
            +
                include PathUtils, HTTPUtils
         | 
| 12 | 
            +
                include Configuration
         | 
| 13 | 
            +
                include Server
         | 
| 14 | 
            +
                include Resolve
         | 
| 15 | 
            +
                include Bower
         | 
| 16 | 
            +
                include Legacy
         | 
| 87 17 |  | 
| 88 18 | 
             
                # Get persistent cache store
         | 
| 89 19 | 
             
                attr_reader :cache
         | 
| @@ -94,197 +24,80 @@ module Sprockets | |
| 94 24 | 
             
                # setters. Either `get(key)`/`set(key, value)`,
         | 
| 95 25 | 
             
                # `[key]`/`[key]=value`, `read(key)`/`write(key, value)`.
         | 
| 96 26 | 
             
                def cache=(cache)
         | 
| 97 | 
            -
                   | 
| 98 | 
            -
                  @cache = cache
         | 
| 99 | 
            -
                end
         | 
| 100 | 
            -
             | 
| 101 | 
            -
                def prepend_path(path)
         | 
| 102 | 
            -
                  # Overrides the global behavior to expire the index
         | 
| 103 | 
            -
                  expire_index!
         | 
| 104 | 
            -
                  super
         | 
| 27 | 
            +
                  @cache = Cache.new(cache, logger)
         | 
| 105 28 | 
             
                end
         | 
| 106 29 |  | 
| 107 | 
            -
                 | 
| 108 | 
            -
             | 
| 109 | 
            -
                   | 
| 110 | 
            -
                  super
         | 
| 111 | 
            -
                end
         | 
| 112 | 
            -
             | 
| 113 | 
            -
                def clear_paths
         | 
| 114 | 
            -
                  # Overrides the global behavior to expire the index
         | 
| 115 | 
            -
                  expire_index!
         | 
| 116 | 
            -
                  super
         | 
| 30 | 
            +
                # Return an `Cached`. Must be implemented by the subclass.
         | 
| 31 | 
            +
                def cached
         | 
| 32 | 
            +
                  raise NotImplementedError
         | 
| 117 33 | 
             
                end
         | 
| 34 | 
            +
                alias_method :index, :cached
         | 
| 118 35 |  | 
| 119 | 
            -
                #  | 
| 120 | 
            -
                # searching the environment's paths.
         | 
| 36 | 
            +
                # Internal: Compute hexdigest for path.
         | 
| 121 37 | 
             
                #
         | 
| 122 | 
            -
                # | 
| 123 | 
            -
                #     # => "/path/to/app/javascripts/application.js.coffee"
         | 
| 38 | 
            +
                # path - String filename or directory path.
         | 
| 124 39 | 
             
                #
         | 
| 125 | 
            -
                #  | 
| 126 | 
            -
                def  | 
| 127 | 
            -
                   | 
| 128 | 
            -
             | 
| 129 | 
            -
                     | 
| 130 | 
            -
                     | 
| 131 | 
            -
             | 
| 132 | 
            -
             | 
| 133 | 
            -
             | 
| 134 | 
            -
             | 
| 135 | 
            -
                         | 
| 136 | 
            -
             | 
| 137 | 
            -
             | 
| 138 | 
            -
             | 
| 139 | 
            -
             | 
| 140 | 
            -
                            if extname == "" || extname == File.extname(fn)
         | 
| 141 | 
            -
                              yield pathname.dirname.join(fn)
         | 
| 142 | 
            -
                            end
         | 
| 143 | 
            -
                          end
         | 
| 144 | 
            -
                        end
         | 
| 145 | 
            -
                      else
         | 
| 146 | 
            -
                        yield pathname
         | 
| 40 | 
            +
                # Returns a String SHA1 hexdigest or nil.
         | 
| 41 | 
            +
                def file_hexdigest(path)
         | 
| 42 | 
            +
                  if stat = self.stat(path)
         | 
| 43 | 
            +
                    # Caveat: Digests are cached by the path's current mtime. Its possible
         | 
| 44 | 
            +
                    # for a files contents to have changed and its mtime to have been
         | 
| 45 | 
            +
                    # negligently reset thus appearing as if the file hasn't changed on
         | 
| 46 | 
            +
                    # disk. Also, the mtime is only read to the nearest second. Its
         | 
| 47 | 
            +
                    # also possible the file was updated more than once in a given second.
         | 
| 48 | 
            +
                    cache.fetch(['file_hexdigest', path, stat.mtime.to_i]) do
         | 
| 49 | 
            +
                      if stat.directory?
         | 
| 50 | 
            +
                        # If its a directive, digest the list of filenames
         | 
| 51 | 
            +
                        Digest::SHA1.hexdigest(self.entries(path).join(','))
         | 
| 52 | 
            +
                      elsif stat.file?
         | 
| 53 | 
            +
                        # If its a file, digest the contents
         | 
| 54 | 
            +
                        Digest::SHA1.file(path.to_s).hexdigest
         | 
| 147 55 | 
             
                      end
         | 
| 148 56 | 
             
                    end
         | 
| 149 | 
            -
                  else
         | 
| 150 | 
            -
                    resolve(logical_path, options) do |pathname|
         | 
| 151 | 
            -
                      return pathname
         | 
| 152 | 
            -
                    end
         | 
| 153 | 
            -
                    raise FileNotFound, "couldn't find file '#{logical_path}'"
         | 
| 154 57 | 
             
                  end
         | 
| 155 58 | 
             
                end
         | 
| 156 59 |  | 
| 157 | 
            -
                #  | 
| 158 | 
            -
                def register_mime_type(mime_type, ext)
         | 
| 159 | 
            -
                  # Overrides the global behavior to expire the index
         | 
| 160 | 
            -
                  expire_index!
         | 
| 161 | 
            -
                  @trail.append_extension(ext)
         | 
| 162 | 
            -
                  super
         | 
| 163 | 
            -
                end
         | 
| 164 | 
            -
             | 
| 165 | 
            -
                # Registers a new Engine `klass` for `ext`.
         | 
| 166 | 
            -
                def register_engine(ext, klass)
         | 
| 167 | 
            -
                  # Overrides the global behavior to expire the index
         | 
| 168 | 
            -
                  expire_index!
         | 
| 169 | 
            -
                  add_engine_to_trail(ext, klass)
         | 
| 170 | 
            -
                  super
         | 
| 171 | 
            -
                end
         | 
| 172 | 
            -
             | 
| 173 | 
            -
                def register_preprocessor(mime_type, klass, &block)
         | 
| 174 | 
            -
                  # Overrides the global behavior to expire the index
         | 
| 175 | 
            -
                  expire_index!
         | 
| 176 | 
            -
                  super
         | 
| 177 | 
            -
                end
         | 
| 178 | 
            -
             | 
| 179 | 
            -
                def unregister_preprocessor(mime_type, klass)
         | 
| 180 | 
            -
                  # Overrides the global behavior to expire the index
         | 
| 181 | 
            -
                  expire_index!
         | 
| 182 | 
            -
                  super
         | 
| 183 | 
            -
                end
         | 
| 184 | 
            -
             | 
| 185 | 
            -
                def register_postprocessor(mime_type, klass, &block)
         | 
| 186 | 
            -
                  # Overrides the global behavior to expire the index
         | 
| 187 | 
            -
                  expire_index!
         | 
| 188 | 
            -
                  super
         | 
| 189 | 
            -
                end
         | 
| 190 | 
            -
             | 
| 191 | 
            -
                def unregister_postprocessor(mime_type, klass)
         | 
| 192 | 
            -
                  # Overrides the global behavior to expire the index
         | 
| 193 | 
            -
                  expire_index!
         | 
| 194 | 
            -
                  super
         | 
| 195 | 
            -
                end
         | 
| 196 | 
            -
             | 
| 197 | 
            -
                def register_bundle_processor(mime_type, klass, &block)
         | 
| 198 | 
            -
                  # Overrides the global behavior to expire the index
         | 
| 199 | 
            -
                  expire_index!
         | 
| 200 | 
            -
                  super
         | 
| 201 | 
            -
                end
         | 
| 202 | 
            -
             | 
| 203 | 
            -
                def unregister_bundle_processor(mime_type, klass)
         | 
| 204 | 
            -
                  # Overrides the global behavior to expire the index
         | 
| 205 | 
            -
                  expire_index!
         | 
| 206 | 
            -
                  super
         | 
| 207 | 
            -
                end
         | 
| 208 | 
            -
             | 
| 209 | 
            -
                # Return an `Index`. Must be implemented by the subclass.
         | 
| 210 | 
            -
                def index
         | 
| 211 | 
            -
                  raise NotImplementedError
         | 
| 212 | 
            -
                end
         | 
| 213 | 
            -
             | 
| 214 | 
            -
                if defined? Encoding.default_external
         | 
| 215 | 
            -
                  # Define `default_external_encoding` accessor on 1.9.
         | 
| 216 | 
            -
                  # Defaults to UTF-8.
         | 
| 217 | 
            -
                  attr_accessor :default_external_encoding
         | 
| 218 | 
            -
                end
         | 
| 219 | 
            -
             | 
| 220 | 
            -
                # Works like `Dir.entries`.
         | 
| 60 | 
            +
                # Internal: Compute hexdigest for a set of paths.
         | 
| 221 61 | 
             
                #
         | 
| 222 | 
            -
                #  | 
| 223 | 
            -
                def entries(pathname)
         | 
| 224 | 
            -
                  @trail.entries(pathname)
         | 
| 225 | 
            -
                end
         | 
| 226 | 
            -
             | 
| 227 | 
            -
                # Works like `File.stat`.
         | 
| 62 | 
            +
                # paths - Array of filename or directory paths.
         | 
| 228 63 | 
             
                #
         | 
| 229 | 
            -
                #  | 
| 230 | 
            -
                def  | 
| 231 | 
            -
                   | 
| 64 | 
            +
                # Returns a String SHA1 hexdigest.
         | 
| 65 | 
            +
                def dependencies_hexdigest(paths)
         | 
| 66 | 
            +
                  digest = Digest::SHA1.new
         | 
| 67 | 
            +
                  paths.each { |path| digest.update(file_hexdigest(path).to_s) }
         | 
| 68 | 
            +
                  digest.hexdigest
         | 
| 232 69 | 
             
                end
         | 
| 233 70 |  | 
| 234 | 
            -
                #  | 
| 235 | 
            -
                 | 
| 236 | 
            -
             | 
| 237 | 
            -
             | 
| 238 | 
            -
                  if stat = self.stat(path)
         | 
| 239 | 
            -
                    # If its a file, digest the contents
         | 
| 240 | 
            -
                    if stat.file?
         | 
| 241 | 
            -
                      digest.file(path.to_s)
         | 
| 242 | 
            -
             | 
| 243 | 
            -
                    # If its a directive, digest the list of filenames
         | 
| 244 | 
            -
                    elsif stat.directory?
         | 
| 245 | 
            -
                      contents = self.entries(path).join(',')
         | 
| 246 | 
            -
                      digest.update(contents)
         | 
| 247 | 
            -
                    end
         | 
| 71 | 
            +
                # Find asset by logical path or expanded path.
         | 
| 72 | 
            +
                def find_asset(path, options = {})
         | 
| 73 | 
            +
                  if uri = resolve_asset_uri(path, options)
         | 
| 74 | 
            +
                    Asset.new(self, build_asset_by_uri(uri))
         | 
| 248 75 | 
             
                  end
         | 
| 249 76 | 
             
                end
         | 
| 250 77 |  | 
| 251 | 
            -
                 | 
| 252 | 
            -
             | 
| 253 | 
            -
                   | 
| 78 | 
            +
                def find_asset_by_uri(uri)
         | 
| 79 | 
            +
                  _, params = AssetURI.parse(uri)
         | 
| 80 | 
            +
                  asset = params.key?(:id) ?
         | 
| 81 | 
            +
                    build_asset_by_id_uri(uri) :
         | 
| 82 | 
            +
                    build_asset_by_uri(uri)
         | 
| 83 | 
            +
                  Asset.new(self, asset)
         | 
| 254 84 | 
             
                end
         | 
| 255 85 |  | 
| 256 | 
            -
                 | 
| 257 | 
            -
             | 
| 258 | 
            -
                  attributes_for(path).content_type
         | 
| 259 | 
            -
                end
         | 
| 86 | 
            +
                def find_all_linked_assets(path, options = {})
         | 
| 87 | 
            +
                  return to_enum(__method__, path, options) unless block_given?
         | 
| 260 88 |  | 
| 261 | 
            -
             | 
| 262 | 
            -
             | 
| 263 | 
            -
             | 
| 264 | 
            -
                   | 
| 265 | 
            -
             | 
| 266 | 
            -
             | 
| 267 | 
            -
             | 
| 268 | 
            -
                     | 
| 269 | 
            -
             | 
| 270 | 
            -
                    begin
         | 
| 271 | 
            -
                      pathname = resolve(logical_path)
         | 
| 272 | 
            -
             | 
| 273 | 
            -
                      # If logical path is missing a mime type extension, append
         | 
| 274 | 
            -
                      # the absolute path extname so it has one.
         | 
| 275 | 
            -
                      #
         | 
| 276 | 
            -
                      # Ensures some consistency between finding "foo/bar" vs
         | 
| 277 | 
            -
                      # "foo/bar.js".
         | 
| 278 | 
            -
                      if File.extname(logical_path) == ""
         | 
| 279 | 
            -
                        expanded_logical_path = attributes_for(pathname).logical_path
         | 
| 280 | 
            -
                        logical_path += File.extname(expanded_logical_path)
         | 
| 281 | 
            -
                      end
         | 
| 282 | 
            -
                    rescue FileNotFound
         | 
| 283 | 
            -
                      return nil
         | 
| 284 | 
            -
                    end
         | 
| 89 | 
            +
                  asset = find_asset(path, options)
         | 
| 90 | 
            +
                  return unless asset
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                  yield asset
         | 
| 93 | 
            +
                  stack = asset.links.to_a
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                  while uri = stack.shift
         | 
| 96 | 
            +
                    yield asset = find_asset_by_uri(uri)
         | 
| 97 | 
            +
                    stack = asset.links.to_a + stack
         | 
| 285 98 | 
             
                  end
         | 
| 286 99 |  | 
| 287 | 
            -
                   | 
| 100 | 
            +
                  nil
         | 
| 288 101 | 
             
                end
         | 
| 289 102 |  | 
| 290 103 | 
             
                # Preferred `find_asset` shorthand.
         | 
| @@ -295,153 +108,105 @@ module Sprockets | |
| 295 108 | 
             
                  find_asset(*args)
         | 
| 296 109 | 
             
                end
         | 
| 297 110 |  | 
| 298 | 
            -
                def each_entry(root, &block)
         | 
| 299 | 
            -
                  return to_enum(__method__, root) unless block_given?
         | 
| 300 | 
            -
                  root = Pathname.new(root) unless root.is_a?(Pathname)
         | 
| 301 | 
            -
             | 
| 302 | 
            -
                  paths = []
         | 
| 303 | 
            -
                  entries(root).sort.each do |filename|
         | 
| 304 | 
            -
                    path = root.join(filename)
         | 
| 305 | 
            -
                    paths << path
         | 
| 306 | 
            -
             | 
| 307 | 
            -
                    if stat(path).directory?
         | 
| 308 | 
            -
                      each_entry(path) do |subpath|
         | 
| 309 | 
            -
                        paths << subpath
         | 
| 310 | 
            -
                      end
         | 
| 311 | 
            -
                    end
         | 
| 312 | 
            -
                  end
         | 
| 313 | 
            -
             | 
| 314 | 
            -
                  paths.sort_by(&:to_s).each(&block)
         | 
| 315 | 
            -
             | 
| 316 | 
            -
                  nil
         | 
| 317 | 
            -
                end
         | 
| 318 | 
            -
             | 
| 319 | 
            -
                def each_file
         | 
| 320 | 
            -
                  return to_enum(__method__) unless block_given?
         | 
| 321 | 
            -
                  paths.each do |root|
         | 
| 322 | 
            -
                    each_entry(root) do |path|
         | 
| 323 | 
            -
                      if !stat(path).directory?
         | 
| 324 | 
            -
                        yield path
         | 
| 325 | 
            -
                      end
         | 
| 326 | 
            -
                    end
         | 
| 327 | 
            -
                  end
         | 
| 328 | 
            -
                  nil
         | 
| 329 | 
            -
                end
         | 
| 330 | 
            -
             | 
| 331 | 
            -
                def each_logical_path(*args, &block)
         | 
| 332 | 
            -
                  return to_enum(__method__, *args) unless block_given?
         | 
| 333 | 
            -
                  filters = args.flatten
         | 
| 334 | 
            -
                  files = {}
         | 
| 335 | 
            -
                  each_file do |filename|
         | 
| 336 | 
            -
                    if logical_path = logical_path_for_filename(filename, filters)
         | 
| 337 | 
            -
                      unless files[logical_path]
         | 
| 338 | 
            -
                        if block.arity == 2
         | 
| 339 | 
            -
                          yield logical_path, filename.to_s
         | 
| 340 | 
            -
                        else
         | 
| 341 | 
            -
                          yield logical_path
         | 
| 342 | 
            -
                        end
         | 
| 343 | 
            -
                      end
         | 
| 344 | 
            -
             | 
| 345 | 
            -
                      files[logical_path] = true
         | 
| 346 | 
            -
                    end
         | 
| 347 | 
            -
                  end
         | 
| 348 | 
            -
                  nil
         | 
| 349 | 
            -
                end
         | 
| 350 | 
            -
             | 
| 351 111 | 
             
                # Pretty inspect
         | 
| 352 112 | 
             
                def inspect
         | 
| 353 113 | 
             
                  "#<#{self.class}:0x#{object_id.to_s(16)} " +
         | 
| 354 114 | 
             
                    "root=#{root.to_s.inspect}, " +
         | 
| 355 | 
            -
                    "paths=#{paths.inspect} | 
| 356 | 
            -
                    "digest=#{digest.to_s.inspect}" +
         | 
| 357 | 
            -
                    ">"
         | 
| 115 | 
            +
                    "paths=#{paths.inspect}>"
         | 
| 358 116 | 
             
                end
         | 
| 359 117 |  | 
| 360 118 | 
             
                protected
         | 
| 361 | 
            -
                   | 
| 362 | 
            -
             | 
| 363 | 
            -
                    raise NotImplementedError
         | 
| 364 | 
            -
                  end
         | 
| 119 | 
            +
                  def build_asset_by_id_uri(uri)
         | 
| 120 | 
            +
                    path, params = AssetURI.parse(uri)
         | 
| 365 121 |  | 
| 366 | 
            -
             | 
| 367 | 
            -
                     | 
| 368 | 
            -
             | 
| 369 | 
            -
                    # If there are any processors to run on the pathname, use
         | 
| 370 | 
            -
                    # `BundledAsset`. Otherwise use `StaticAsset` and treat is as binary.
         | 
| 371 | 
            -
                    if attributes_for(pathname).processors.any?
         | 
| 372 | 
            -
                      if options[:bundle] == false
         | 
| 373 | 
            -
                        circular_call_protection(pathname.to_s) do
         | 
| 374 | 
            -
                          ProcessedAsset.new(index, logical_path, pathname)
         | 
| 375 | 
            -
                        end
         | 
| 376 | 
            -
                      else
         | 
| 377 | 
            -
                        BundledAsset.new(index, logical_path, pathname)
         | 
| 378 | 
            -
                      end
         | 
| 379 | 
            -
                    else
         | 
| 380 | 
            -
                      StaticAsset.new(index, logical_path, pathname)
         | 
| 122 | 
            +
                    # Internal assertion, should be routed through build_asset_by_uri
         | 
| 123 | 
            +
                    unless id = params.delete(:id)
         | 
| 124 | 
            +
                      raise ArgumentError, "expected uri to have an id: #{uri}"
         | 
| 381 125 | 
             
                    end
         | 
| 382 | 
            -
                  end
         | 
| 383 126 |  | 
| 384 | 
            -
             | 
| 385 | 
            -
                    "#{path}:#{options[:bundle] ? '1' : '0'}"
         | 
| 386 | 
            -
                  end
         | 
| 127 | 
            +
                    asset = build_asset_by_uri(AssetURI.build(path, params))
         | 
| 387 128 |  | 
| 388 | 
            -
             | 
| 389 | 
            -
             | 
| 390 | 
            -
                    calls = Thread.current[:sprockets_circular_calls] ||= Set.new
         | 
| 391 | 
            -
                    if calls.include?(path)
         | 
| 392 | 
            -
                      raise CircularDependencyError, "#{path} has already been required"
         | 
| 129 | 
            +
                    if id && asset[:id] != id
         | 
| 130 | 
            +
                      raise VersionNotFound, "could not find specified id: #{id}"
         | 
| 393 131 | 
             
                    end
         | 
| 394 | 
            -
             | 
| 395 | 
            -
                     | 
| 396 | 
            -
                  ensure
         | 
| 397 | 
            -
                    Thread.current[:sprockets_circular_calls] = nil if reset
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                    asset
         | 
| 398 134 | 
             
                  end
         | 
| 399 135 |  | 
| 400 | 
            -
                  def  | 
| 401 | 
            -
                     | 
| 136 | 
            +
                  def build_asset_by_uri(uri)
         | 
| 137 | 
            +
                    filename, params = AssetURI.parse(uri)
         | 
| 402 138 |  | 
| 403 | 
            -
                     | 
| 404 | 
            -
             | 
| 139 | 
            +
                    # Internal assertion, should be routed through build_asset_by_id_uri
         | 
| 140 | 
            +
                    if params.key?(:id)
         | 
| 141 | 
            +
                      raise ArgumentError, "expected uri to have no id: #{uri}"
         | 
| 405 142 | 
             
                    end
         | 
| 406 143 |  | 
| 407 | 
            -
                     | 
| 408 | 
            -
                     | 
| 409 | 
            -
             | 
| 410 | 
            -
             | 
| 411 | 
            -
             | 
| 412 | 
            -
             | 
| 144 | 
            +
                    type = params[:type]
         | 
| 145 | 
            +
                    load_path, logical_path = paths_split(self.paths, filename)
         | 
| 146 | 
            +
             | 
| 147 | 
            +
                    if !file?(filename)
         | 
| 148 | 
            +
                      raise FileNotFound, "could not find file: #{filename}"
         | 
| 149 | 
            +
                    elsif type && !resolve_path_transform_type(filename, type)
         | 
| 150 | 
            +
                      raise ConversionError, "could not convert to type: #{type}"
         | 
| 151 | 
            +
                    elsif !load_path
         | 
| 152 | 
            +
                      raise FileOutsidePaths, "#{filename} is no longer under a load path: #{self.paths.join(', ')}"
         | 
| 413 153 | 
             
                    end
         | 
| 414 154 |  | 
| 415 | 
            -
                     | 
| 416 | 
            -
             | 
| 155 | 
            +
                    logical_path, file_type, engine_extnames = parse_path_extnames(logical_path)
         | 
| 156 | 
            +
                    logical_path = normalize_logical_path(logical_path)
         | 
| 417 157 |  | 
| 418 | 
            -
             | 
| 419 | 
            -
             | 
| 420 | 
            -
             | 
| 421 | 
            -
             | 
| 422 | 
            -
                       | 
| 423 | 
            -
             | 
| 424 | 
            -
             | 
| 425 | 
            -
                        if filter.arity == 1
         | 
| 426 | 
            -
                          filter.call(logical_path)
         | 
| 427 | 
            -
                        else
         | 
| 428 | 
            -
                          filter.call(logical_path, filename.to_s)
         | 
| 429 | 
            -
                        end
         | 
| 430 | 
            -
                      else
         | 
| 431 | 
            -
                        File.fnmatch(filter.to_s, logical_path)
         | 
| 432 | 
            -
                      end
         | 
| 433 | 
            -
                    end
         | 
| 434 | 
            -
                  end
         | 
| 158 | 
            +
                    asset = {
         | 
| 159 | 
            +
                      uri: uri,
         | 
| 160 | 
            +
                      load_path: load_path,
         | 
| 161 | 
            +
                      filename: filename,
         | 
| 162 | 
            +
                      name: logical_path,
         | 
| 163 | 
            +
                      logical_path: logical_path
         | 
| 164 | 
            +
                    }
         | 
| 435 165 |  | 
| 436 | 
            -
             | 
| 437 | 
            -
             | 
| 438 | 
            -
             | 
| 439 | 
            -
                      MultiJson.load(obj)
         | 
| 166 | 
            +
                    if type
         | 
| 167 | 
            +
                      asset[:content_type] = type
         | 
| 168 | 
            +
                      asset[:logical_path] += mime_types[type][:extensions].first
         | 
| 440 169 | 
             
                    end
         | 
| 441 | 
            -
             | 
| 442 | 
            -
                     | 
| 443 | 
            -
                       | 
| 170 | 
            +
             | 
| 171 | 
            +
                    processed_processors = unwrap_preprocessors(file_type) +
         | 
| 172 | 
            +
                      unwrap_engines(engine_extnames).reverse +
         | 
| 173 | 
            +
                      unwrap_transformer(file_type, type) +
         | 
| 174 | 
            +
                      unwrap_postprocessors(type)
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                    bundled_processors = params[:skip_bundle] ? [] : unwrap_bundle_processors(type)
         | 
| 177 | 
            +
             | 
| 178 | 
            +
                    processors = bundled_processors.any? ? bundled_processors : processed_processors
         | 
| 179 | 
            +
                    processors += unwrap_encoding_processors(params[:encoding])
         | 
| 180 | 
            +
             | 
| 181 | 
            +
                    if processors.any?
         | 
| 182 | 
            +
                      asset.merge!(process(
         | 
| 183 | 
            +
                        [method(:read_input)] + processors,
         | 
| 184 | 
            +
                        asset[:uri],
         | 
| 185 | 
            +
                        asset[:filename],
         | 
| 186 | 
            +
                        asset[:load_path],
         | 
| 187 | 
            +
                        asset[:name],
         | 
| 188 | 
            +
                        asset[:content_type]
         | 
| 189 | 
            +
                      ))
         | 
| 190 | 
            +
                    else
         | 
| 191 | 
            +
                      asset.merge!({
         | 
| 192 | 
            +
                        encoding: Encoding::BINARY,
         | 
| 193 | 
            +
                        length: self.stat(asset[:filename]).size,
         | 
| 194 | 
            +
                        digest: digest_class.file(asset[:filename]).hexdigest,
         | 
| 195 | 
            +
                        metadata: {}
         | 
| 196 | 
            +
                      })
         | 
| 444 197 | 
             
                    end
         | 
| 198 | 
            +
             | 
| 199 | 
            +
                    metadata = asset[:metadata]
         | 
| 200 | 
            +
                    metadata[:dependency_paths] = Set.new(metadata[:dependency_paths]).merge([asset[:filename]])
         | 
| 201 | 
            +
                    metadata[:dependency_digest] = dependencies_hexdigest(metadata[:dependency_paths])
         | 
| 202 | 
            +
             | 
| 203 | 
            +
                    asset[:id]  = Utils.hexdigest(asset)
         | 
| 204 | 
            +
                    asset[:uri] = AssetURI.build(filename, params.merge(id: asset[:id]))
         | 
| 205 | 
            +
             | 
| 206 | 
            +
                    # TODO: Avoid tracking Asset mtime
         | 
| 207 | 
            +
                    asset[:mtime] = metadata[:dependency_paths].map { |p| stat(p).mtime.to_i }.max
         | 
| 208 | 
            +
             | 
| 209 | 
            +
                    asset
         | 
| 445 210 | 
             
                  end
         | 
| 446 211 | 
             
              end
         | 
| 447 212 | 
             
            end
         |