pax_global_header00006660000000000000000000000064133122202200014475gustar00rootroot0000000000000052 comment=2f7b7e5e67f47c32a2d637b7e90dfa5ecf922eb3 sprockets-3.7.2/000077500000000000000000000000001331222022000135235ustar00rootroot00000000000000sprockets-3.7.2/.gitattributes000066400000000000000000000000701331222022000164130ustar00rootroot00000000000000test/fixtures/**/*.png binary test/fixtures/**/* eol=lf sprockets-3.7.2/.gitignore000066400000000000000000000001021331222022000155040ustar00rootroot00000000000000*.rbc .bundle Gemfile.lock README.html doc docs pkg tmp .DS_Store sprockets-3.7.2/.travis.yml000066400000000000000000000012361331222022000156360ustar00rootroot00000000000000language: ruby cache: bundler sudo: false rvm: - 2.0.0 - 2.1 - 2.2 - 2.3.1 - 2.4.0-rc1 matrix: include: test_isolated matrix: include: - rvm: 1.9.3 gemfile: gemfiles/Gemfile-1.9 - rvm: 2.2 script: bundle exec rake test_isolated notifications: email: false irc: on_success: change on_failure: always channels: - "irc.freenode.org#rails-contrib" campfire: on_success: change on_failure: always rooms: - secure: "bJyiK4EXGfm0EhAId/QqIEdhPCx8BjxUKvx1h0+wgrsUm8BDoEN7tg2wqoGWU2KfzqLdx77wZVQXbmksOgmNcMGKJed5uNNMpAG4B+AQYTEX0odFRgOZKdkMtypga9CNIkKVgeSKhd6BY+g2AV6wvJ0Jq056uXpGkqK5OEFOpQc=" sprockets-3.7.2/CHANGELOG.md000066400000000000000000000211241331222022000153340ustar00rootroot00000000000000**3.7.2** (June 19, 2018) * Security release for [CVE-2018-3760](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3760). **3.7.1** (December 19, 2016) * Ruby 2.4 support for Sprockets 3. **3.7.0** (July 21, 2016) * Deprecated interfaces now emit deprecation warnings #345 **3.6.3** (July 1, 2016) * Faster asset lookup in large directories #336 * Faster PathUtils.match_path_extname https://github.com/rails/sprockets/commit/697269cf81e5261fdd7072e32bd489403027fd7e * Fixed uglifier comment stripping #326 * Error messages now show load path info #313 **3.6.2** (June 21, 2016) * More performance improvements. **3.6.1** (June 17, 2016) * Some performance improvements. **3.6.0** (April 6, 2016) * Add `Manifest#find_sources` to return the source of the compiled assets. * Fix the list of compressable mime types. * Improve performance of the `FileStore` cache. **3.5.2** (December 8, 2015) * Fix JRuby bug with concurrent-ruby. * Fix disabling gzip generation in cached environments. **3.5.1** (December 5, 2015) * Fix gzip asset generation for assets already on disk. **3.5.0** (December 3, 2015) * Reintroduce Gzip file generation for non-binary assets. **3.4.1** (November 25, 2015) * PathUtils::Entries will no longer error on an empty directory. **3.4.0** (October 5, 2015) * Expose method to override the sass cache in the SassProcessor. **3.3.5** (September 25, 2015) * Fix bug related to absolute path being reintroduced into history cache #141. **3.3.4** (September 1, 2015) * Relative cache contents now work with windows. **3.3.3** (August 21, 2015) * Remove more absolute paths from cache contents. **3.3.2** (August 19, 2015) * Fix cache contents to use relative paths instead of absolute paths. **3.3.1** (August 15, 2015) * Fix legacy Tilt integration when locals is required argument. **3.3.0** (August 12, 2015) * Change internal cache key to use relative asset paths instead of absolute paths. **3.2.0** (June 2, 2015) * Updated SRI integrity to align with spec changes * Deprecated Manifest integrity attribute * Cleanup concatenating JS sources with newlines **3.1.0** (May 10, 2015) * Removed "index" logical path normalization. Asset#logical_path is always the full logical path to the index file. * Fixed static asset mtimes * Fix manifest cleanup by age * Removed redundant minifier level cache * Updated SRI format according to spec changes **3.0.3** (April 27, 2015) * Fix static asset mtime fallback * Only warn when specified asset version can not be loaded. **3.0.2** (April 22, 2015) * Ensure legacy Tilt handlers return String class data. Fixes issues with Haml Tilt handler. * Type check and improve error messages raised on bad processor returned results. * Improve error message for relative paths not under load path. * Changed HTML encoding fallback from ISO-8859-1 to default external. * Avoid falling back to 0 mtimes which may cause warnings with tar **3.0.1** (April 14, 2015) * Fixed `Context#depend_on` with paths outside the load path **3.0.0** (April 12, 2015) [Guide to upgrading from Sprockets 2.x to 3.x](https://github.com/rails/sprockets/blob/3.x/UPGRADING.md) * New processor API. Tilt interface is deprecated. * Improved file store caching backend. * MIME Types now accept charset custom charset detecters. Improves support for UTF-16/32 files. * Environment#version no longer affects asset digests. Only used for busting the asset cache. * Removed builtin support for LESS. * Removed `//= include` directive support. * Deprecated `BundledAsset#to_a`. Use `BundledAsset#included` to access debugging subcomponents. * Support circular dependencies. For parity with ES6 modules. * Manifest compilation will no longer generate .gz files by default. [Mixing Content-Encoding and ETags is just a bad idea](https://issues.apache.org/bugzilla/show_bug.cgi?id=39727) * Added linked or referenced assets. When an asset is compiled, any of its links will be compiled as well. * Introduce some limitations around enumerating all logical paths. 4.x will deprecate it and favor linked manifests for compliation. * Add Asset integrity attribute for Subresource Integrity * Default digest changed to SHA256. Configuring `digest_class` is deprecated. * Rename `Asset#digest` to `Asset#hexdigest`. `Asset#digest` is deprecated and will return a raw byte String in 4.x. * Added transitional compatibility flag to `Environment#resolve(path, compat: true)`. 2.x mode operates with `compat: true` and 4.x with `compat: false` * `manifest-abc123.json` renamed to `.sprockets-abc123.json` **2.12.3** (October 28, 2014) * Security: Fix directory traversal bug in development mode server. **2.12.2** (September 5, 2014) * Ensure internal asset lookups calls are still restricted to load paths within asset compiles. Though, you should not depend on internal asset resolves to be completely restricted for security reasons. Assets themselves should be considered full scripting environments with filesystem access. **2.12.1** (April 17, 2014) * Fix making manifest target directory when its different than the output directory. **2.12.0** (March 13, 2014) * Avoid context reference in SassImporter hack so its Marshallable. Fixes issues with Sass 3.3.x. **2.11.0** (February 19, 2014) * Cache store must now be an LRU implementation. * Default digest changed to SHA1. To continue using MD5. `env.digest_class = Digest::MD5`. **2.10.0** (May 24, 2013) * Support for `bower.json` **2.9.3** (April 20, 2013) * Fixed sass caching bug **2.9.2** (April 8, 2013) * Improve file freshness check performance * Directive processor encoding fixes **2.9.1** (April 6, 2013) * Support for Uglifier 2.x **2.9.0** (February 25, 2013) * Write out gzipped variants of bundled assets. **2.8.2** (December 10, 2012) * Fixed top level Sass constant references * Fixed manifest logger when environment is disabled **2.8.1** (October 31, 2012) * Fixed Sass importer bug **2.8.0** (October 16, 2012) * Allow manifest location to be separated from output directory * Pass logical path and absolute path to each_logical_path iterator **2.7.0** (October 10, 2012) * Added --css-compressor and --js-compressor command line flags * Added css/js compressor shorthand * Change default manifest.json filename to be a randomized manifest-16HEXBYTES.json * Allow nil environment to be passed to manifest * Allow manifest instance to be set on rake task **2.6.0** (September 19, 2012) * Added bower component.json require support **2.5.0** (September 4, 2012) * Fixed Ruby 2.0 RegExp warning * Provide stubbed implementation of context *_path helpers * Add SassCompressor **2.4.5** (July 10, 2012) * Tweaked some logger levels **2.4.4** (July 2, 2012) * Canonicalize logical path extensions * Check absolute paths passed to depend_on **2.4.3** (May 16, 2012) * Exposed :sprockets in sass options * Include dependency paths in asset mtime **2.4.2** (May 7, 2012) * Fixed MultiJson feature detect **2.4.1** (April 26, 2012) * Fixed MultiJson API change * Fixed gzip mtime **2.4.0** (March 27, 2012) * Added global path registry * Added global processor registry **2.3.2** (March 26, 2012) * Fix Context#logical_path with dots **2.3.1** (February 11, 2012) * Added bytesize to manifest * Added Asset#bytesize alias * Security: Check path for forbidden access after unescaping **2.3.0** (January 16, 2012) * Added special Sass importer that automatically tracks any `@import`ed files. **2.2.0** (January 10, 2012) * Added `sprockets` command line utility. * Added rake/sprocketstask. * Added json manifest log of compiled assets. * Added `stub` directive that allows you to exclude files from the bundle. * Added per environment external encoding (Environment#default_external_encoding). Defaults to UTF-8. Fixes issues where LANG is not set correctly and Rubys default external is set to ASCII. **2.1.2** (November 20, 2011) * Disabled If-Modified-Since server checks. Fixes some browser caching issues when serving the asset body only. If-None-Match caching is sufficient. **2.1.1** (November 18, 2011) * Fix windows absolute path check bug. **2.1.0** (November 11, 2011) * Directive comment lines are now turned into empty lines instead of removed. This way line numbers in CoffeeScript syntax errors are correct. * Performance and caching bug fixes. **2.0.3** (October 17, 2011) * Detect format extensions from right to left. * Make JST namespace configurable. **2.0.2** (October 4, 2011) * Fixed loading stale cache from bundler gems. **2.0.1** (September 30, 2011) * Fixed bug with fingerprinting file names with multiple dots. * Decode URIs as default internal. * Fix symlinked asset directories. **2.0.0** (August 29, 2011) * Initial public release. sprockets-3.7.2/Gemfile000066400000000000000000000003261331222022000150170ustar00rootroot00000000000000source "https://rubygems.org" gemspec if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.2.2") gem 'rack', '< 2.0' end if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.0") gem 'json', '< 2.0' end sprockets-3.7.2/LICENSE000066400000000000000000000021011331222022000145220ustar00rootroot00000000000000Copyright (c) 2014 Sam Stephenson Copyright (c) 2014 Joshua Peek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. sprockets-3.7.2/README.md000066400000000000000000000440221331222022000150040ustar00rootroot00000000000000# Sprockets: Rack-based asset packaging Sprockets is a Ruby library for compiling and serving web assets. It features declarative dependency management for JavaScript and CSS assets, as well as a powerful preprocessor pipeline that allows you to write assets in languages like CoffeeScript, Sass and SCSS. ## Installation Install Sprockets from RubyGems: ``` sh $ gem install sprockets ``` Or include it in your project's `Gemfile` with Bundler: ``` ruby gem 'sprockets', '~> 3.0' ``` ## Using sprockets For most people interested in using sprockets you will want to see [End User Asset Generation](guides/end_user_asset_generation.md) guide. This contains information about sprocket's directive syntax, and default processing behavior. If you are a framework developer that is using sprockets, see [Building an Asset Processing Framework](guides/building_an_asset_processing_framework.md). If you are a library developer who is extending the functionality of sprockets, see [Extending Sprockets](guides/extending_sprockets.md). Below is a disjointed mix of documentation for all three of these roles. Eventually they will be moved to an appropriate guide, for now the recommended way to consume documentation is to view the appropriate guide first and then supplement with docs from the README. ## Behavior ### Index files are proxies for folders In sprockets index files such as `index.js` or `index.css` files inside of a folder will generate a file with the folder's name. So if you have a `foo/index.js` file it will compile down to `foo.js`. This is similar to NPM's behavior of using [folders as modules](https://nodejs.org/api/modules.html#modules_folders_as_modules). It is also somewhat similar to the way that a file in `public/my_folder/index.html` can be reached by a request to `/my_folder`. This means that you cannot directly use an index file. For example this would not work: ``` <%= asset_path("foo/index.js") %> ``` Instead you would need to use: ``` <%= asset_path("foo.js") %> ``` Why would you want to use this behavior? It is common behavior where you might want to include an entire directory of files in a top level javascript. You can do this in sprockets using `require_tree .` ``` //= require_tree . ``` This has the problem that files are required alphabetically. If your directory has `jquery-ui.js` and `jquery.min.js` then sprockets will require `jquery-ui.js` before `jquery` is required which won't work (because jquery-ui depends on jquery). Previously the only way to get the correct ordering would be to rename your files, something like `0-jquery-ui.js`. Instead of doing that you can use an index file. For example, if you have an `application.js` and want all the files in the `foo/` folder you could do this: ``` //= require foo.js ``` Then create a file `foo/index.js` that requires all the files in that folder in any order you want: ``` //= require foo.min.js //= require foo-ui.js ``` Now in your `application.js` will correctly load the `foo.min.js` before `foo-ui.js`. If you used `require_tree` it would not work correctly. ## Understanding the Sprockets Environment You'll need an instance of the `Sprockets::Environment` class to access and serve assets from your application. Under Rails 4.0 and later, `YourApp::Application.assets` is a preconfigured `Sprockets::Environment` instance. For Rack-based applications, create an instance in `config.ru`. The Sprockets `Environment` has methods for retrieving and serving assets, manipulating the load path, and registering processors. It is also a Rack application that can be mounted at a URL to serve assets over HTTP. ### The Load Path The *load path* is an ordered list of directories that Sprockets uses to search for assets. In the simplest case, a Sprockets environment's load path will consist of a single directory containing your application's asset source files. When mounted, the environment will serve assets from this directory as if they were static files in your public root. The power of the load path is that it lets you organize your source files into multiple directories -- even directories that live outside your application -- and combine those directories into a single virtual filesystem. That means you can easily bundle JavaScript, CSS and images into a Ruby library or [Bower](http://bower.io) package and import them into your application. #### Manipulating the Load Path To add a directory to your environment's load path, use the `append_path` and `prepend_path` methods. Directories at the beginning of the load path have precedence over subsequent directories. ``` ruby environment = Sprockets::Environment.new environment.append_path 'app/assets/javascripts' environment.append_path 'lib/assets/javascripts' environment.append_path 'vendor/assets/bower_components' ``` In general, you should append to the path by default and reserve prepending for cases where you need to override existing assets. ### Accessing Assets Once you've set up your environment's load path, you can mount the environment as a Rack server and request assets via HTTP. You can also access assets programmatically from within your application. #### Logical Paths Assets in Sprockets are always referenced by their *logical path*. The logical path is the path of the asset source file relative to its containing directory in the load path. For example, if your load path contains the directory `app/assets/javascripts`:
Asset source file Logical path
app/assets/javascripts/application.js application.js
app/assets/javascripts/models/project.js models/project.js
In this way, all directories in the load path are merged to create a virtual filesystem whose entries are logical paths. #### Serving Assets Over HTTP When you mount an environment, all of its assets are accessible as logical paths underneath the *mount point*. For example, if you mount your environment at `/assets` and request the URL `/assets/application.js`, Sprockets will search your load path for the file named `application.js` and serve it. Under Rails 4.0 and later, your Sprockets environment is automatically mounted at `/assets`. If you are using Sprockets with a Rack application, you will need to mount the environment yourself. A good way to do this is with the `map` method in `config.ru`: ``` ruby require 'sprockets' map '/assets' do environment = Sprockets::Environment.new environment.append_path 'app/assets/javascripts' environment.append_path 'app/assets/stylesheets' run environment end map '/' do run YourRackApp end ``` #### Accessing Assets Programmatically You can use the `find_asset` method (aliased as `[]`) to retrieve an asset from a Sprockets environment. Pass it a logical path and you'll get a `Sprockets::Asset` instance back: ``` ruby environment['application.js'] # => # ``` Call `to_s` on the resulting asset to access its contents, `length` to get its length in bytes, `mtime` to query its last-modified time, and `filename` to get its full path on the filesystem. ## Using Processors Asset source files can be written in another format, like SCSS or CoffeeScript, and automatically compiled to CSS or JavaScript by Sprockets. Processors that convert a file from one format to another are called *transformers*. ### Minifying Assets Several JavaScript and CSS minifiers are available through shorthand. ``` ruby environment.js_compressor = :uglify environment.css_compressor = :scss ``` ### Styling with Sass and SCSS [Sass](http://sass-lang.com/) is a language that compiles to CSS and adds features like nested rules, variables, mixins and selector inheritance. If the `sass` gem is available to your application, you can use Sass to write CSS assets in Sprockets. Sprockets supports both Sass syntaxes. For the original whitespace-sensitive syntax, use the extension `.sass`. For the new SCSS syntax, use the extension `.scss`. ### Scripting with CoffeeScript [CoffeeScript](http://jashkenas.github.com/coffee-script/) is a language that compiles to the "good parts" of JavaScript, featuring a cleaner syntax with array comprehensions, classes, and function binding. If the `coffee-script` gem is available to your application, you can use CoffeeScript to write JavaScript assets in Sprockets. Note that the CoffeeScript compiler is written in JavaScript, and you will need an [ExecJS](https://github.com/rails/execjs)-supported runtime on your system to invoke it. To write JavaScript assets with CoffeeScript, use the extension `.coffee`. ### JavaScript Templating with EJS and Eco Sprockets supports *JavaScript templates* for client-side rendering of strings or markup. JavaScript templates have the special format extension `.jst` and are compiled to JavaScript functions. When loaded, a JavaScript template function can be accessed by its logical path as a property on the global `JST` object. Invoke a template function to render the template as a string. The resulting string can then be inserted into the DOM. ```
Hello, <%= name %>!
// application.js //= require templates/hello $("#hello").html(JST["templates/hello"]({ name: "Sam" })); ``` Sprockets supports two JavaScript template languages: [EJS](https://github.com/sstephenson/ruby-ejs), for embedded JavaScript, and [Eco](https://github.com/sstephenson/ruby-eco), for embedded CoffeeScript. Both languages use the familiar `<% … %>` syntax for embedding logic in templates. If the `ejs` gem is available to your application, you can use EJS templates in Sprockets. EJS templates have the extension `.jst.ejs`. If the `eco` gem is available to your application, you can use [Eco templates](https://github.com/sstephenson/eco) in Sprockets. Eco templates have the extension `.jst.eco`. Note that the `eco` gem depends on the CoffeeScript compiler, so the same caveats apply as outlined above for the CoffeeScript engine. ### Invoking Ruby with ERB Sprockets provides an ERB engine for preprocessing assets using embedded Ruby code. Append `.erb` to a CSS or JavaScript asset's filename to enable the ERB engine. Ruby code embedded in an asset is evaluated in the context of a `Sprockets::Context` instance for the given asset. Common uses for ERB include: - embedding another asset as a Base64-encoded `data:` URI with the `asset_data_uri` helper - inserting the URL to another asset, such as with the `asset_path` helper provided by the Sprockets Rails plugin - embedding other application resources, such as a localized string database, in a JavaScript asset via JSON - embedding version constants loaded from another file See the [Helper Methods](lib/sprockets/context.rb) section for more information about interacting with `Sprockets::Context` instances via ERB. ## Managing and Bundling Dependencies You can create *asset bundles* -- ordered concatenations of asset source files -- by specifying dependencies in a special comment syntax at the top of each source file. Sprockets reads these comments, called *directives*, and processes them to recursively build a dependency graph. When you request an asset with dependencies, the dependencies will be included in order at the top of the file. ### The Directive Processor Sprockets runs the *directive processor* on each CSS and JavaScript source file. The directive processor scans for comment lines beginning with `=` in comment blocks at the top of the file. ``` js //= require jquery //= require jquery-ui //= require backbone //= require_tree . ``` The first word immediately following `=` specifies the directive name. Any words following the directive name are treated as arguments. Arguments may be placed in single or double quotes if they contain spaces, similar to commands in the Unix shell. **Note**: Non-directive comment lines will be preserved in the final asset, but directive comments are stripped after processing. Sprockets will not look for directives in comment blocks that occur after the first line of code. #### Supported Comment Types The directive processor understands comment blocks in three formats: ``` css /* Multi-line comment blocks (CSS, SCSS, JavaScript) *= require foo */ ``` ``` js // Single-line comment blocks (SCSS, JavaScript) //= require foo ``` ``` coffee # Single-line comment blocks (CoffeeScript) #= require foo ``` ### Sprockets Directives You can use the following directives to declare dependencies in asset source files. For directives that take a *path* argument, you may specify either a logical path or a relative path. Relative paths begin with `./` and reference files relative to the location of the current file. #### The `require` Directive `require` *path* inserts the contents of the asset source file specified by *path*. If the file is required multiple times, it will appear in the bundle only once. ### The `require_directory` Directive ### `require_directory` *path* requires all source files of the same format in the directory specified by *path*. Files are required in alphabetical order. #### The `require_tree` Directive `require_tree` *path* works like `require_directory`, but operates recursively to require all files in all subdirectories of the directory specified by *path*. #### The `require_self` Directive `require_self` tells Sprockets to insert the body of the current source file before any subsequent `require` directives. #### The `link` Directive `link` *path* declares a dependency on the target *path* and adds it to a list of subdependencies to automatically be compiled when the asset is written out to disk. For an example, in a CSS file you might reference an external image that always needs to be compiled along with the css file. ``` css /*= link "logo.png" */ .logo { background-image: url(logo.png) } ``` However, if you use a `asset-path` or `asset-url` SCSS helper, these links will automatically be defined for you. ``` css .logo { background-image: asset-url("logo.png") } ``` #### The `depend_on` Directive `depend_on` *path* declares a dependency on the given *path* without including it in the bundle. This is useful when you need to expire an asset's cache in response to a change in another file. #### The `depend_on_asset` Directive `depend_on_asset` *path* works like `depend_on`, but operates recursively reading the file and following the directives found. This is automatically implied if you use `link`, so consider if it just makes sense using `link` instead of `depend_on_asset`. #### The `stub` Directive `stub` *path* allows dependency to be excluded from the asset bundle. The *path* must be a valid asset and may or may not already be part of the bundle. `stub` should only be used at the top level bundle, not within any subdependencies. ## Processor Interface Sprockets 2.x was originally design around [Tilt](https://github.com/rtomayko/tilt)'s engine interface. However, starting with 3.x, a new interface has been introduced deprecating Tilt. Similar to Rack, a processor is a any "callable" (an object that responds to `call`). This maybe a simple Proc or a full class that defines a `def self.call(input)` method. The `call` method accepts an `input` Hash and returns a Hash of metadata. Also see [`Sprockets::ProcessorUtils`](https://github.com/rails/sprockets/blob/master/lib/sprockets/processor_utils.rb) for public helper methods. ### input Hash The `input` Hash defines the following public fields. * `:data` - String asset contents * `:environment` - Current `Sprockets::Environment` instance. * `:cache` - A `Sprockets::Cache` instance. See [`Sprockets::Cache#fetch`](https://github.com/rails/sprockets/blob/master/lib/sprockets/cache.rb). * `:uri` - String Asset URI. * `:filename` - String full path to original file. * `:load_path` - String current load path for filename. * `:name` - String logical path for filename. * `:content_type` - String content type of the output asset. * `:metadata` - Hash of processor metadata. ``` ruby def self.call(input) input[:cache].fetch("my:cache:key:v1") do # Remove all semicolons from source input[:data].gsub(";", "") end end ``` ### return Hash The processor should return metadata `Hash`. With the exception of the `:data` key, the processor can store arbitrary JSON valid values in this Hash. The data will be stored and exposed on `Asset#metadata`. The returned `:data` replaces the assets `input[:data]` to the next processor in the chain. Returning a `String` is shorthand for returning `{ data: str }`. And returning `nil` is shorthand for a no-op where the input data is not transformed, `{ data: input[:data] }`. ### metadata The metadata Hash provides an open format for processors to extend the pipeline processor. Internally, built-in processors use it for passing data to each other. * `:required` - A `Set` of String Asset URIs that the Bundle processor should concatenate together. * `:stubbed` - A `Set` of String Asset URIs that will be omitted from the `:required` set. * `:links` - A `Set` of String Asset URIs that should be compiled along with this asset. * `:dependencies` - A `Set` of String Cache URIs that should be monitored for caching. ``` ruby def self.call(input) # Any metadata may start off as nil, so initialize it the value required = Set.new(input[:metadata][:required]) # Manually add "foo.js" asset uri to our bundle required << input[:environment].resolve("foo.js") { required: required } end ``` ## Development ### Contributing The Sprockets source code is [hosted on GitHub](https://github.com/rails/sprockets). You can check out a copy of the latest code using Git: $ git clone https://github.com/rails/sprockets If you've found a bug or have a question, please open an issue on the [Sprockets issue tracker](https://github.com/rails/sprockets/issues). Or, clone the Sprockets repository, write a failing test case, fix the bug and submit a pull request. ### Version History Please see the [CHANGELOG](https://github.com/rails/sprockets/tree/master/CHANGELOG.md) ## License Copyright © 2014 Sam Stephenson <> Copyright © 2014 Joshua Peek <> Sprockets is distributed under an MIT-style license. See LICENSE for details. sprockets-3.7.2/Rakefile000066400000000000000000000004241331222022000151700ustar00rootroot00000000000000require "rake/testtask" require "bundler/gem_tasks" task :default => :test Rake::TestTask.new do |t| t.libs << "test" t.warning = true end task :test_isolated do Dir["test/test*.rb"].each do |fn| ruby "-Ilib:test", "-w", fn abort unless $?.success? end end sprockets-3.7.2/UPGRADING.md000066400000000000000000000241511331222022000153700ustar00rootroot00000000000000# Guide to upgrading from Sprockets 2.x to 3.x Even though its a major release, Sprockets 3.x should be fairly API compatible with 2.x unless explicitly noted in the CHANGELOG. For the most part, the application facing APIs have remained the same with the majority of the changes at the extension layer. So you shouldn't have to change much application code, but you should verify that all the sprockets extension gems you are using are compatible with 3.x. ## Application Changes ### public/assets/manifest-abc123.json location JSON manifests are now written out to `.sprockets-manifest-abc123.json` to prevent collisions with assets actually called `manifest`. If any old manifests exists they will automatically be renamed. Just note if you were depending on the `manifests-abc123.json` name in a deployment related task, you'll see this new file showing up. ### Preference for asset manifest and links Previously, Sprockets had no idea what files you wanted to statically compile and how they related to each other. Now assets have the concept of referencing each with "links". This provides a composable way for assets subresources to be declared. ``` css /* homepage.css */ .logo { background: url("logo.png") } ``` Typically you have these subresource relations in css files to other images. You'd have to tell Sprockets to compile both the css and image. But now when you use any of the asset helpers in ERB or SCSS, a link relationship to created between the two assets. ``` css .logo { background: url(<%= asset_url("logo.png") %>) } ``` Its understood that whenever `homepage.css` is compiled, you'll need `logo.png` too. Most of the time you won't have to think up declaring links, helpers will do that for you. But there are programmatic APIs for setting up links if you're doing something custom. ``` css /* A comment directive or erb call can be used to declare a link relationship */ /*= link logo.png */ <%= link_asset "logo.png" %> .logo {} ``` Since links are composable, you can use them to define a single "manifest" file that links to ever asset you need in production. ``` js // app/assets/manifest.js // // JS bundles //= link ./javascripts/standalone-jquery.js //= link ./javascripts/application.js //= link ./javascripts/settings.js // // CSS bundles //= link ./stylesheets/application.css //= link ./stylesheets/settings.css // // Pull in all app/assets/images/ since app/views may link to them //= link_tree ./images ``` **Caution** Unlike `require` directives, links should have an explicit content type or file extension. When using `link_directory` or `link_tree` prefer setting a format as well. ``` js // A mime type or file extension can be given as a second parameter to // link_directory or link_tree // //= link_directory ./scripts .js //= link_tree ./styles text/css ``` Then compiling `manifest` will ensure all the subresources are compiled as well. ``` ruby config.assets.precompile = ["manifest.js"] ``` ### Prefer just `foo.coffee` and `foo.scss` Instead of the longer `foo.js.coffee` and `foo.css.scss`. This shorthand works in 2.x but is preferred going forward. ### Rev `version` less often Many load path changing caching bugs have been fixed and processors can now partipate in asset cache invalidation. So when you upgrade CoffeeScript, it will automatically bust old changes. You'll need to be sure you're running the latest versions of any Sprockets extensions so they opt into these new cache APIs. ### Removed `//= include` directive You can replace this with ERB usage `<%= environment.find_asset("foo") %>`. This will also allow you to put the contents anywhere you want in the file. ## Extension Changes ### Processor Interface If you're a Sprockets plugin author you should definitely take some time to migrate to the new processor API. You can relax for now since 3.x will still support the old Tilt interface. 4.x will be the hard break away. Hopefully our existing extensions still work on both 2.x and 3.x (unless you're using private apis or monkey patching things). So whats wrong with Tilt, why bother? It was probably a good decision at the time, but we've out grown the constraints of the Tilt template interface. After all, it was primarily designed for dynamic HTML template engines, not assets like JS and CSS or binary assets like images. Sprockets would like to have other metadata passed between processors besides simple Strings. Passing source maps was one of the primary motivators. Instead of a Tilt template interface, we now have a uniform Processor interface across every part of the pipeline. Similar to Rack, a processor is a any "callable" (an object that responds to `call`). This maybe a simple Proc or a full class that defines a `def self.call(input)` method. The `call` method accepts an `input` Hash and returns a Hash of metadata. If you just care about modifying the input data, the simplest processor looks like ``` ruby proc do |input| # Take input data, remove all semicolons and return a string input[:data].gsub(";", "") end ``` A `proc` works well for quick user defined processors, but you might want to use a full class for your extension. ``` ruby class MyProcessor def initialize(options = {}) @options = options end def call(input) end end # A initializer pattern can allow users to configure application specific # options for your processor MyProcessor.new(style: :minimal) ``` `call(input)` is the only required method to implement, you can also provide a `cache_key` method. This allows the processor to bust asset caches after a library upgrade or configuration changes. ``` ruby class MyProcessor def initialize(options = {}) @options = options end def cache_key ['3', @options] end def call(input) end end ``` `cache_key` may return any simple JSON serializable value to use to differentiate caches. This may just be a static version identifier you change every gem release or configuration options declared on setup. Heres a pretty standard processor boilerplate thats used internally for Sprockets. ``` ruby class MyProcessor VERSION = '3' def self.instance @instance ||= new end def self.call(input) instance.call(input) end def self.cache_key instance.cache_key end attr_reader :cache_key def initialize(options = {}) @cache_key = [self.class.name, VERSION, options].freeze end def call(input) # process input end end ``` ### Transformers Sprockets 2.x always had a one to one mapping between source file on disk (app/assets/javascripts/application.coffee.rb) to compiled artifact (public/assets/application.js). This has prevented the ability to compile assets to multiple targets such as image conversations from logo.svg to logo.png, logo.jpg, logo.gif, etc. Supporting variants will definitely make the processor chain more powerful, but it means moving away from some previous patterns. For an example, we can only simply map over all assets under a directory like app/assets since a single file may have multiple representations depending on the requested content type. To support transformers, two APIs have been added. First, the ability to request a variant of an asset for a content type. ``` ruby # Find any source asset named "logo" that can be transformed into "image/png" env.find_asset("logo", accept: "image/png") # or using the more common extension format now means the same env.find_asset("logo.png") ``` Second, a processor API for describing transformation types. ``` ruby Sprockets.register_transformer 'image/svg+xml', 'image/png', SVG2PNGProcessor Sprockets.register_transformer 'image/svg+xml', 'image/gif', SVG2GIFProcessor ``` Even if you don't need to support multiple content types, transformers can replace traditional engines. ``` ruby # Register a content type for file extension, its okay if its made up register_mime_type 'text/coffeescript', extensions: ['.coffee'] register_transformer 'text/coffeescript', 'application/javascript', CoffeeScriptProcessor ``` Some important differences from previous engines. **We can request the file in its original content type.** ``` ruby # Return the file as is env.find_asset("foo.coffee").source ``` Its important we can serve the original source file to the browser if source maps are being used. **Preprocesors run for the source content type, not the destination** ``` ruby register_preprocessor 'text/coffeescript', LintCoffeeScript register_postprocessor 'application/javascript', FormatJavaScript ``` Before converting a coffeescript file to JS, we first run any coffeescript preprocessors, convert it to JS, then run the postprocessor. Because we have a before and after content type distinction, theres not much use for pre vs post processors. Once the transition to transformers is complete, prefer just using `register_preprocessor` with the correct content type. **Transformers may bind to multi-extnames** ``` ruby register_mime_type 'application/javascript+module', extensions: ['.module.js'] register_mime_type 'text/html+ruby', extensions: ['.html.erb'] register_mime_type 'text/yaml+manifest', extensions: ['.manifest.yml'] ``` Whatever special extname you pick, it doesn't necessarily have to be at the end of the file. Prefer having an extname at the end that plays nice if your editor's syntax highlighting. However, this requires you whitelist all the compatible extension combinations. Theres no free form chaining. This turned out to be a less useful feature. It meant `foo.js.coffee.erb.haml.jst.eco.sass` was a legal processor chain, but pretty useless. ### Pipeline overview * Run preprocessors for source content type (`text/coffeescript`) * Run legacy engines defined by file extensions (.erb) * Run postprocessors for source content type (`text/coffeescript`) * Run transformer from source to destination content type (coffee->js) * Run preprocessors for destination content type (`application/javascript`) * Run postprocessors for destination content type (`application/javascript`) * Concatenate "required" files * Run bundle processors With engines being phased out, we can collapse the pre and post processor chains. But that still leaves the "bundle" step as a special thing. I haven't quite figured out how to it more unified. Let me know if you have any ideas. sprockets-3.7.2/bin/000077500000000000000000000000001331222022000142735ustar00rootroot00000000000000sprockets-3.7.2/bin/sprockets000077500000000000000000000041311331222022000162350ustar00rootroot00000000000000#!/usr/bin/env ruby $VERBOSE = nil require 'sprockets' require 'optparse' require 'shellwords' unless ARGV.delete("--noenv") if File.exist?(path = "./.sprocketsrc") rcflags = Shellwords.split(File.read(path)) ARGV.unshift(*rcflags) end end filenames = [] environment = Sprockets::Environment.new(Dir.pwd) manifest = nil (ENV['SPROCKETS_PATH'] || "").split(File::PATH_SEPARATOR).each do |path| environment.append_path path end OptionParser.new do |opts| opts.summary_width = 28 opts.banner = "Usage: sprockets [options] filename [filename ...]" def opts.show_usage puts self exit 1 end opts.on("-r", "--require LIBRARY", "Require the LIBRARY before doing anything") do |lib| require lib end opts.on("-I DIRECTORY", "--include=DIRECTORY", "Adds the directory to the Sprockets load path") do |directory| environment.append_path directory end opts.on("-o DIRECTORY", "--output=DIRECTORY", "Copy provided assets into DIRECTORY") do |directory| manifest = Sprockets::Manifest.new(environment, directory) end opts.on("--css-compressor=COMPRESSOR", "Use CSS compressor") do |compressor| environment.css_compressor = compressor.to_sym end opts.on("--js-compressor=COMPRESSOR", "Use JavaScript compressor") do |compressor| environment.js_compressor = compressor.to_sym end opts.on("--noenv", "Disables .sprocketsrc file") do end opts.on_tail("-h", "--help", "Shows this help message") do opts.show_usage end opts.on_tail("-v", "--version", "Shows version") do puts Sprockets::VERSION exit end opts.show_usage if ARGV.empty? begin opts.order(ARGV) do |filename| filenames << File.expand_path(filename) end rescue OptionParser::ParseError => e opts.warn e.message opts.show_usage end end if environment.paths.empty? warn "No load paths given" warn "Usage: sprockets -Ijavascripts/ filename" exit 1 end if manifest manifest.compile(filenames) elsif filenames.length == 1 puts environment.find_asset(filenames.first).to_s else warn "Only one file can be compiled to stdout at a time" exit 1 end sprockets-3.7.2/gemfiles/000077500000000000000000000000001331222022000153165ustar00rootroot00000000000000sprockets-3.7.2/gemfiles/Gemfile-1.9000066400000000000000000000001551331222022000171170ustar00rootroot00000000000000source "https://rubygems.org" gemspec path: '..' gem 'sass', '< 3.4' gem 'rack', '< 2.0' gem 'json', '< 2.0' sprockets-3.7.2/guides/000077500000000000000000000000001331222022000150035ustar00rootroot00000000000000sprockets-3.7.2/guides/building_an_asset_processing_framework.md000066400000000000000000000030671331222022000253160ustar00rootroot00000000000000# Building an Asset Processing Framework This guide is for using a Sprockets::Environment to process assets. You would use this class directly if you were building a feature similar to Rail's asset pipeline. If you aren't building an asset processing frameworks, you will want to refer to the [End User Asset Generation](end_user_asset_generation.md) guide instead. For a reference use of `Sprockets::Environemnt` see [sprockets-rails](github.com/rails/Sprockets-rails). ## Gzip By default when Sprockets generates a compiled asset file it will also produce a gzipped copy of that file. Sprockets only gzips non-binary files such as CSS, JavaScript, and SVG files. For example if Sprockets is generating ``` application-12345.css ``` Then it will also generate a compressed copy in ``` application-12345.css.gz ``` You can disable this behavior `Sprockets::Environemnt#gzip=` to something falsey for example: ```ruby env = Sprockets::Environment.new(".") env.gzip = false ``` ## WIP This guide is a work in progress. There are many different groups of people who interact with Sprockets. Some only need to know directive syntax to put in their asset files, some are building features like the Rails asset pipeline, and some are plugging into Sprockets and writing things like preprocessors. The goal of these guides are to provide task specific guidance to make the expected behavior explicit. If you are using Sprockets and you find missing information in these guides, please consider submitting a pull request with updated information. These guides live in [guides](/guides). sprockets-3.7.2/guides/end_user_asset_generation.md000066400000000000000000000167101331222022000225500ustar00rootroot00000000000000# End User Asset Generation This guide is for those using Sprockets through an interface similar to the Rails asset pipeline. It will talk about end user interfaces. If you are not the end user, but instead a tools developer who is building an asset processing framework, see [building an asset processing framework](building_an_asset_processing_framework.md). ## What is Sprockets? Sprockets is a Ruby library for compiling and serving web assets. It features declarative dependency management for JavaScript and CSS assets, as well as a preprocessor pipeline that allows you to write assets in languages like CoffeeScript, Sass and SCSS. ## Behavior Overview You can interact through Sprockets primarily through directives and file extensions. This section covers how to use each of these things, and the defaults that ship with Sprockets. Since you are likely using Sprockets through another framework (like the Rails asset pipeline), there will configuration options you can toggle that will change behavior such as what directories or files get compiled. For that documentation you should see your framework's documentation. ### Directives Directives are special comments in your asset file and the main way of interacting with processors. What kind of interactions? You can use these directives to tell Sprockets to load other files, or specify dependencies on other assets. For example, let's say you have custom JavaScript that you've written. You put this javascript in a file called `beta.js`. The javascript makes heavy use of jQuery, so you need to load that before your code executes. You could add this directive to the top of `beta.js`: ```js //= require jquery $().ready({ // my custom code here }) ``` The directive processor understands comment blocks in three formats: ``` css /* Multi-line comment blocks (CSS, SCSS, JavaScript) *= require foo */ ``` ``` js // Single-line comment blocks (SCSS, JavaScript) //= require foo ``` ``` coffee # Single-line comment blocks (CoffeeScript) #= require foo ``` Here is a list of the available directives - require - require_self - require_tree - require_directory - depend - depend_on_asset - stub - link - link_directory - link_tree You can see what each of these does below ### Specifying Processors through File Extensions Sprockets uses the filename extensions to determine what processors to run on your file and in what order. For example if you have a file: ``` application.scss ``` Then Sprockets will by default run the sass processor (which implements scss). The output file will be converted to css. You can specify multiple processors by specifying multiple file extensions. For example you can use Ruby's [ERB template language](http://ruby-doc.org/stdlib-2.2.3/libdoc/erb/rdoc/ERB.html) to embed content in your doc before running the sass processor. To accomplish this you would need to name your file ``` application.scss.erb ``` Processors are run from right to left, so in the above example the processor associated with `erb` will be run before the processor associated with `scss` extension. For a description of the processors that Sprockets has by default see the "default processors" section below. Other libraries may register additional processors. ## File Order Processing By default files are processed in alphabetical order. This behavior can impact your asset compilation when one asset needs to be loaded before another. For example if you have an `application.js` and it loads another directory ```js //= require_directory my_javascript ``` The files in that directory will be loaded in alphabetical order. If the directory looks like this: ```sh $ ls -1 my_javascript/ alpha.js beta.js jquery.js ``` Then `alpha.js` will be loaded before either of the other two. This can be a problem if `alpha.js` uses jquery. For this reason it is not recommend to use `require_directory` with files that are ordering dependent. You can either require individual files manually: ``` //= require jquery //= require alpha //= require beta ``` Or you can use index files to proxy your folders ### Index files are proxies for folders In Sprockets index files such as `index.js` or `index.css` files inside of a folder will generate a file with the folder's name. So if you have a `foo/index.js` file it will compile down to `foo.js`. This is similar to NPM's behavior of using [folders as modules](https://nodejs.org/api/modules.html#modules_folders_as_modules). It is also somewhat similar to the way that a file in `public/my_folder/index.html` can be reached by a request to `/my_folder`. This means that you cannot directly use an index file. For example this would not work: ``` <%= asset_path("foo/index.js") %> ``` Instead you would need to use: ``` <%= asset_path("foo.js") %> ``` Why would you want to use this behavior? It is common behavior where you might want to include an entire directory of files in a top level JavaScript. You can do this in Sprockets using `require_tree .` ``` //= require_tree . ``` This has the problem that files are required alphabetically. If your directory has `jquery-ui.js` and `jquery.min.js` then Sprockets will require `jquery-ui.js` before `jquery` is required which won't work (because jquery-ui depends on jquery). Previously the only way to get the correct ordering would be to rename your files, something like `0-jquery-ui.js`. Instead of doing that you can use an index file. For example, if you have an `application.js` and want all the files in the `foo/` folder you could do this: ``` //= require foo.js ``` Then create a file `foo/index.js` that requires all the files in that folder in any order you want: ``` //= require foo.min.js //= require foo-ui.js ``` Now in your `application.js` will correctly load the `foo.min.js` before `foo-ui.js`. If you used `require_tree` it would not work correctly. ## Default Directives TODO: add description of each of the directives ## Default Processors TODO: add description of each of the processors ## Default Compressors TODO: ## Output This section details the default output of Sprockets. This may have been modified by the frameworks you're using, so you will want to verify behavior with their docs. Processors and compressors will affect individual file output contents. Refer to the default processors and compressor section how processors for your asset may have modified your file. ### Manifest File TODO: Explain contents, location, and name of a manifest file. ### Fingerprinting TODO: Explain default fingerprinting/digest behavior ### Gzip By default when Sprockets generates a compiled asset file it will also produce a gzipped copy of that file. Sprockets only gzips non-binary files such as CSS, javascript, and SVG files. For example if Sprockets is generating ``` application-12345.css ``` Then it will also generate a compressed copy in ``` application-12345.css.gz ``` This behavior can be disabled, refer to your framework specific documentation. ## WIP This guide is a work in progress. There are many different groups of people who interact with Sprockets. Some only need to know directive syntax to put in their asset files, some are building features like the Rails asset pipeline, and some are plugging into Sprockets and writing things like preprocessors. The goal of these guides are to provide task specific guidance to make the expected behavior explicit. If you are using Sprockets and you find missing information in these guides, please consider submitting a pull request with updated information. These guides live in [guides](/guides). sprockets-3.7.2/guides/extending_sprockets.md000066400000000000000000000014211331222022000214050ustar00rootroot00000000000000# Extending Sprockets Sprockets can use custom processors, compressors, and directives. This document is intended for library authors who want to extend sprockets functionality. ## WIP This guide is a work in progress. There are many different groups of people who interact with sprockets. Some only need to know directive syntax to put in their asset files, some are building features like the Rails asset pipeline, and some are plugging into sprockets and writing things like preprocessors. The goal of these guides are to provide task specific guidance to make the expected behavior explicit. If you are using sprockets and you find missing information in these guides, please consider submitting a pull request with updated information. These guides live in [guides](/guides). sprockets-3.7.2/lib/000077500000000000000000000000001331222022000142715ustar00rootroot00000000000000sprockets-3.7.2/lib/rake/000077500000000000000000000000001331222022000152135ustar00rootroot00000000000000sprockets-3.7.2/lib/rake/sprocketstask.rb000066400000000000000000000073111331222022000204420ustar00rootroot00000000000000require 'rake' require 'rake/tasklib' require 'sprockets' require 'logger' module Rake # Simple Sprockets compilation Rake task macro. # # Rake::SprocketsTask.new do |t| # t.environment = Sprockets::Environment.new # t.output = "./public/assets" # t.assets = %w( application.js application.css ) # end # class SprocketsTask < Rake::TaskLib # Name of the task. Defaults to "assets". # # The name will also be used to suffix the clean and clobber # tasks, "clean_assets" and "clobber_assets". attr_accessor :name # `Environment` instance used for finding assets. # # You'll most likely want to reassign `environment` to your own. # # Rake::SprocketsTask.new do |t| # t.environment = Foo::Assets # end # def environment if !@environment.is_a?(Sprockets::Base) && @environment.respond_to?(:call) @environment = @environment.call else @environment end end attr_writer :environment # Returns cached cached environment def cached @cached ||= environment.cached if environment end alias_method :index, :cached # `Manifest` instance used for already compiled assets. # # Will be created by default if an environment and output # directory are given def manifest if !@manifest.is_a?(Sprockets::Manifest) && @manifest.respond_to?(:call) @manifest = @manifest.call else @manifest end end attr_writer :manifest # Directory to write compiled assets too. As well as the manifest file. # # t.output = "./public/assets" # attr_accessor :output # Array of asset logical paths to compile. # # t.assets = %w( application.js jquery.js application.css ) # attr_accessor :assets # Number of old assets to keep. attr_accessor :keep # Logger to use during rake tasks. Defaults to using stderr. # # t.logger = Logger.new($stdout) # attr_accessor :logger # Returns logger level Integer. def log_level @logger.level end # Set logger level with constant or symbol. # # t.log_level = Logger::INFO # t.log_level = :debug # def log_level=(level) if level.is_a?(Integer) @logger.level = level else @logger.level = Logger.const_get(level.to_s.upcase) end end def initialize(name = :assets) @name = name @environment = lambda { Sprockets::Environment.new(Dir.pwd) } @manifest = lambda { Sprockets::Manifest.new(cached, output) } @logger = Logger.new($stderr) @logger.level = Logger::INFO @keep = 2 yield self if block_given? define end # Define tasks def define desc name == :assets ? "Compile assets" : "Compile #{name} assets" task name do with_logger do manifest.compile(assets) end end desc name == :assets ? "Remove all assets" : "Remove all #{name} assets" task "clobber_#{name}" do with_logger do manifest.clobber end end task :clobber => ["clobber_#{name}"] desc name == :assets ? "Clean old assets" : "Clean old #{name} assets" task "clean_#{name}" do with_logger do manifest.clean(keep) end end task :clean => ["clean_#{name}"] end private # Sub out environment logger with our rake task logger that # writes to stderr. def with_logger if env = manifest.environment old_logger = env.logger env.logger = @logger end yield ensure env.logger = old_logger if env end end end sprockets-3.7.2/lib/sprockets.rb000066400000000000000000000150041331222022000166330ustar00rootroot00000000000000# encoding: utf-8 require 'sprockets/version' require 'sprockets/cache' require 'sprockets/environment' require 'sprockets/errors' require 'sprockets/manifest' require 'sprockets/deprecation' module Sprockets require 'sprockets/processor_utils' extend ProcessorUtils # Extend Sprockets module to provide global registry require 'sprockets/configuration' require 'sprockets/context' require 'digest/sha2' extend Configuration self.config = { bundle_processors: Hash.new { |h, k| [].freeze }.freeze, bundle_reducers: Hash.new { |h, k| {}.freeze }.freeze, compressors: Hash.new { |h, k| {}.freeze }.freeze, dependencies: Set.new.freeze, dependency_resolvers: {}.freeze, digest_class: Digest::SHA256, engine_mime_types: {}.freeze, engines: {}.freeze, mime_exts: {}.freeze, mime_types: {}.freeze, paths: [].freeze, pipelines: {}.freeze, postprocessors: Hash.new { |h, k| [].freeze }.freeze, preprocessors: Hash.new { |h, k| [].freeze }.freeze, registered_transformers: Hash.new { |h, k| {}.freeze }.freeze, root: File.expand_path('..', __FILE__).freeze, transformers: Hash.new { |h, k| {}.freeze }.freeze, version: "", gzip_enabled: true }.freeze self.computed_config = {} @context_class = Context require 'logger' @logger = Logger.new($stderr) @logger.level = Logger::FATAL # Common asset text types register_mime_type 'application/javascript', extensions: ['.js'], charset: :unicode register_mime_type 'application/json', extensions: ['.json'], charset: :unicode register_mime_type 'application/xml', extensions: ['.xml'] register_mime_type 'text/css', extensions: ['.css'], charset: :css register_mime_type 'text/html', extensions: ['.html', '.htm'], charset: :html register_mime_type 'text/plain', extensions: ['.txt', '.text'] register_mime_type 'text/yaml', extensions: ['.yml', '.yaml'], charset: :unicode # Common image types register_mime_type 'image/x-icon', extensions: ['.ico'] register_mime_type 'image/bmp', extensions: ['.bmp'] register_mime_type 'image/gif', extensions: ['.gif'] register_mime_type 'image/webp', extensions: ['.webp'] register_mime_type 'image/png', extensions: ['.png'] register_mime_type 'image/jpeg', extensions: ['.jpg', '.jpeg'] register_mime_type 'image/tiff', extensions: ['.tiff', '.tif'] register_mime_type 'image/svg+xml', extensions: ['.svg'] # Common audio/video types register_mime_type 'video/webm', extensions: ['.webm'] register_mime_type 'audio/basic', extensions: ['.snd', '.au'] register_mime_type 'audio/aiff', extensions: ['.aiff'] register_mime_type 'audio/mpeg', extensions: ['.mp3', '.mp2', '.m2a', '.m3a'] register_mime_type 'application/ogg', extensions: ['.ogx'] register_mime_type 'audio/midi', extensions: ['.midi', '.mid'] register_mime_type 'video/avi', extensions: ['.avi'] register_mime_type 'audio/wave', extensions: ['.wav', '.wave'] register_mime_type 'video/mp4', extensions: ['.mp4', '.m4v'] # Common font types register_mime_type 'application/vnd.ms-fontobject', extensions: ['.eot'] register_mime_type 'application/x-font-opentype', extensions: ['.otf'] register_mime_type 'application/x-font-ttf', extensions: ['.ttf'] register_mime_type 'application/font-woff', extensions: ['.woff'] register_pipeline :source do |env| [] end register_pipeline :self do |env, type, file_type, engine_extnames| env.self_processors_for(type, file_type, engine_extnames) end register_pipeline :default do |env, type, file_type, engine_extnames| env.default_processors_for(type, file_type, engine_extnames) end require 'sprockets/directive_processor' register_preprocessor 'text/css', DirectiveProcessor.new( comments: ["//", ["/*", "*/"]] ) register_preprocessor 'application/javascript', DirectiveProcessor.new( comments: ["//", ["/*", "*/"]] + ["#", ["###", "###"]] ) require 'sprockets/bundle' register_bundle_processor 'application/javascript', Bundle register_bundle_processor 'text/css', Bundle register_bundle_metadata_reducer '*/*', :data, proc { "" }, :concat register_bundle_metadata_reducer 'application/javascript', :data, proc { "" }, Utils.method(:concat_javascript_sources) register_bundle_metadata_reducer '*/*', :links, :+ require 'sprockets/closure_compressor' require 'sprockets/sass_compressor' require 'sprockets/uglifier_compressor' require 'sprockets/yui_compressor' register_compressor 'text/css', :sass, SassCompressor register_compressor 'text/css', :scss, SassCompressor register_compressor 'text/css', :yui, YUICompressor register_compressor 'application/javascript', :closure, ClosureCompressor register_compressor 'application/javascript', :uglifier, UglifierCompressor register_compressor 'application/javascript', :uglify, UglifierCompressor register_compressor 'application/javascript', :yui, YUICompressor # Mmm, CoffeeScript require 'sprockets/coffee_script_processor' Deprecation.silence do register_engine '.coffee', CoffeeScriptProcessor, mime_type: 'application/javascript', silence_deprecation: true end # JST engines require 'sprockets/eco_processor' require 'sprockets/ejs_processor' require 'sprockets/jst_processor' Deprecation.silence do register_engine '.jst', JstProcessor, mime_type: 'application/javascript', silence_deprecation: true register_engine '.eco', EcoProcessor, mime_type: 'application/javascript', silence_deprecation: true register_engine '.ejs', EjsProcessor, mime_type: 'application/javascript', silence_deprecation: true end # CSS engines require 'sprockets/sass_processor' Deprecation.silence do register_engine '.sass', SassProcessor, mime_type: 'text/css', silence_deprecation: true register_engine '.scss', ScssProcessor, mime_type: 'text/css', silence_deprecation: true end register_bundle_metadata_reducer 'text/css', :sass_dependencies, Set.new, :+ # Other require 'sprockets/erb_processor' register_engine '.erb', ERBProcessor, mime_type: 'text/plain', silence_deprecation: true register_dependency_resolver 'environment-version' do |env| env.version end register_dependency_resolver 'environment-paths' do |env| env.paths.map {|path| env.compress_from_root(path) } end register_dependency_resolver 'file-digest' do |env, str| env.file_digest(env.parse_file_digest_uri(str)) end register_dependency_resolver 'processors' do |env, str| env.resolve_processors_cache_key_uri(str) end depend_on 'environment-version' depend_on 'environment-paths' end require 'sprockets/legacy' sprockets-3.7.2/lib/sprockets/000077500000000000000000000000001331222022000163065ustar00rootroot00000000000000sprockets-3.7.2/lib/sprockets/asset.rb000066400000000000000000000114341331222022000177550ustar00rootroot00000000000000require 'fileutils' require 'sprockets/digest_utils' module Sprockets class Asset attr_reader :logical_path # Private: Intialize Asset wrapper from attributes Hash. # # Asset wrappers should not be initialized directly, only # Environment#find_asset should vend them. # # attributes - Hash of ivars # # Returns Asset. def initialize(environment, attributes = {}) @environment = environment @attributes = attributes @content_type = attributes[:content_type] @filename = attributes[:filename] @id = attributes[:id] @load_path = attributes[:load_path] @logical_path = attributes[:logical_path] @metadata = attributes[:metadata] @mtime = attributes[:mtime] @name = attributes[:name] @source = attributes[:source] @uri = attributes[:uri] end # Internal: Return all internal instance variables as a hash. # # Returns a Hash. def to_hash @attributes end # Public: Metadata accumulated from pipeline process. # # The API status of the keys is dependent on the pipeline processors # itself. So some values maybe considered public and others internal. # See the pipeline proccessor documentation itself. # # Returns Hash. attr_reader :metadata # Public: Returns String path of asset. attr_reader :filename # Internal: Unique asset object ID. # # Returns a String. attr_reader :id # Public: Internal URI to lookup asset by. # # NOT a publically accessible URL. # # Returns URI. attr_reader :uri # Public: Return logical path with digest spliced in. # # "foo/bar-37b51d194a7513e45b56f6524f2d51f2.js" # # Returns String. def digest_path logical_path.sub(/\.(\w+)$/) { |ext| "-#{etag}#{ext}" } end # Public: Returns String MIME type of asset. Returns nil if type is unknown. attr_reader :content_type # Public: Get all externally linked asset filenames from asset. # # All linked assets should be compiled anytime this asset is. # # Returns Set of String asset URIs. def links metadata[:links] || Set.new end # Public: Get all internally required assets that were concated into this # asset. # # Returns Array of String asset URIs. def included metadata[:included] end # Public: Return `String` of concatenated source. # # Returns String. def source if @source @source else # File is read everytime to avoid memory bloat of large binary files File.binread(filename) end end # Public: Alias for #source. # # Returns String. def to_s source end # Public: Get charset of source. # # Returns a String charset name or nil if binary. def charset metadata[:charset] end # Public: Returns Integer length of source. def length metadata[:length] end alias_method :bytesize, :length # Public: Returns String hexdigest of source. def hexdigest DigestUtils.pack_hexdigest(metadata[:digest]) end # Deprecated: Returns String hexdigest of source. # # In 4.x this will be changed to return a raw Digest byte String. alias_method :digest, :hexdigest # Pubic: ETag String of Asset. alias_method :etag, :hexdigest # Public: Returns String base64 digest of source. def base64digest DigestUtils.pack_base64digest(metadata[:digest]) end # Public: A "named information" URL for subresource integrity. def integrity DigestUtils.integrity_uri(metadata[:digest]) end # Public: Add enumerator to allow `Asset` instances to be used as Rack # compatible body objects. # # block # part - String body chunk # # Returns nothing. def each yield to_s end # Deprecated: Save asset to disk. # # filename - String target # # Returns nothing. def write_to(filename) FileUtils.mkdir_p File.dirname(filename) PathUtils.atomic_write(filename) do |f| f.write source end # Set mtime correctly File.utime(mtime, mtime, filename) nil end # Public: Pretty inspect # # Returns String. def inspect "#<#{self.class}:#{object_id.to_s(16)} #{uri.inspect}>" end # Public: Implements Object#hash so Assets can be used as a Hash key or # in a Set. # # Returns Integer hash of the id. def hash id.hash end # Public: Compare assets. # # Assets are equal if they share the same path and digest. # # Returns true or false. def eql?(other) self.class == other.class && self.id == other.id end alias_method :==, :eql? end end sprockets-3.7.2/lib/sprockets/autoload.rb000066400000000000000000000006101331222022000204400ustar00rootroot00000000000000module Sprockets module Autoload autoload :Closure, 'sprockets/autoload/closure' autoload :CoffeeScript, 'sprockets/autoload/coffee_script' autoload :Eco, 'sprockets/autoload/eco' autoload :EJS, 'sprockets/autoload/ejs' autoload :Sass, 'sprockets/autoload/sass' autoload :Uglifier, 'sprockets/autoload/uglifier' autoload :YUI, 'sprockets/autoload/yui' end end sprockets-3.7.2/lib/sprockets/autoload/000077500000000000000000000000001331222022000201165ustar00rootroot00000000000000sprockets-3.7.2/lib/sprockets/autoload/closure.rb000066400000000000000000000001411331222022000221130ustar00rootroot00000000000000require 'closure-compiler' module Sprockets module Autoload Closure = ::Closure end end sprockets-3.7.2/lib/sprockets/autoload/coffee_script.rb000066400000000000000000000001501331222022000232520ustar00rootroot00000000000000require 'coffee_script' module Sprockets module Autoload CoffeeScript = ::CoffeeScript end end sprockets-3.7.2/lib/sprockets/autoload/eco.rb000066400000000000000000000001141331222022000212050ustar00rootroot00000000000000require 'eco' module Sprockets module Autoload Eco = ::Eco end end sprockets-3.7.2/lib/sprockets/autoload/ejs.rb000066400000000000000000000001141331222022000212200ustar00rootroot00000000000000require 'ejs' module Sprockets module Autoload EJS = ::EJS end end sprockets-3.7.2/lib/sprockets/autoload/sass.rb000066400000000000000000000001171331222022000214130ustar00rootroot00000000000000require 'sass' module Sprockets module Autoload Sass = ::Sass end end sprockets-3.7.2/lib/sprockets/autoload/uglifier.rb000066400000000000000000000001331331222022000222460ustar00rootroot00000000000000require 'uglifier' module Sprockets module Autoload Uglifier = ::Uglifier end end sprockets-3.7.2/lib/sprockets/autoload/yui.rb000066400000000000000000000001271331222022000212510ustar00rootroot00000000000000require 'yui/compressor' module Sprockets module Autoload YUI = ::YUI end end sprockets-3.7.2/lib/sprockets/base.rb000066400000000000000000000056121331222022000175510ustar00rootroot00000000000000require 'sprockets/asset' require 'sprockets/bower' require 'sprockets/cache' require 'sprockets/configuration' require 'sprockets/digest_utils' require 'sprockets/errors' require 'sprockets/loader' require 'sprockets/path_digest_utils' require 'sprockets/path_dependency_utils' require 'sprockets/path_utils' require 'sprockets/resolve' require 'sprockets/server' require 'sprockets/loader' require 'sprockets/uri_tar' module Sprockets # `Base` class for `Environment` and `Cached`. class Base include PathUtils, PathDependencyUtils, PathDigestUtils, DigestUtils include Configuration include Server include Resolve, Loader include Bower # Get persistent cache store attr_reader :cache # Set persistent cache store # # The cache store must implement a pair of getters and # setters. Either `get(key)`/`set(key, value)`, # `[key]`/`[key]=value`, `read(key)`/`write(key, value)`. def cache=(cache) @cache = Cache.new(cache, logger) end # Return an `Cached`. Must be implemented by the subclass. def cached raise NotImplementedError end alias_method :index, :cached # Internal: Compute digest for path. # # path - String filename or directory path. # # Returns a String digest or nil. def file_digest(path) if stat = self.stat(path) # Caveat: Digests are cached by the path's current mtime. Its possible # for a files contents to have changed and its mtime to have been # negligently reset thus appearing as if the file hasn't changed on # disk. Also, the mtime is only read to the nearest second. It's # also possible the file was updated more than once in a given second. key = UnloadedAsset.new(path, self).file_digest_key(stat.mtime.to_i) cache.fetch(key) do self.stat_digest(path, stat) end end end # Find asset by logical path or expanded path. def find_asset(path, options = {}) uri, _ = resolve(path, options.merge(compat: false)) if uri load(uri) end end def find_all_linked_assets(path, options = {}) return to_enum(__method__, path, options) unless block_given? asset = find_asset(path, options) return unless asset yield asset stack = asset.links.to_a while uri = stack.shift yield asset = load(uri) stack = asset.links.to_a + stack end nil end # Preferred `find_asset` shorthand. # # environment['application.js'] # def [](*args) find_asset(*args) end # Pretty inspect def inspect "#<#{self.class}:0x#{object_id.to_s(16)} " + "root=#{root.to_s.inspect}, " + "paths=#{paths.inspect}>" end def compress_from_root(uri) URITar.new(uri, self).compress end def expand_from_root(uri) URITar.new(uri, self).expand end end end sprockets-3.7.2/lib/sprockets/bower.rb000066400000000000000000000031751331222022000177570ustar00rootroot00000000000000require 'json' module Sprockets module Bower # Internal: All supported bower.json files. # # https://github.com/bower/json/blob/0.4.0/lib/json.js#L7 POSSIBLE_BOWER_JSONS = ['bower.json', 'component.json', '.bower.json'] # Internal: Override resolve_alternates to install bower.json behavior. # # load_path - String environment path # logical_path - String path relative to base # # Returns candiate filenames. def resolve_alternates(load_path, logical_path) candidates, deps = super # bower.json can only be nested one level deep if !logical_path.index('/') dirname = File.join(load_path, logical_path) if directory?(dirname) filenames = POSSIBLE_BOWER_JSONS.map { |basename| File.join(dirname, basename) } filename = filenames.detect { |fn| self.file?(fn) } if filename deps << build_file_digest_uri(filename) read_bower_main(dirname, filename) do |path| candidates << path end end end end return candidates, deps end # Internal: Read bower.json's main directive. # # dirname - String path to component directory. # filename - String path to bower.json. # # Returns nothing. def read_bower_main(dirname, filename) bower = JSON.parse(File.read(filename), create_additions: false) case bower['main'] when String yield File.expand_path(bower['main'], dirname) when Array bower['main'].each do |name| yield File.expand_path(name, dirname) end end end end end sprockets-3.7.2/lib/sprockets/bundle.rb000066400000000000000000000041611331222022000201060ustar00rootroot00000000000000require 'set' require 'sprockets/utils' module Sprockets # Internal: Bundle processor takes a single file asset and prepends all the # `:required` URIs to the contents. # # Uses pipeline metadata: # # :required - Ordered Set of asset URIs to prepend # :stubbed - Set of asset URIs to substract from the required set. # # Also see DirectiveProcessor. class Bundle def self.call(input) env = input[:environment] type = input[:content_type] dependencies = Set.new(input[:metadata][:dependencies]) processed_uri, deps = env.resolve(input[:filename], accept: type, pipeline: :self, compat: false) dependencies.merge(deps) find_required = proc { |uri| env.load(uri).metadata[:required] } required = Utils.dfs(processed_uri, &find_required) stubbed = Utils.dfs(env.load(processed_uri).metadata[:stubbed], &find_required) required.subtract(stubbed) assets = required.map { |uri| env.load(uri) } (required + stubbed).each do |uri| dependencies.merge(env.load(uri).metadata[:dependencies]) end reducers = Hash[env.match_mime_type_keys(env.config[:bundle_reducers], type).flat_map(&:to_a)] process_bundle_reducers(assets, reducers).merge(dependencies: dependencies, included: assets.map(&:uri)) end # Internal: Run bundle reducers on set of Assets producing a reduced # metadata Hash. # # assets - Array of Assets # reducers - Array of [initial, reducer_proc] pairs # # Returns reduced asset metadata Hash. def self.process_bundle_reducers(assets, reducers) initial = {} reducers.each do |k, (v, _)| if v.respond_to?(:call) initial[k] = v.call elsif !v.nil? initial[k] = v end end assets.reduce(initial) do |h, asset| reducers.each do |k, (_, block)| value = k == :data ? asset.source : asset.metadata[k] if h.key?(k) if !value.nil? h[k] = block.call(h[k], value) end else h[k] = value end end h end end end end sprockets-3.7.2/lib/sprockets/cache.rb000066400000000000000000000151501331222022000177000ustar00rootroot00000000000000require 'logger' require 'sprockets/digest_utils' module Sprockets # Public: Wrapper interface to backend cache stores. Ensures a consistent API # even when the backend uses get/set or read/write. # # Public cache interface # # Always assign the backend store instance to Environment#cache=. # # environment.cache = Sprockets::Cache::MemoryStore.new(1000) # # Environment#cache will always return a wrapped Cache interface. See the # methods marked public on this class. # # # Backend cache interface # # The Backend cache store must implement two methods. # # get(key) # # key - An opaque String with a length less than 250 characters. # # Returns an JSON serializable object. # # set(key, value) # # Will only be called once per key. Setting a key "foo" with value "bar", # then later key "foo" with value "baz" is an undefined behavior. # # key - An opaque String with a length less than 250 characters. # value - A JSON serializable object. # # Returns argument value. # class Cache # Builtin cache stores. autoload :FileStore, 'sprockets/cache/file_store' autoload :MemoryStore, 'sprockets/cache/memory_store' autoload :NullStore, 'sprockets/cache/null_store' # Internal: Cache key version for this class. Rarely should have to change # unless the cache format radically changes. Will be bump on major version # releases though. VERSION = '3.0' def self.default_logger logger = Logger.new($stderr) logger.level = Logger::FATAL logger end # Internal: Wrap a backend cache store. # # Always assign a backend cache store instance to Environment#cache= and # use Environment#cache to retreive a wrapped interface. # # cache - A compatible backend cache store instance. def initialize(cache = nil, logger = self.class.default_logger) @cache_wrapper = get_cache_wrapper(cache) @fetch_cache = Cache::MemoryStore.new(1024) @logger = logger end # Public: Prefer API to retrieve and set values in the cache store. # # key - JSON serializable key # block - # Must return a consistent JSON serializable object for the given key. # # Examples # # cache.fetch("foo") { "bar" } # # Returns a JSON serializable object. def fetch(key) start = Time.now.to_f expanded_key = expand_key(key) value = @fetch_cache.get(expanded_key) if value.nil? value = @cache_wrapper.get(expanded_key) if value.nil? value = yield @cache_wrapper.set(expanded_key, value) @logger.debug do ms = "(#{((Time.now.to_f - start) * 1000).to_i}ms)" "Sprockets Cache miss #{peek_key(key)} #{ms}" end end @fetch_cache.set(expanded_key, value) end value end # Public: Low level API to retrieve item directly from the backend cache # store. # # This API may be used publicly, but may have undefined behavior # depending on the backend store being used. Prefer the # Cache#fetch API over using this. # # key - JSON serializable key # local - Check local cache first (default: false) # # Returns a JSON serializable object or nil if there was a cache miss. def get(key, local = false) expanded_key = expand_key(key) if local && value = @fetch_cache.get(expanded_key) return value end value = @cache_wrapper.get(expanded_key) @fetch_cache.set(expanded_key, value) if local value end # Public: Low level API to set item directly to the backend cache store. # # This API may be used publicly, but may have undefined behavior # depending on the backend store being used. Prefer the # Cache#fetch API over using this. # # key - JSON serializable key # value - A consistent JSON serializable object for the given key. Setting # a different value for the given key has undefined behavior. # local - Set on local cache (default: false) # # Returns the value argument. def set(key, value, local = false) expanded_key = expand_key(key) @fetch_cache.set(expanded_key, value) if local @cache_wrapper.set(expanded_key, value) end # Public: Pretty inspect # # Returns String. def inspect "#<#{self.class} local=#{@fetch_cache.inspect} store=#{@cache_wrapper.cache.inspect}>" end private # Internal: Expand object cache key into a short String key. # # The String should be under 250 characters so its compatible with # Memcache. # # key - JSON serializable key # # Returns a String with a length less than 250 characters. def expand_key(key) digest_key = DigestUtils.pack_urlsafe_base64digest(DigestUtils.digest(key)) namespace = digest_key[0, 2] "sprockets/v#{VERSION}/#{namespace}/#{digest_key}" end PEEK_SIZE = 100 # Internal: Show first 100 characters of cache key for logging purposes. # # Returns a String with a length less than 100 characters. def peek_key(key) case key when Integer key.to_s when String key[0, PEEK_SIZE].inspect when Array str = [] key.each { |k| str << peek_key(k) } str.join(':')[0, PEEK_SIZE] else peek_key(DigestUtils.pack_urlsafe_base64digest(DigestUtils.digest(key))) end end def get_cache_wrapper(cache) if cache.is_a?(Cache) cache # `Cache#get(key)` for Memcache elsif cache.respond_to?(:get) GetWrapper.new(cache) # `Cache#[key]` so `Hash` can be used elsif cache.respond_to?(:[]) HashWrapper.new(cache) # `Cache#read(key)` for `ActiveSupport::Cache` support elsif cache.respond_to?(:read) ReadWriteWrapper.new(cache) else cache = Sprockets::Cache::NullStore.new GetWrapper.new(cache) end end class Wrapper < Struct.new(:cache) end class GetWrapper < Wrapper def get(key) cache.get(key) end def set(key, value) cache.set(key, value) end end class HashWrapper < Wrapper def get(key) cache[key] end def set(key, value) cache[key] = value end end class ReadWriteWrapper < Wrapper def get(key) cache.read(key) end def set(key, value) cache.write(key, value) end end end end sprockets-3.7.2/lib/sprockets/cache/000077500000000000000000000000001331222022000173515ustar00rootroot00000000000000sprockets-3.7.2/lib/sprockets/cache/file_store.rb000066400000000000000000000116121331222022000220320ustar00rootroot00000000000000require 'fileutils' require 'logger' require 'sprockets/encoding_utils' require 'sprockets/path_utils' require 'zlib' module Sprockets class Cache # Public: A file system cache store that automatically cleans up old keys. # # Assign the instance to the Environment#cache. # # environment.cache = Sprockets::Cache::FileStore.new("/tmp") # # See Also # # ActiveSupport::Cache::FileStore # class FileStore # Internal: Default key limit for store. DEFAULT_MAX_SIZE = 25 * 1024 * 1024 # Internal: Default standard error fatal logger. # # Returns a Logger. def self.default_logger logger = Logger.new($stderr) logger.level = Logger::FATAL logger end # Public: Initialize the cache store. # # root - A String path to a directory to persist cached values to. # max_size - A Integer of the maximum number of keys the store will hold. # (default: 1000). def initialize(root, max_size = DEFAULT_MAX_SIZE, logger = self.class.default_logger) @root = root @max_size = max_size @gc_size = max_size * 0.75 @logger = logger end # Public: Retrieve value from cache. # # This API should not be used directly, but via the Cache wrapper API. # # key - String cache key. # # Returns Object or nil or the value is not set. def get(key) path = File.join(@root, "#{key}.cache") value = safe_open(path) do |f| begin EncodingUtils.unmarshaled_deflated(f.read, Zlib::MAX_WBITS) rescue Exception => e @logger.error do "#{self.class}[#{path}] could not be unmarshaled: " + "#{e.class}: #{e.message}" end nil end end if value FileUtils.touch(path) value end end # Public: Set a key and value in the cache. # # This API should not be used directly, but via the Cache wrapper API. # # key - String cache key. # value - Object value. # # Returns Object value. def set(key, value) path = File.join(@root, "#{key}.cache") # Ensure directory exists FileUtils.mkdir_p File.dirname(path) # Check if cache exists before writing exists = File.exist?(path) # Serialize value marshaled = Marshal.dump(value) # Compress if larger than 4KB if marshaled.bytesize > 4 * 1024 deflater = Zlib::Deflate.new( Zlib::BEST_COMPRESSION, Zlib::MAX_WBITS, Zlib::MAX_MEM_LEVEL, Zlib::DEFAULT_STRATEGY ) deflater << marshaled raw = deflater.finish else raw = marshaled end # Write data PathUtils.atomic_write(path) do |f| f.write(raw) @size = size + f.size unless exists end # GC if necessary gc! if size > @max_size value end # Public: Pretty inspect # # Returns String. def inspect "#<#{self.class} size=#{size}/#{@max_size}>" end private # Internal: Get all cache files along with stats. # # Returns an Array of [String filename, File::Stat] pairs sorted by # mtime. def find_caches Dir.glob(File.join(@root, '**/*.cache')).reduce([]) { |stats, filename| stat = safe_stat(filename) # stat maybe nil if file was removed between the time we called # dir.glob and the next stat stats << [filename, stat] if stat stats }.sort_by { |_, stat| stat.mtime.to_i } end def size @size ||= compute_size(find_caches) end def compute_size(caches) caches.inject(0) { |sum, (_, stat)| sum + stat.size } end def safe_stat(fn) File.stat(fn) rescue Errno::ENOENT nil end def safe_open(path, &block) if File.exist?(path) File.open(path, 'rb', &block) end rescue Errno::ENOENT end def gc! start_time = Time.now caches = find_caches size = compute_size(caches) delete_caches, keep_caches = caches.partition { |filename, stat| deleted = size > @gc_size size -= stat.size deleted } return if delete_caches.empty? FileUtils.remove(delete_caches.map(&:first), force: true) @size = compute_size(keep_caches) @logger.warn do secs = Time.now.to_f - start_time.to_f "#{self.class}[#{@root}] garbage collected " + "#{delete_caches.size} files (#{(secs * 1000).to_i}ms)" end end end end end sprockets-3.7.2/lib/sprockets/cache/memory_store.rb000066400000000000000000000031631331222022000224250ustar00rootroot00000000000000module Sprockets class Cache # Public: Basic in memory LRU cache. # # Assign the instance to the Environment#cache. # # environment.cache = Sprockets::Cache::MemoryStore.new(1000) # # See Also # # ActiveSupport::Cache::MemoryStore # class MemoryStore # Internal: Default key limit for store. DEFAULT_MAX_SIZE = 1000 # Public: Initialize the cache store. # # max_size - A Integer of the maximum number of keys the store will hold. # (default: 1000). def initialize(max_size = DEFAULT_MAX_SIZE) @max_size = max_size @cache = {} end # Public: Retrieve value from cache. # # This API should not be used directly, but via the Cache wrapper API. # # key - String cache key. # # Returns Object or nil or the value is not set. def get(key) exists = true value = @cache.delete(key) { exists = false } if exists @cache[key] = value else nil end end # Public: Set a key and value in the cache. # # This API should not be used directly, but via the Cache wrapper API. # # key - String cache key. # value - Object value. # # Returns Object value. def set(key, value) @cache.delete(key) @cache[key] = value @cache.shift if @cache.size > @max_size value end # Public: Pretty inspect # # Returns String. def inspect "#<#{self.class} size=#{@cache.size}/#{@max_size}>" end end end end sprockets-3.7.2/lib/sprockets/cache/null_store.rb000066400000000000000000000020351331222022000220640ustar00rootroot00000000000000module Sprockets class Cache # Public: A compatible cache store that doesn't store anything. Used by # default when no Environment#cache is configured. # # Assign the instance to the Environment#cache. # # environment.cache = Sprockets::Cache::NullStore.new # # See Also # # ActiveSupport::Cache::NullStore # class NullStore # Public: Simulate a cache miss. # # This API should not be used directly, but via the Cache wrapper API. # # key - String cache key. # # Returns nil. def get(key) nil end # Public: Simulate setting a value in the cache. # # This API should not be used directly, but via the Cache wrapper API. # # key - String cache key. # value - Object value. # # Returns Object value. def set(key, value) value end # Public: Pretty inspect # # Returns String. def inspect "#<#{self.class}>" end end end end sprockets-3.7.2/lib/sprockets/cached_environment.rb000066400000000000000000000037031331222022000224710ustar00rootroot00000000000000require 'sprockets/base' module Sprockets # `Cached` is a special cached version of `Environment`. # # The expection is that all of its file system methods are cached # for the instances lifetime. This makes `Cached` much faster. This # behavior is ideal in production environments where the file system # is immutable. # # `Cached` should not be initialized directly. Instead use # `Environment#cached`. class CachedEnvironment < Base def initialize(environment) initialize_configuration(environment) @cache = environment.cache @stats = Hash.new { |h, k| h[k] = _stat(k) } @entries = Hash.new { |h, k| h[k] = _entries(k) } @uris = Hash.new { |h, k| h[k] = _load(k) } @processor_cache_keys = Hash.new { |h, k| h[k] = _processor_cache_key(k) } @resolved_dependencies = Hash.new { |h, k| h[k] = _resolve_dependency(k) } end # No-op return self as cached environment. def cached self end alias_method :index, :cached # Internal: Cache Environment#entries alias_method :_entries, :entries def entries(path) @entries[path] end # Internal: Cache Environment#stat alias_method :_stat, :stat def stat(path) @stats[path] end # Internal: Cache Environment#load alias_method :_load, :load def load(uri) @uris[uri] end # Internal: Cache Environment#processor_cache_key alias_method :_processor_cache_key, :processor_cache_key def processor_cache_key(str) @processor_cache_keys[str] end # Internal: Cache Environment#resolve_dependency alias_method :_resolve_dependency, :resolve_dependency def resolve_dependency(str) @resolved_dependencies[str] end private # Cache is immutable, any methods that try to change the runtime config # should bomb. def config=(config) raise RuntimeError, "can't modify immutable cached environment" end end end sprockets-3.7.2/lib/sprockets/closure_compressor.rb000066400000000000000000000022341331222022000225640ustar00rootroot00000000000000require 'sprockets/autoload' require 'sprockets/digest_utils' module Sprockets # Public: Closure Compiler minifier. # # To accept the default options # # environment.register_bundle_processor 'application/javascript', # Sprockets::ClosureCompressor # # Or to pass options to the Closure::Compiler class. # # environment.register_bundle_processor 'application/javascript', # Sprockets::ClosureCompressor.new({ ... }) # class ClosureCompressor VERSION = '1' # Public: Return singleton instance with default options. # # Returns ClosureCompressor object. def self.instance @instance ||= new end def self.call(input) instance.call(input) end def self.cache_key instance.cache_key end attr_reader :cache_key def initialize(options = {}) @options = options @cache_key = "#{self.class.name}:#{Autoload::Closure::VERSION}:#{Autoload::Closure::COMPILER_VERSION}:#{VERSION}:#{DigestUtils.digest(options)}".freeze end def call(input) @compiler ||= Autoload::Closure::Compiler.new(@options) @compiler.compile(input[:data]) end end end sprockets-3.7.2/lib/sprockets/coffee_script_processor.rb000066400000000000000000000011451331222022000235460ustar00rootroot00000000000000require 'sprockets/autoload' module Sprockets # Processor engine class for the CoffeeScript compiler. # Depends on the `coffee-script` and `coffee-script-source` gems. # # For more infomation see: # # https://github.com/josh/ruby-coffee-script # module CoffeeScriptProcessor VERSION = '1' def self.cache_key @cache_key ||= "#{name}:#{Autoload::CoffeeScript::Source.version}:#{VERSION}".freeze end def self.call(input) data = input[:data] input[:cache].fetch([self.cache_key, data]) do Autoload::CoffeeScript.compile(data) end end end end sprockets-3.7.2/lib/sprockets/coffee_script_template.rb000066400000000000000000000006331331222022000233430ustar00rootroot00000000000000require 'sprockets/coffee_script_processor' module Sprockets # Deprecated module CoffeeScriptTemplate VERSION = CoffeeScriptProcessor::VERSION def self.cache_key CoffeeScriptProcessor.cache_key end def self.call(*args) Deprecation.new.warn "CoffeeScriptTemplate is deprecated please use CoffeeScriptProcessor instead" CoffeeScriptProcessor.call(*args) end end end sprockets-3.7.2/lib/sprockets/compressing.rb000066400000000000000000000053751331222022000211760ustar00rootroot00000000000000require 'sprockets/utils' module Sprockets # `Compressing` is an internal mixin whose public methods are exposed on # the `Environment` and `CachedEnvironment` classes. module Compressing include Utils def compressors config[:compressors] end def register_compressor(mime_type, sym, klass) self.config = hash_reassoc(config, :compressors, mime_type) do |compressors| compressors[sym] = klass compressors end end # Return CSS compressor or nil if none is set def css_compressor if defined? @css_compressor @css_compressor end end # Assign a compressor to run on `text/css` assets. # # The compressor object must respond to `compress`. def css_compressor=(compressor) unregister_bundle_processor 'text/css', @css_compressor if defined? @css_compressor @css_compressor = nil return unless compressor if compressor.is_a?(Symbol) @css_compressor = klass = config[:compressors]['text/css'][compressor] || raise(Error, "unknown compressor: #{compressor}") elsif compressor.respond_to?(:compress) klass = LegacyProcProcessor.new(:css_compressor, proc { |context, data| compressor.compress(data) }) @css_compressor = :css_compressor else @css_compressor = klass = compressor end register_bundle_processor 'text/css', klass end # Return JS compressor or nil if none is set def js_compressor if defined? @js_compressor @js_compressor end end # Assign a compressor to run on `application/javascript` assets. # # The compressor object must respond to `compress`. def js_compressor=(compressor) unregister_bundle_processor 'application/javascript', @js_compressor if defined? @js_compressor @js_compressor = nil return unless compressor if compressor.is_a?(Symbol) @js_compressor = klass = config[:compressors]['application/javascript'][compressor] || raise(Error, "unknown compressor: #{compressor}") elsif compressor.respond_to?(:compress) klass = LegacyProcProcessor.new(:js_compressor, proc { |context, data| compressor.compress(data) }) @js_compressor = :js_compressor else @js_compressor = klass = compressor end register_bundle_processor 'application/javascript', klass end # Public: Checks if Gzip is enabled. def gzip? config[:gzip_enabled] end # Public: Checks if Gzip is disabled. def skip_gzip? !gzip? end # Public: Enable or disable the creation of Gzip files. # # Defaults to true. # # environment.gzip = false # def gzip=(gzip) self.config = config.merge(gzip_enabled: gzip).freeze end end end sprockets-3.7.2/lib/sprockets/configuration.rb000066400000000000000000000044001331222022000215000ustar00rootroot00000000000000require 'sprockets/compressing' require 'sprockets/dependencies' require 'sprockets/engines' require 'sprockets/mime' require 'sprockets/paths' require 'sprockets/processing' require 'sprockets/transformers' require 'sprockets/utils' module Sprockets module Configuration include Paths, Mime, Engines, Transformers, Processing, Compressing, Dependencies, Utils def initialize_configuration(parent) @config = parent.config @computed_config = parent.computed_config @logger = parent.logger @context_class = Class.new(parent.context_class) end attr_reader :config attr_accessor :computed_config def config=(config) raise TypeError, "can't assign mutable config" unless config.frozen? @config = config end # Get and set `Logger` instance. attr_accessor :logger # The `Environment#version` is a custom value used for manually # expiring all asset caches. # # Sprockets is able to track most file and directory changes and # will take care of expiring the cache for you. However, its # impossible to know when any custom helpers change that you mix # into the `Context`. # # It would be wise to increment this value anytime you make a # configuration change to the `Environment` object. def version config[:version] end # Assign an environment version. # # environment.version = '2.0' # def version=(version) self.config = hash_reassoc(config, :version) { version.dup } end # Public: Returns a `Digest` implementation class. # # Defaults to `Digest::SHA256`. def digest_class config[:digest_class] end # Deprecated: Assign a `Digest` implementation class. This maybe any Ruby # `Digest::` implementation such as `Digest::SHA256` or # `Digest::MD5`. # # environment.digest_class = Digest::MD5 # def digest_class=(klass) self.config = config.merge(digest_class: klass).freeze end # Deprecated: Get `Context` class. # # This class maybe mutated and mixed in with custom helpers. # # environment.context_class.instance_eval do # include MyHelpers # def asset_url; end # end # attr_reader :context_class end end sprockets-3.7.2/lib/sprockets/context.rb000066400000000000000000000155201331222022000203220ustar00rootroot00000000000000require 'pathname' require 'rack/utils' require 'set' require 'sprockets/errors' module Sprockets # Deprecated: `Context` provides helper methods to all 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 # # <%= asset_url "foo.png" %> # # The `Context` also collects dependencies declared by # assets. See `DirectiveProcessor` for an example of this. class Context attr_reader :environment, :filename, :pathname # Deprecated attr_accessor :__LINE__ 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 = Set.new(@metadata[:required]) @stubbed = Set.new(@metadata[:stubbed]) @links = Set.new(@metadata[:links]) @dependencies = Set.new(input[:metadata][:dependencies]) end def metadata { required: @required, stubbed: @stubbed, links: @links, dependencies: @dependencies } 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`, `load_path` would # return `app/javascripts`. attr_reader :load_path alias_method :root_path, :load_path # Returns logical path without any file extensions. # # 'app/javascripts/application.js' # # => 'application' # attr_reader :logical_path # Returns content type of file # # 'application/javascript' # 'text/css' # attr_reader :content_type # Public: Given a logical path, `resolve` will find and return an Asset URI. # Relative paths will also be resolved. An accept type maybe given to # restrict the search. # # resolve("foo.js") # # => "file:///path/to/app/javascripts/foo.js?type=application/javascript" # # resolve("./bar.js") # # => "file:///path/to/app/javascripts/bar.js?type=application/javascript" # # path - String logical or absolute path # options # accept - String content accept type # # Returns an Asset URI String. def resolve(path, options = {}) uri, deps = environment.resolve!(path, options.merge(base_path: @dirname)) @dependencies.merge(deps) uri end # Public: Load Asset by AssetURI and track it as a dependency. # # uri - AssetURI # # Returns Asset. def load(uri) asset = environment.load(uri) @dependencies.merge(asset.metadata[:dependencies]) asset 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) path = path.to_s if path.is_a?(Pathname) if environment.absolute_path?(path) && environment.stat(path) @dependencies << environment.build_file_digest_uri(path) else resolve(path, compat: false) end nil end # `depend_on_asset` allows you to state an asset dependency # without including it. # # 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) load(resolve(path, compat: false)) end # `require_asset` declares `path` as a dependency of the file. The # dependency will be inserted before the file and will only be # included once. # # If ERB processing is enabled, you can use it to dynamically # require assets. # # <%= require_asset "#{framework}.js" %> # def require_asset(path) @required << resolve(path, accept: @content_type, pipeline: :self, compat: 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 << resolve(path, accept: @content_type, pipeline: :self, compat: false) nil end # `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. # # Returns an Asset or nil. def link_asset(path) asset = depend_on_asset(path) @links << asset.uri 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. # # Use `asset_data_uri` from ERB with CSS or JavaScript assets: # # #logo { background: url(<%= asset_data_uri 'logo.png' %>) } # # $('').attr('src', '<%= asset_data_uri 'avatar.jpg' %>') # def asset_data_uri(path) asset = depend_on_asset(path) data = EncodingUtils.base64(asset.source) "data:#{asset.content_type};base64,#{Rack::Utils.escape(data)}" end # Expands logical path to full url to asset. # # NOTE: This helper is currently not implemented and should be # customized by the application. Though, in the future, some # basics implemention may be provided with different methods that # are required to be overridden. def asset_path(path, options = {}) message = <<-EOS Custom asset_path helper is not implemented Extend your environment context with a custom method. environment.context_class.class_eval do def asset_path(path, options = {}) end end EOS raise NotImplementedError, message end # Expand logical image asset path. def image_path(path) asset_path(path, type: :image) end # Expand logical video asset path. def video_path(path) asset_path(path, type: :video) end # Expand logical audio asset path. def audio_path(path) asset_path(path, type: :audio) end # Expand logical font asset path. def font_path(path) asset_path(path, type: :font) end # Expand logical javascript asset path. def javascript_path(path) asset_path(path, type: :javascript) end # Expand logical stylesheet asset path. def stylesheet_path(path) asset_path(path, type: :stylesheet) end end end sprockets-3.7.2/lib/sprockets/dependencies.rb000066400000000000000000000035731331222022000212710ustar00rootroot00000000000000require 'sprockets/digest_utils' require 'sprockets/path_digest_utils' require 'sprockets/uri_utils' module Sprockets # `Dependencies` is an internal mixin whose public methods are exposed on the # `Environment` and `CachedEnvironment` classes. module Dependencies include DigestUtils, PathDigestUtils, URIUtils # Public: Mapping dependency schemes to resolver functions. # # key - String scheme # value - Proc.call(Environment, String) # # Returns Hash. def dependency_resolvers config[:dependency_resolvers] end # Public: Default set of dependency URIs for assets. # # Returns Set of String URIs. def dependencies config[:dependencies] end # Public: Register new dependency URI resolver. # # scheme - String scheme # block - # environment - Environment # uri - String dependency URI # # Returns nothing. def register_dependency_resolver(scheme, &block) self.config = hash_reassoc(config, :dependency_resolvers) do |hash| hash.merge(scheme => block) end end # Public: Add environmental dependency inheirted by all assets. # # uri - String dependency URI # # Returns nothing. def add_dependency(uri) self.config = hash_reassoc(config, :dependencies) do |set| set + Set.new([uri]) end end alias_method :depend_on, :add_dependency # Internal: Resolve dependency URIs. # # Returns resolved Object. def resolve_dependency(str) # Optimize for the most common scheme to # save 22k allocations on an average Spree app. scheme = if str.start_with?('file-digest:'.freeze) 'file-digest'.freeze else str[/([^:]+)/, 1] end if resolver = config[:dependency_resolvers][scheme] resolver.call(self, str) else nil end end end end sprockets-3.7.2/lib/sprockets/deprecation.rb000066400000000000000000000047311331222022000211350ustar00rootroot00000000000000module Sprockets class Deprecation THREAD_LOCAL__SILENCE_KEY = "_sprockets_deprecation_silence".freeze DEFAULT_BEHAVIORS = { raise: ->(message, callstack) { e = DeprecationException.new(message) e.set_backtrace(callstack.map(&:to_s)) raise e }, stderr: ->(message, callstack) { $stderr.puts(message) }, } attr_reader :callstack def self.silence(&block) Thread.current[THREAD_LOCAL__SILENCE_KEY] = true block.call ensure Thread.current[THREAD_LOCAL__SILENCE_KEY] = false end def initialize(callstack = nil) @callstack = callstack || caller(2) end def warn(message) return if Thread.current[THREAD_LOCAL__SILENCE_KEY] deprecation_message(message).tap do |m| behavior.each { |b| b.call(m, callstack) } end end private def behavior @behavior ||= [DEFAULT_BEHAVIORS[:stderr]] end def behavior=(behavior) @behavior = Array(behavior).map { |b| DEFAULT_BEHAVIORS[b] || b } end def deprecation_message(message = nil) message ||= "You are using deprecated behavior which will be removed from the next major or minor release." "DEPRECATION WARNING: #{message} #{ deprecation_caller_message }" end def deprecation_caller_message file, line, method = extract_callstack if file if line && method "(called from #{method} at #{file}:#{line})" else "(called from #{file}:#{line})" end end end SPROCKETS_GEM_ROOT = File.expand_path("../../../../..", __FILE__) + "/" def ignored_callstack(path) path.start_with?(SPROCKETS_GEM_ROOT) || path.start_with?(RbConfig::CONFIG['rubylibdir']) end def extract_callstack return _extract_callstack if callstack.first.is_a? String offending_line = callstack.find { |frame| frame.absolute_path && !ignored_callstack(frame.absolute_path) } || callstack.first [offending_line.path, offending_line.lineno, offending_line.label] end def _extract_callstack offending_line = callstack.find { |line| !ignored_callstack(line) } || callstack.first if offending_line if md = offending_line.match(/^(.+?):(\d+)(?::in `(.*?)')?/) md.captures else offending_line end end end end private_constant :Deprecation end sprockets-3.7.2/lib/sprockets/digest_utils.rb000066400000000000000000000116351331222022000213400ustar00rootroot00000000000000require 'digest/md5' require 'digest/sha1' require 'digest/sha2' require 'set' module Sprockets # Internal: Hash functions and digest related utilities. Mixed into # Environment. module DigestUtils extend self # Internal: Default digest class. # # Returns a Digest::Base subclass. def digest_class Digest::SHA256 end # Internal: Maps digest bytesize to the digest class. DIGEST_SIZES = { 16 => Digest::MD5, 20 => Digest::SHA1, 32 => Digest::SHA256, 48 => Digest::SHA384, 64 => Digest::SHA512 } # Internal: Detect digest class hash algorithm for digest bytes. # # While not elegant, all the supported digests have a unique bytesize. # # Returns Digest::Base or nil. def detect_digest_class(bytes) DIGEST_SIZES[bytes.bytesize] end ADD_VALUE_TO_DIGEST = { String => ->(val, digest) { digest << val }, FalseClass => ->(val, digest) { digest << 'FalseClass'.freeze }, TrueClass => ->(val, digest) { digest << 'TrueClass'.freeze }, NilClass => ->(val, digest) { digest << 'NilClass'.freeze }, Symbol => ->(val, digest) { digest << 'Symbol'.freeze digest << val.to_s }, Integer => ->(val, digest) { digest << 'Integer'.freeze digest << val.to_s }, Array => ->(val, digest) { digest << 'Array'.freeze val.each do |element| ADD_VALUE_TO_DIGEST[element.class].call(element, digest) end }, Hash => ->(val, digest) { digest << 'Hash'.freeze val.sort.each do |array| ADD_VALUE_TO_DIGEST[Array].call(array, digest) end }, Set => ->(val, digest) { digest << 'Set'.freeze ADD_VALUE_TO_DIGEST[Array].call(val.to_a, digest) }, Encoding => ->(val, digest) { digest << 'Encoding'.freeze digest << val.name }, } if 0.class != Integer # Ruby < 2.4 ADD_VALUE_TO_DIGEST[Fixnum] = ->(val, digest) { digest << 'Integer'.freeze digest << val.to_s } ADD_VALUE_TO_DIGEST[Bignum] = ->(val, digest) { digest << 'Integer'.freeze digest << val.to_s } end ADD_VALUE_TO_DIGEST.default_proc = ->(_, val) { raise TypeError, "couldn't digest #{ val }" } private_constant :ADD_VALUE_TO_DIGEST # Internal: Generate a hexdigest for a nested JSON serializable object. # # This is used for generating cache keys, so its pretty important its # wicked fast. Microbenchmarks away! # # obj - A JSON serializable object. # # Returns a String digest of the object. def digest(obj) digest = digest_class.new ADD_VALUE_TO_DIGEST[obj.class].call(obj, digest) digest.digest end # Internal: Pack a binary digest to a hex encoded string. # # bin - String bytes # # Returns hex String. def pack_hexdigest(bin) bin.unpack('H*').first end # Internal: Unpack a hex encoded digest string into binary bytes. # # hex - String hex # # Returns binary String. def unpack_hexdigest(hex) [hex].pack('H*') end # Internal: Pack a binary digest to a base64 encoded string. # # bin - String bytes # # Returns base64 String. def pack_base64digest(bin) [bin].pack('m0') end # Internal: Pack a binary digest to a urlsafe base64 encoded string. # # bin - String bytes # # Returns urlsafe base64 String. def pack_urlsafe_base64digest(bin) str = pack_base64digest(bin) str.tr!('+/'.freeze, '-_'.freeze) str.tr!('='.freeze, ''.freeze) str end # Internal: Maps digest class to the CSP hash algorithm name. HASH_ALGORITHMS = { Digest::SHA256 => 'sha256'.freeze, Digest::SHA384 => 'sha384'.freeze, Digest::SHA512 => 'sha512'.freeze } # Public: Generate hash for use in the `integrity` attribute of an asset tag # as per the subresource integrity specification. # # digest - The String byte digest of the asset content. # # Returns a String or nil if hash algorithm is incompatible. def integrity_uri(digest) case digest when Digest::Base digest_class = digest.class digest = digest.digest when String digest_class = DIGEST_SIZES[digest.bytesize] else raise TypeError, "unknown digest: #{digest.inspect}" end if hash_name = HASH_ALGORITHMS[digest_class] "#{hash_name}-#{pack_base64digest(digest)}" end end # Public: Generate hash for use in the `integrity` attribute of an asset tag # as per the subresource integrity specification. # # digest - The String hexbyte digest of the asset content. # # Returns a String or nil if hash algorithm is incompatible. def hexdigest_integrity_uri(hexdigest) integrity_uri(unpack_hexdigest(hexdigest)) end end end sprockets-3.7.2/lib/sprockets/directive_processor.rb000066400000000000000000000314061331222022000227140ustar00rootroot00000000000000require 'set' require 'shellwords' module Sprockets # The `DirectiveProcessor` is responsible for parsing and evaluating # directive comments in a source file. # # A directive comment starts with a comment prefix, followed by an "=", # then the directive name, then any arguments. # # // JavaScript # //= require "foo" # # # CoffeeScript # #= require "bar" # # /* CSS # *= require "baz" # */ # # This makes it possible to disable or modify the processor to do whatever # you'd like. You could add your own custom directives or invent your own # directive syntax. # # `Environment#processors` includes `DirectiveProcessor` by default. # # To remove the processor entirely: # # env.unregister_processor('text/css', Sprockets::DirectiveProcessor) # env.unregister_processor('application/javascript', Sprockets::DirectiveProcessor) # # Then inject your own preprocessor: # # env.register_processor('text/css', MyProcessor) # class DirectiveProcessor VERSION = '1' # Directives are denoted by a `=` followed by the name, then # argument list. # # A few different styles are allowed: # # // =require foo # //= require foo # //= require "foo" # DIRECTIVE_PATTERN = / ^ \W* = \s* (\w+.*?) (\*\/)? $ /x def self.instance @instance ||= new( # Deprecated: Default to C and Ruby comment styles comments: ["//", ["/*", "*/"]] + ["#", ["###", "###"]] ) end def self.call(input) instance.call(input) end def initialize(options = {}) @header_pattern = compile_header_pattern(Array(options[:comments])) end def call(input) dup._call(input) end def _call(input) @environment = input[:environment] @uri = input[:uri] @filename = input[:filename] @dirname = File.dirname(@filename) @content_type = input[:content_type] @required = Set.new(input[:metadata][:required]) @stubbed = Set.new(input[:metadata][:stubbed]) @links = Set.new(input[:metadata][:links]) @dependencies = Set.new(input[:metadata][:dependencies]) data, directives = process_source(input[:data]) process_directives(directives) { data: data, required: @required, stubbed: @stubbed, links: @links, dependencies: @dependencies } end protected # Directives will only be picked up if they are in the header # of the source file. C style (/* */), JavaScript (//), and # Ruby (#) comments are supported. # # Directives in comments after the first non-whitespace line # of code will not be processed. def compile_header_pattern(comments) re = comments.map { |c| case c when String "(?:#{Regexp.escape(c)}.*\\n?)+" when Array "(?:#{Regexp.escape(c[0])}(?m:.*?)#{Regexp.escape(c[1])})" else raise TypeError, "unknown comment type: #{c.class}" end }.join("|") Regexp.compile("\\A(?:(?m:\\s*)(?:#{re}))+") end def process_source(source) header = source[@header_pattern, 0] || "" body = $' || source header, directives = extract_directives(header) data = "" data.force_encoding(body.encoding) data << header << "\n" unless header.empty? data << body # Ensure body ends in a new line data << "\n" if data.length > 0 && data[-1] != "\n" return data, directives end # Returns an Array of directive structures. Each structure # is an Array with the line number as the first element, the # directive name as the second element, followed by any # arguments. # # [[1, "require", "foo"], [2, "require", "bar"]] # def extract_directives(header) processed_header = "" directives = [] header.lines.each_with_index do |line, index| if directive = line[DIRECTIVE_PATTERN, 1] name, *args = Shellwords.shellwords(directive) if respond_to?("process_#{name}_directive", true) directives << [index + 1, name, *args] # Replace directive line with a clean break line = "\n" end end processed_header << line end return processed_header.chomp, directives end # Gathers comment directives in the source and processes them. # Any directive method matching `process_*_directive` will # automatically be available. This makes it easy to extend the # processor. # # To implement a custom directive called `require_glob`, subclass # `Sprockets::DirectiveProcessor`, then add a method called # `process_require_glob_directive`. # # class DirectiveProcessor < Sprockets::DirectiveProcessor # def process_require_glob_directive # Dir["#{dirname}/#{glob}"].sort.each do |filename| # require(filename) # end # end # end # # Replace the current processor on the environment with your own: # # env.unregister_processor('text/css', Sprockets::DirectiveProcessor) # env.register_processor('text/css', DirectiveProcessor) # def process_directives(directives) directives.each do |line_number, name, *args| begin send("process_#{name}_directive", *args) rescue Exception => e e.set_backtrace(["#{@filename}:#{line_number}"] + e.backtrace) raise e end end end # The `require` directive functions similar to Ruby's own `require`. # It provides a way to declare a dependency on a file in your path # and ensures its only loaded once before the source file. # # `require` works with files in the environment path: # # //= require "foo.js" # # Extensions are optional. If your source file is ".js", it # assumes you are requiring another ".js". # # //= require "foo" # # Relative paths work too. Use a leading `./` to denote a relative # path: # # //= require "./bar" # def process_require_directive(path) @required << resolve(path, accept: @content_type, pipeline: :self) end # `require_self` causes the body of the current file to be inserted # before any subsequent `require` directives. Useful in CSS files, where # it's common for the index file to contain global styles that need to # be defined before other dependencies are loaded. # # /*= require "reset" # *= require_self # *= require_tree . # */ # def process_require_self_directive if @required.include?(@uri) raise ArgumentError, "require_self can only be called once per source file" end @required << @uri end # `require_directory` requires all the files inside a single # directory. It's similar to `path/*` since it does not follow # nested directories. # # //= require_directory "./javascripts" # def process_require_directory_directive(path = ".") path = expand_relative_dirname(:require_directory, path) require_paths(*@environment.stat_directory_with_dependencies(path)) end # `require_tree` requires all the nested files in a directory. # Its glob equivalent is `path/**/*`. # # //= require_tree "./public" # def process_require_tree_directive(path = ".") path = expand_relative_dirname(:require_tree, path) require_paths(*@environment.stat_sorted_tree_with_dependencies(path)) end # 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 will invalidate the cache of the # source file. # # This is useful if you are using ERB and File.read to pull # in contents from another file. # # //= depend_on "foo.png" # def process_depend_on_directive(path) resolve(path) end # Allows you to state a dependency on an asset without including # it. # # This is used for caching purposes. Any changes that would # invalid the asset dependency will invalidate the cache our the # source file. # # Unlike `depend_on`, the path must be a requirable asset. # # //= depend_on_asset "bar.js" # def process_depend_on_asset_directive(path) load(resolve(path)) end # Allows dependency to be excluded from the asset bundle. # # The `path` must be a valid asset and may or may not already # be part of the bundle. Once stubbed, it is blacklisted and # can't be brought back by any other `require`. # # //= stub "jquery" # def process_stub_directive(path) @stubbed << resolve(path, accept: @content_type, pipeline: :self) end # Declares a linked dependency on the target asset. # # The `path` must be a valid asset and should not already be part of the # bundle. Any linked assets will automatically be compiled along with the # current. # # /*= link "logo.png" */ # def process_link_directive(path) @links << load(resolve(path)).uri end # `link_directory` links all the files inside a single # directory. It's similar to `path/*` since it does not follow # nested directories. # # //= link_directory "./fonts" # # Use caution when linking against JS or CSS assets. Include an explicit # extension or content type in these cases # # //= link_directory "./scripts" .js # def process_link_directory_directive(path = ".", accept = nil) path = expand_relative_dirname(:link_directory, path) accept = expand_accept_shorthand(accept) link_paths(*@environment.stat_directory_with_dependencies(path), accept) end # `link_tree` links all the nested files in a directory. # Its glob equivalent is `path/**/*`. # # //= link_tree "./images" # # Use caution when linking against JS or CSS assets. Include an explicit # extension or content type in these cases # # //= link_tree "./styles" .css # def process_link_tree_directive(path = ".", accept = nil) path = expand_relative_dirname(:link_tree, path) accept = expand_accept_shorthand(accept) link_paths(*@environment.stat_sorted_tree_with_dependencies(path), accept) end private def expand_accept_shorthand(accept) if accept.nil? nil elsif accept.include?("/") accept elsif accept.start_with?(".") @environment.mime_exts[accept] else @environment.mime_exts[".#{accept}"] end end def require_paths(paths, deps) resolve_paths(paths, deps, accept: @content_type, pipeline: :self) do |uri| @required << uri end end def link_paths(paths, deps, accept) resolve_paths(paths, deps, accept: accept) do |uri| @links << load(uri).uri end end def resolve_paths(paths, deps, options = {}) @dependencies.merge(deps) paths.each do |subpath, stat| next if subpath == @filename || stat.directory? uri, deps = @environment.resolve(subpath, options.merge(compat: false)) @dependencies.merge(deps) yield uri if uri end end def expand_relative_dirname(directive, path) if @environment.relative_path?(path) path = File.expand_path(path, @dirname) stat = @environment.stat(path) if stat && stat.directory? path else raise ArgumentError, "#{directive} argument must be a directory" end else # The path must be relative and start with a `./`. raise ArgumentError, "#{directive} argument must be a relative path" end end def load(uri) asset = @environment.load(uri) @dependencies.merge(asset.metadata[:dependencies]) asset end def resolve(path, options = {}) # Prevent absolute paths in directives if @environment.absolute_path?(path) raise FileOutsidePaths, "can't require absolute file: #{path}" end uri, deps = @environment.resolve!(path, options.merge(base_path: @dirname)) @dependencies.merge(deps) uri end end end sprockets-3.7.2/lib/sprockets/eco_processor.rb000066400000000000000000000014041331222022000214770ustar00rootroot00000000000000require 'sprockets/autoload' module Sprockets # Processor engine class for the Eco compiler. Depends on the `eco` gem. # # For more infomation see: # # https://github.com/sstephenson/ruby-eco # https://github.com/sstephenson/eco # module EcoProcessor VERSION = '1' def self.cache_key @cache_key ||= "#{name}:#{Autoload::Eco::Source::VERSION}:#{VERSION}".freeze end # Compile template data with Eco compiler. # # Returns a JS function definition String. The result should be # assigned to a JS variable. # # # => "function(...) {...}" # def self.call(input) data = input[:data] input[:cache].fetch([cache_key, data]) do Autoload::Eco.compile(data) end end end end sprockets-3.7.2/lib/sprockets/eco_template.rb000066400000000000000000000005331331222022000212750ustar00rootroot00000000000000require 'sprockets/eco_processor' module Sprockets # Deprecated module EcoTemplate VERSION = EcoProcessor::VERSION def self.cache_key EcoProcessor.cache_key end def self.call(*args) Deprecation.new.warn "EcoTemplate is deprecated please use EcoProcessor instead" EcoProcessor.call(*args) end end end sprockets-3.7.2/lib/sprockets/ejs_processor.rb000066400000000000000000000012701331222022000215130ustar00rootroot00000000000000require 'sprockets/autoload' module Sprockets # Processor engine class for the EJS compiler. Depends on the `ejs` gem. # # For more infomation see: # # https://github.com/sstephenson/ruby-ejs # module EjsProcessor VERSION = '1' def self.cache_key @cache_key ||= "#{name}:#{VERSION}".freeze end # Compile template data with EJS compiler. # # Returns a JS function definition String. The result should be # assigned to a JS variable. # # # => "function(obj){...}" # def self.call(input) data = input[:data] input[:cache].fetch([cache_key, data]) do Autoload::EJS.compile(data) end end end end sprockets-3.7.2/lib/sprockets/ejs_template.rb000066400000000000000000000005331331222022000213100ustar00rootroot00000000000000require 'sprockets/ejs_processor' module Sprockets # Deprecated module EjsTemplate VERSION = EjsProcessor::VERSION def self.cache_key EjsProcessor.cache_key end def self.call(*args) Deprecation.new.warn "EjsTemplate is deprecated please use EjsProcessor instead" EjsProcessor.call(*args) end end end sprockets-3.7.2/lib/sprockets/encoding_utils.rb000066400000000000000000000146101331222022000216430ustar00rootroot00000000000000require 'base64' require 'stringio' require 'zlib' module Sprockets # Internal: HTTP transport encoding and charset detecting related functions. # Mixed into Environment. module EncodingUtils extend self ## Binary encodings ## # Public: Use deflate to compress data. # # str - String data # # Returns a compressed String def deflate(str) deflater = Zlib::Deflate.new( Zlib::BEST_COMPRESSION, -Zlib::MAX_WBITS, Zlib::MAX_MEM_LEVEL, Zlib::DEFAULT_STRATEGY ) deflater << str deflater.finish end # Internal: Unmarshal optionally deflated data. # # Checks leading marshal header to see if the bytes are uncompressed # otherwise inflate the data an unmarshal. # # str - Marshaled String # window_bits - Integer deflate window size. See ZLib::Inflate.new() # # Returns unmarshaled Object or raises an Exception. def unmarshaled_deflated(str, window_bits = -Zlib::MAX_WBITS) major, minor = str[0], str[1] if major && major.ord == Marshal::MAJOR_VERSION && minor && minor.ord <= Marshal::MINOR_VERSION marshaled = str else begin marshaled = Zlib::Inflate.new(window_bits).inflate(str) rescue Zlib::DataError marshaled = str end end Marshal.load(marshaled) end # Public: Use gzip to compress data. # # str - String data # # Returns a compressed String def gzip(str) io = StringIO.new gz = Zlib::GzipWriter.new(io, Zlib::BEST_COMPRESSION) gz.mtime = 1 gz << str gz.finish io.string end # Public: Use base64 to encode data. # # str - String data # # Returns a encoded String def base64(str) Base64.strict_encode64(str) end ## Charset encodings ## # Internal: Shorthand aliases for detecter functions. CHARSET_DETECT = {} # Internal: Mapping unicode encodings to byte order markers. BOM = { Encoding::UTF_32LE => [0xFF, 0xFE, 0x00, 0x00], Encoding::UTF_32BE => [0x00, 0x00, 0xFE, 0xFF], Encoding::UTF_8 => [0xEF, 0xBB, 0xBF], Encoding::UTF_16LE => [0xFF, 0xFE], Encoding::UTF_16BE => [0xFE, 0xFF] } # Public: Basic string detecter. # # Attempts to parse any Unicode BOM otherwise falls back to the # environment's external encoding. # # str - ASCII-8BIT encoded String # # Returns encoded String. def detect(str) str = detect_unicode_bom(str) # Attempt Charlock detection if str.encoding == Encoding::BINARY charlock_detect(str) end # Fallback to environment's external encoding if str.encoding == Encoding::BINARY str.force_encoding(Encoding.default_external) end str end CHARSET_DETECT[:default] = method(:detect) # Internal: Use Charlock Holmes to detect encoding. # # To enable this code path, require 'charlock_holmes' # # Returns encoded String. def charlock_detect(str) if defined? CharlockHolmes::EncodingDetector if detected = CharlockHolmes::EncodingDetector.detect(str) str.force_encoding(detected[:encoding]) if detected[:encoding] end end str end # Public: Detect Unicode string. # # Attempts to parse Unicode BOM and falls back to UTF-8. # # str - ASCII-8BIT encoded String # # Returns encoded String. def detect_unicode(str) str = detect_unicode_bom(str) # Fallback to UTF-8 if str.encoding == Encoding::BINARY str.force_encoding(Encoding::UTF_8) end str end CHARSET_DETECT[:unicode] = method(:detect_unicode) # Public: Detect and strip BOM from possible unicode string. # # str - ASCII-8BIT encoded String # # Returns UTF 8/16/32 encoded String without BOM or the original String if # no BOM was present. def detect_unicode_bom(str) bom_bytes = str.byteslice(0, 4).bytes.to_a BOM.each do |encoding, bytes| if bom_bytes[0, bytes.size] == bytes str = str.dup str.force_encoding(Encoding::BINARY) str.slice!(0, bytes.size) str.force_encoding(encoding) return str end end return str end # Public: Detect and strip @charset from CSS style sheet. # # str - String. # # Returns a encoded String. def detect_css(str) str = detect_unicode_bom(str) if name = scan_css_charset(str) encoding = Encoding.find(name) str = str.dup str.force_encoding(encoding) len = "@charset \"#{name}\";".encode(encoding).size str.slice!(0, len) str end # Fallback to UTF-8 if str.encoding == Encoding::BINARY str.force_encoding(Encoding::UTF_8) end str end CHARSET_DETECT[:css] = method(:detect_css) # Internal: @charset bytes CHARSET_START = [0x40, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x20, 0x22] CHARSET_SIZE = CHARSET_START.size # Internal: Scan binary CSS string for @charset encoding name. # # str - ASCII-8BIT encoded String # # Returns encoding String name or nil. def scan_css_charset(str) buf = [] i = 0 str.each_byte.each do |byte| # Halt on line breaks break if byte == 0x0A || byte == 0x0D # Only ascii bytes next unless 0x0 < byte && byte <= 0xFF if i < CHARSET_SIZE elsif i == CHARSET_SIZE if buf == CHARSET_START buf = [] else break end elsif byte == 0x22 return buf.pack('C*') end buf << byte i += 1 end nil end # Public: Detect charset from HTML document. # # Attempts to parse any Unicode BOM otherwise attempt Charlock detection # and finally falls back to the environment's external encoding. # # str - String. # # Returns a encoded String. def detect_html(str) str = detect_unicode_bom(str) # Attempt Charlock detection if str.encoding == Encoding::BINARY charlock_detect(str) end # Fallback to environment's external encoding if str.encoding == Encoding::BINARY str.force_encoding(Encoding.default_external) end str end CHARSET_DETECT[:html] = method(:detect_html) end end sprockets-3.7.2/lib/sprockets/engines.rb000066400000000000000000000060471331222022000202720ustar00rootroot00000000000000require 'sprockets/legacy_tilt_processor' require 'sprockets/utils' module Sprockets # `Engines` provides a global and `Environment` instance registry. # # An engine is a type of processor that is bound to a filename # extension. `application.js.coffee` indicates that the # `CoffeeScriptProcessor` engine will be ran on the file. # # Extensions can be stacked and will be evaulated from right to # left. `application.js.coffee.erb` will first run `ERBProcessor` # then `CoffeeScriptProcessor`. # # All `Engine`s must follow the `Template` interface. It is # recommended to subclass `Template`. # # Its recommended that you register engine changes on your local # `Environment` instance. # # environment.register_engine '.foo', FooProcessor # # The global registry is exposed for plugins to register themselves. # # Sprockets.register_engine '.sass', SassProcessor # module Engines include Utils # Returns a `Hash` of `Engine`s registered on the `Environment`. # If an `ext` argument is supplied, the `Engine` associated with # that extension will be returned. # # environment.engines # # => {".coffee" => CoffeeScriptProcessor, ".sass" => SassProcessor, ...} # def engines config[:engines] end # Internal: Returns a `Hash` of engine extensions to mime types. # # # => { '.coffee' => 'application/javascript' } def engine_mime_types config[:engine_mime_types] end # Registers a new Engine `klass` for `ext`. If the `ext` already # has an engine registered, it will be overridden. # # environment.register_engine '.coffee', CoffeeScriptProcessor # def register_engine(ext, klass, options = {}) unless options[:silence_deprecation] msg = <<-MSG Sprockets method `register_engine` is deprecated. Please register a mime type using `register_mime_type` then use `register_compressor` or `register_transformer`. https://github.com/rails/sprockets/blob/master/guides/extending_sprockets.md#supporting-all-versions-of-sprockets-in-processors MSG Deprecation.new([caller.first]).warn(msg) end ext = Sprockets::Utils.normalize_extension(ext) self.computed_config = {} if klass.respond_to?(:call) processor = klass self.config = hash_reassoc(config, :engines) do |engines| engines.merge(ext => klass) end if options[:mime_type] self.config = hash_reassoc(config, :engine_mime_types) do |mime_types| mime_types.merge(ext.to_s => options[:mime_type]) end end else processor = LegacyTiltProcessor.new(klass) self.config = hash_reassoc(config, :engines) do |engines| engines.merge(ext => processor) end if klass.respond_to?(:default_mime_type) && klass.default_mime_type self.config = hash_reassoc(config, :engine_mime_types) do |mime_types| mime_types.merge(ext.to_s => klass.default_mime_type) end end end end end end sprockets-3.7.2/lib/sprockets/environment.rb000066400000000000000000000020721331222022000212000ustar00rootroot00000000000000require 'sprockets/base' require 'sprockets/cache/memory_store' require 'sprockets/cached_environment' module Sprockets class Environment < Base # `Environment` should initialized with your application's root # directory. This should be the same as your Rails or Rack root. # # env = Environment.new(Rails.root) # def initialize(root = ".") initialize_configuration(Sprockets) self.root = root self.cache = Cache::MemoryStore.new yield self if block_given? end # Returns a cached version of the environment. # # All its file system calls are cached which makes `cached` much # faster. This behavior is ideal in production since the file # system only changes between deploys. def cached CachedEnvironment.new(self) end alias_method :index, :cached def find_asset(*args) cached.find_asset(*args) end def find_all_linked_assets(*args, &block) cached.find_all_linked_assets(*args, &block) end def load(*args) cached.load(*args) end end end sprockets-3.7.2/lib/sprockets/erb_processor.rb000066400000000000000000000013131331222022000215000ustar00rootroot00000000000000require 'erb' module Sprockets class ERBProcessor # Public: Return singleton instance with default options. # # Returns ERBProcessor object. def self.instance @instance ||= new end def self.call(input) instance.call(input) end def initialize(&block) @block = block end def call(input) engine = ::ERB.new(input[:data], nil, '<>') context = input[:environment].context_class.new(input) klass = (class << context; self; end) klass.class_eval(&@block) if @block engine.def_method(klass, :_evaluate_template, input[:filename]) data = context._evaluate_template context.metadata.merge(data: data) end end end sprockets-3.7.2/lib/sprockets/erb_template.rb000066400000000000000000000003571331222022000213030ustar00rootroot00000000000000require 'sprockets/erb_processor' module Sprockets # Deprecated class ERBTemplate < ERBProcessor def call(*args) Deprecation.new.warn "ERBTemplate is deprecated please use ERBProcessor instead" super end end end sprockets-3.7.2/lib/sprockets/errors.rb000066400000000000000000000006621331222022000201530ustar00rootroot00000000000000# Define some basic Sprockets error classes module Sprockets class Error < StandardError; end class ArgumentError < Error; end class ContentTypeMismatch < Error; end class NotImplementedError < Error; end class NotFound < Error; end class ConversionError < NotFound; end class FileNotFound < NotFound; end class FileOutsidePaths < NotFound; end end sprockets-3.7.2/lib/sprockets/file_reader.rb000066400000000000000000000007631331222022000211020ustar00rootroot00000000000000require 'set' module Sprockets # Internal: The first processor in the pipeline that reads the file into # memory and passes it along as `input[:data]`. class FileReader def self.call(input) env = input[:environment] data = env.read_file(input[:filename], input[:content_type]) dependencies = Set.new(input[:metadata][:dependencies]) dependencies += [env.build_file_digest_uri(input[:filename])] { data: data, dependencies: dependencies } end end end sprockets-3.7.2/lib/sprockets/http_utils.rb000066400000000000000000000067231331222022000210420ustar00rootroot00000000000000module Sprockets # Internal: HTTP URI utilities. Many adapted from Rack::Utils. Mixed into # Environment. module HTTPUtils extend self # Public: Test mime type against mime range. # # match_mime_type?('text/html', 'text/*') => true # match_mime_type?('text/plain', '*') => true # match_mime_type?('text/html', 'application/json') => false # # Returns true if the given value is a mime match for the given mime match # specification, false otherwise. def match_mime_type?(value, matcher) v1, v2 = value.split('/', 2) m1, m2 = matcher.split('/', 2) (m1 == '*' || v1 == m1) && (m2.nil? || m2 == '*' || m2 == v2) end # Public: Return values from Hash where the key matches the mime type. # # hash - Hash of String matcher keys to Object values # mime_type - String mime type # # Returns Array of Object values. def match_mime_type_keys(hash, mime_type) type, subtype = mime_type.split('/', 2) [ hash["*"], hash["*/*"], hash["#{type}/*"], hash["#{type}/#{subtype}"] ].compact end # Internal: Parse Accept header quality values. # # Adapted from Rack::Utils#q_values. # # Returns an Array of [String, Float]. def parse_q_values(values) values.to_s.split(/\s*,\s*/).map do |part| value, parameters = part.split(/\s*;\s*/, 2) quality = 1.0 if md = /\Aq=([\d.]+)/.match(parameters) quality = md[1].to_f end [value, quality] end end # Internal: Find all qvalue matches from an Array of available options. # # Adapted from Rack::Utils#q_values. # # Returns Array of matched Strings from available Array or []. def find_q_matches(q_values, available, &matcher) matcher ||= lambda { |a, b| a == b } matches = [] case q_values when Array when String q_values = parse_q_values(q_values) when NilClass q_values = [] else raise TypeError, "unknown q_values type: #{q_values.class}" end q_values.each do |accepted, quality| if match = available.find { |option| matcher.call(option, accepted) } matches << [match, quality] end end matches.sort_by! { |match, quality| -quality } matches.map! { |match, quality| match } matches end # Internal: Find the best qvalue match from an Array of available options. # # Adapted from Rack::Utils#q_values. # # Returns the matched String from available Array or nil. def find_best_q_match(q_values, available, &matcher) find_q_matches(q_values, available, &matcher).first end # Internal: Find the all qvalue match from an Array of available mime type # options. # # Adapted from Rack::Utils#q_values. # # Returns Array of matched mime type Strings from available Array or []. def find_mime_type_matches(q_value_header, available) find_q_matches(q_value_header, available) do |a, b| match_mime_type?(a, b) end end # Internal: Find the best qvalue match from an Array of available mime type # options. # # Adapted from Rack::Utils#q_values. # # Returns the matched mime type String from available Array or nil. def find_best_mime_type_match(q_value_header, available) find_best_q_match(q_value_header, available) do |a, b| match_mime_type?(a, b) end end end end sprockets-3.7.2/lib/sprockets/jst_processor.rb000066400000000000000000000022431331222022000215330ustar00rootroot00000000000000module Sprockets # Public: .jst engine. # # Exports server side compiled templates to an object. # # Name your template "users/show.jst.ejs", "users/new.jst.eco", etc. # # To accept the default options # # environment.register_engine '.jst', # JstProcessor, # mime_type: 'application/javascript' # # Change the default namespace. # # environment.register_engine '.jst', # JstProcessor.new(namespace: 'App.templates'), # mime_type: 'application/javascript' # class JstProcessor def self.default_namespace 'this.JST' end # Public: Return singleton instance with default options. # # Returns JstProcessor object. def self.instance @instance ||= new end def self.call(input) instance.call(input) end def initialize(options = {}) @namespace = options[:namespace] || self.class.default_namespace end def call(input) data = input[:data].gsub(/$(.)/m, "\\1 ").strip key = input[:name] <<-JST (function() { #{@namespace} || (#{@namespace} = {}); #{@namespace}[#{key.inspect}] = #{data}; }).call(this); JST end end end sprockets-3.7.2/lib/sprockets/legacy.rb000066400000000000000000000222011331222022000200740ustar00rootroot00000000000000require 'pathname' require 'sprockets/asset' require 'sprockets/base' require 'sprockets/cached_environment' require 'sprockets/context' require 'sprockets/manifest' require 'sprockets/resolve' module Sprockets autoload :CoffeeScriptTemplate, 'sprockets/coffee_script_template' autoload :EcoTemplate, 'sprockets/eco_template' autoload :EjsTemplate, 'sprockets/ejs_template' autoload :ERBTemplate, 'sprockets/erb_template' autoload :SassTemplate, 'sprockets/sass_template' autoload :ScssTemplate, 'sprockets/sass_template' # Deprecated Index = CachedEnvironment class Base include Resolve # Deprecated: Change default return type of resolve() to return 2.x # compatible plain filename String. 4.x will always return an Asset URI # and a set of file system dependencies that had to be read to compute the # result. # # 2.x # # resolve("foo.js") # # => "/path/to/app/javascripts/foo.js" # # 3.x # # resolve("foo.js") # # => "/path/to/app/javascripts/foo.js" # # resolve("foo.js", compat: true) # # => "/path/to/app/javascripts/foo.js" # # resolve("foo.js", compat: false) # # => [ # # "file:///path/to/app/javascripts/foo.js?type=application/javascript" # # # # # ] # # 4.x # # resolve("foo.js") # # => [ # # "file:///path/to/app/javascripts/foo.js?type=application/javascript" # # # # # ] # def resolve_with_compat(path, options = {}) options = options.dup if options.delete(:compat) { true } uri, _ = resolve_without_compat(path, options) if uri path, _ = parse_asset_uri(uri) path else nil end else resolve_without_compat(path, options) end end alias_method :resolve_without_compat, :resolve alias_method :resolve, :resolve_with_compat # Deprecated: Iterate over all logical paths with a matcher. # # Remove from 4.x. # # args - List of matcher objects. # # Returns Enumerator if no block is given. def each_logical_path(*args, &block) return to_enum(__method__, *args) unless block_given? filters = args.flatten.map { |arg| Manifest.compile_match_filter(arg) } logical_paths.each do |a, b| if filters.any? { |f| f.call(a, b) } if block.arity == 2 yield a, b else yield a end end end nil end # Deprecated: Enumerate over all logical paths in the environment. # # Returns an Enumerator of [logical_path, filename]. def logical_paths return to_enum(__method__) unless block_given? seen = Set.new paths.each do |load_path| stat_tree(load_path).each do |filename, stat| next unless stat.file? path = split_subpath(load_path, filename) path, mime_type, _, _ = parse_path_extnames(path) path = normalize_logical_path(path) path += mime_types[mime_type][:extensions].first if mime_type if !seen.include?(path) yield path, filename seen << path end end end nil end def cache_get(key) cache.get(key) end def cache_set(key, value) cache.set(key, value) end def normalize_logical_path(path) dirname, basename = File.split(path) path = dirname if basename == 'index' path end private # Deprecated: Seriously. def matches_filter(filters, logical_path, filename) return true if filters.empty? filters.any? do |filter| if filter.is_a?(Regexp) filter.match(logical_path) elsif filter.respond_to?(:call) if filter.arity == 1 filter.call(logical_path) else filter.call(logical_path, filename.to_s) end else File.fnmatch(filter.to_s, logical_path) end end end # URI.unescape is deprecated on 1.9. We need to use URI::Parser # if its available. if defined? URI::DEFAULT_PARSER def unescape(str) str = URI::DEFAULT_PARSER.unescape(str) str.force_encoding(Encoding.default_internal) if Encoding.default_internal str end else def unescape(str) URI.unescape(str) end end end class Asset # Deprecated: Use #filename instead. # # Returns Pathname. def pathname @pathname ||= Pathname.new(filename) end # Deprecated: 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. # # Use Asset#included instead. Keeping a full copy of the bundle's processed # assets in memory (and in cache) is expensive and redundant. The common use # case is to relink to the assets anyway. # # Returns Array of Assets. def to_a if metadata[:included] metadata[:included].map { |uri| @environment.load(uri) } else [self] end end # Deprecated: Get all required Assets. # # See Asset#to_a # # Returns Array of Assets. def dependencies to_a.reject { |a| a.filename.eql?(self.filename) } end # Deprecated: Returns Time of the last time the source was modified. # # Time resolution is normalized to the nearest second. # # Returns Time. def mtime Time.at(@mtime) end end class Context # Deprecated: Change default return type of resolve() to return 2.x # compatible plain filename String. 4.x will always return an Asset URI. # # 2.x # # resolve("foo.js") # # => "/path/to/app/javascripts/foo.js" # # 3.x # # resolve("foo.js") # # => "/path/to/app/javascripts/foo.js" # # resolve("foo.js", compat: true) # # => "/path/to/app/javascripts/foo.js" # # resolve("foo.js", compat: false) # # => "file:///path/to/app/javascripts/foo.js?type=application/javascript" # # 4.x # # resolve("foo.js") # # => "file:///path/to/app/javascripts/foo.js?type=application/javascript" # def resolve_with_compat(path, options = {}) options = options.dup # Support old :content_type option, prefer :accept going forward if type = options.delete(:content_type) type = self.content_type if type == :self options[:accept] ||= type end if options.delete(:compat) { true } uri = resolve_without_compat(path, options) path, _ = environment.parse_asset_uri(uri) path else resolve_without_compat(path, options) end end alias_method :resolve_without_compat, :resolve alias_method :resolve, :resolve_with_compat end class Manifest # Deprecated: Compile logical path matching filter into a proc that can be # passed to logical_paths.select(&proc). # # compile_match_filter(proc { |logical_path| # File.extname(logical_path) == '.js' # }) # # compile_match_filter(/application.js/) # # compile_match_filter("foo/*.js") # # Returns a Proc or raise a TypeError. def self.compile_match_filter(filter) # If the filter is already a proc, great nothing to do. if filter.respond_to?(:call) filter # If the filter is a regexp, wrap it in a proc that tests it against the # logical path. elsif filter.is_a?(Regexp) proc { |logical_path| filter.match(logical_path) } elsif filter.is_a?(String) # If its an absolute path, detect the matching full filename if PathUtils.absolute_path?(filter) proc { |logical_path, filename| filename == filter.to_s } else # Otherwise do an fnmatch against the logical path. proc { |logical_path| File.fnmatch(filter.to_s, logical_path) } end else raise TypeError, "unknown filter type: #{filter.inspect}" end end def self.simple_logical_path?(str) str.is_a?(String) && !PathUtils.absolute_path?(str) && str !~ /\*|\*\*|\?|\[|\]|\{|\}/ end def self.compute_alias_logical_path(path) dirname, basename = File.split(path) extname = File.extname(basename) if File.basename(basename, extname) == 'index' "#{dirname}#{extname}" else nil end end # Deprecated: Filter logical paths in environment. Useful for selecting what # files you want to compile. # # Returns an Enumerator. def filter_logical_paths(*args) filters = args.flatten.map { |arg| self.class.compile_match_filter(arg) } environment.cached.logical_paths.select do |a, b| filters.any? { |f| f.call(a, b) } end end # Deprecated alias. alias_method :find_logical_paths, :filter_logical_paths end end sprockets-3.7.2/lib/sprockets/legacy_proc_processor.rb000066400000000000000000000013141331222022000232200ustar00rootroot00000000000000require 'delegate' module Sprockets # Deprecated: Wraps legacy process Procs with new processor call signature. # # Will be removed in Sprockets 4.x. # # LegacyProcProcessor.new(:compress, # proc { |context, data| data.gsub(...) }) # class LegacyProcProcessor < Delegator def initialize(name, proc) @name = name @proc = proc end def __getobj__ @proc end def name "Sprockets::LegacyProcProcessor (#{@name})" end def to_s name end def call(input) context = input[:environment].context_class.new(input) data = @proc.call(context, input[:data]) context.metadata.merge(data: data.to_str) end end end sprockets-3.7.2/lib/sprockets/legacy_tilt_processor.rb000066400000000000000000000012271331222022000232340ustar00rootroot00000000000000require 'delegate' module Sprockets # Deprecated: Wraps legacy engine and process Tilt templates with new # processor call signature. # # Will be removed in Sprockets 4.x. # # LegacyTiltProcessor.new(Tilt::CoffeeScriptProcessor) # class LegacyTiltProcessor < Delegator def initialize(klass) @klass = klass end def __getobj__ @klass end def call(input) filename = input[:filename] data = input[:data] context = input[:environment].context_class.new(input) data = @klass.new(filename) { data }.render(context, {}) context.metadata.merge(data: data.to_str) end end end sprockets-3.7.2/lib/sprockets/loader.rb000066400000000000000000000335221331222022000201060ustar00rootroot00000000000000require 'sprockets/asset' require 'sprockets/digest_utils' require 'sprockets/engines' require 'sprockets/errors' require 'sprockets/file_reader' require 'sprockets/mime' require 'sprockets/path_utils' require 'sprockets/processing' require 'sprockets/processor_utils' require 'sprockets/resolve' require 'sprockets/transformers' require 'sprockets/uri_utils' require 'sprockets/unloaded_asset' module Sprockets # The loader phase takes a asset URI location and returns a constructed Asset # object. module Loader include DigestUtils, PathUtils, ProcessorUtils, URIUtils include Engines, Mime, Processing, Resolve, Transformers # Public: Load Asset by Asset URI. # # uri - A String containing complete URI to a file including schema # and full path such as: # "file:///Path/app/assets/js/app.js?type=application/javascript" # # # Returns Asset. def load(uri) unloaded = UnloadedAsset.new(uri, self) if unloaded.params.key?(:id) unless asset = asset_from_cache(unloaded.asset_key) id = unloaded.params.delete(:id) uri_without_id = build_asset_uri(unloaded.filename, unloaded.params) asset = load_from_unloaded(UnloadedAsset.new(uri_without_id, self)) if asset[:id] != id @logger.warn "Sprockets load error: Tried to find #{uri}, but latest was id #{asset[:id]}" end end else asset = fetch_asset_from_dependency_cache(unloaded) do |paths| # When asset is previously generated, its "dependencies" are stored in the cache. # The presence of `paths` indicates dependencies were stored. # We can check to see if the dependencies have not changed by "resolving" them and # generating a digest key from the resolved entries. If this digest key has not # changed the asset will be pulled from cache. # # If this `paths` is present but the cache returns nothing then `fetch_asset_from_dependency_cache` # will confusingly be called again with `paths` set to nil where the asset will be # loaded from disk. if paths digest = DigestUtils.digest(resolve_dependencies(paths)) if uri_from_cache = cache.get(unloaded.digest_key(digest), true) asset_from_cache(UnloadedAsset.new(uri_from_cache, self).asset_key) end else load_from_unloaded(unloaded) end end end Asset.new(self, asset) end private # Internal: Load asset hash from cache # # key - A String containing lookup information for an asset # # This method converts all "compressed" paths to absolute paths. # Returns a hash of values representing an asset def asset_from_cache(key) asset = cache.get(key, true) if asset asset[:uri] = expand_from_root(asset[:uri]) asset[:load_path] = expand_from_root(asset[:load_path]) asset[:filename] = expand_from_root(asset[:filename]) asset[:metadata][:included].map! { |uri| expand_from_root(uri) } if asset[:metadata][:included] asset[:metadata][:links].map! { |uri| expand_from_root(uri) } if asset[:metadata][:links] asset[:metadata][:stubbed].map! { |uri| expand_from_root(uri) } if asset[:metadata][:stubbed] asset[:metadata][:required].map! { |uri| expand_from_root(uri) } if asset[:metadata][:required] asset[:metadata][:dependencies].map! { |uri| uri.start_with?("file-digest://") ? expand_from_root(uri) : uri } if asset[:metadata][:dependencies] asset[:metadata].each_key do |k| next unless k =~ /_dependencies\z/ asset[:metadata][k].map! { |uri| expand_from_root(uri) } end end asset end # Internal: Loads an asset and saves it to cache # # unloaded - An UnloadedAsset # # This method is only called when the given unloaded asset could not be # successfully pulled from cache. def load_from_unloaded(unloaded) unless file?(unloaded.filename) raise FileNotFound, "could not find file: #{unloaded.filename}" end load_path, logical_path = paths_split(config[:paths], unloaded.filename) unless load_path raise FileOutsidePaths, "#{unloaded.filename} is no longer under a load path: #{self.paths.join(', ')}" end logical_path, file_type, engine_extnames, _ = parse_path_extnames(logical_path) name = logical_path if pipeline = unloaded.params[:pipeline] logical_path += ".#{pipeline}" end if type = unloaded.params[:type] logical_path += config[:mime_types][type][:extensions].first end if type != file_type && !config[:transformers][file_type][type] raise ConversionError, "could not convert #{file_type.inspect} to #{type.inspect}" end processors = processors_for(type, file_type, engine_extnames, pipeline) processors_dep_uri = build_processors_uri(type, file_type, engine_extnames, pipeline) dependencies = config[:dependencies] + [processors_dep_uri] # Read into memory and process if theres a processor pipeline if processors.any? result = call_processors(processors, { environment: self, cache: self.cache, uri: unloaded.uri, filename: unloaded.filename, load_path: load_path, name: name, content_type: type, metadata: { dependencies: dependencies } }) validate_processor_result!(result) source = result.delete(:data) metadata = result metadata[:charset] = source.encoding.name.downcase unless metadata.key?(:charset) metadata[:digest] = digest(source) metadata[:length] = source.bytesize else dependencies << build_file_digest_uri(unloaded.filename) metadata = { digest: file_digest(unloaded.filename), length: self.stat(unloaded.filename).size, dependencies: dependencies } end asset = { uri: unloaded.uri, load_path: load_path, filename: unloaded.filename, name: name, logical_path: logical_path, content_type: type, source: source, metadata: metadata, dependencies_digest: DigestUtils.digest(resolve_dependencies(metadata[:dependencies])) } asset[:id] = pack_hexdigest(digest(asset)) asset[:uri] = build_asset_uri(unloaded.filename, unloaded.params.merge(id: asset[:id])) # Deprecated: Avoid tracking Asset mtime asset[:mtime] = metadata[:dependencies].map { |u| if u.start_with?("file-digest:") s = self.stat(parse_file_digest_uri(u)) s ? s.mtime.to_i : nil else nil end }.compact.max asset[:mtime] ||= self.stat(unloaded.filename).mtime.to_i store_asset(asset, unloaded) asset end # Internal: Save a given asset to the cache # # asset - A hash containing values of loaded asset # unloaded - The UnloadedAsset used to lookup the `asset` # # This method converts all absolute paths to "compressed" paths # which are relative if they're in the root. def store_asset(asset, unloaded) # Save the asset in the cache under the new URI cached_asset = asset.dup cached_asset[:uri] = compress_from_root(asset[:uri]) cached_asset[:filename] = compress_from_root(asset[:filename]) cached_asset[:load_path] = compress_from_root(asset[:load_path]) if cached_asset[:metadata] # Deep dup to avoid modifying `asset` cached_asset[:metadata] = cached_asset[:metadata].dup if cached_asset[:metadata][:included] && !cached_asset[:metadata][:included].empty? cached_asset[:metadata][:included] = cached_asset[:metadata][:included].dup cached_asset[:metadata][:included].map! { |uri| compress_from_root(uri) } end if cached_asset[:metadata][:links] && !cached_asset[:metadata][:links].empty? cached_asset[:metadata][:links] = cached_asset[:metadata][:links].dup cached_asset[:metadata][:links].map! { |uri| compress_from_root(uri) } end if cached_asset[:metadata][:stubbed] && !cached_asset[:metadata][:stubbed].empty? cached_asset[:metadata][:stubbed] = cached_asset[:metadata][:stubbed].dup cached_asset[:metadata][:stubbed].map! { |uri| compress_from_root(uri) } end if cached_asset[:metadata][:required] && !cached_asset[:metadata][:required].empty? cached_asset[:metadata][:required] = cached_asset[:metadata][:required].dup cached_asset[:metadata][:required].map! { |uri| compress_from_root(uri) } end if cached_asset[:metadata][:dependencies] && !cached_asset[:metadata][:dependencies].empty? cached_asset[:metadata][:dependencies] = cached_asset[:metadata][:dependencies].dup cached_asset[:metadata][:dependencies].map! do |uri| uri.start_with?("file-digest://".freeze) ? compress_from_root(uri) : uri end end # compress all _dependencies in metadata like `sass_dependencies` cached_asset[:metadata].each do |key, value| next unless key =~ /_dependencies\z/ cached_asset[:metadata][key] = value.dup cached_asset[:metadata][key].map! {|uri| compress_from_root(uri) } end end # Unloaded asset and stored_asset now have a different URI stored_asset = UnloadedAsset.new(asset[:uri], self) cache.set(stored_asset.asset_key, cached_asset, true) # Save the new relative path for the digest key of the unloaded asset cache.set(unloaded.digest_key(asset[:dependencies_digest]), stored_asset.compressed_path, true) end # Internal: Resolve set of dependency URIs. # # uris - An Array of "dependencies" for example: # ["environment-version", "environment-paths", "processors:type=text/css&file_type=text/css", # "file-digest:///Full/path/app/assets/stylesheets/application.css", # "processors:type=text/css&file_type=text/css&pipeline=self", # "file-digest:///Full/path/app/assets/stylesheets"] # # Returns back array of things that the given uri dpends on # For example the environment version, if you're using a different version of sprockets # then the dependencies should be different, this is used only for generating cache key # for example the "environment-version" may be resolved to "environment-1.0-3.2.0" for # version "3.2.0" of sprockets. # # Any paths that are returned are converted to relative paths # # Returns array of resolved dependencies def resolve_dependencies(uris) uris.map { |uri| resolve_dependency(uri) } end # Internal: Retrieves an asset based on its digest # # unloaded - An UnloadedAsset # limit - A Fixnum which sets the maximum number of versions of "histories" # stored in the cache # # This method attempts to retrieve the last `limit` number of histories of an asset # from the cache a "history" which is an array of unresolved "dependencies" that the asset needs # to compile. In this case A dependency can refer to either an asset i.e. index.js # may rely on jquery.js (so jquery.js is a depndency), or other factors that may affect # compilation, such as the VERSION of sprockets (i.e. the environment) and what "processors" # are used. # # For example a history array may look something like this # # [["environment-version", "environment-paths", "processors:type=text/css&file_type=text/css", # "file-digest:///Full/path/app/assets/stylesheets/application.css", # "processors:type=text/css&file_digesttype=text/css&pipeline=self", # "file-digest:///Full/path/app/assets/stylesheets"]] # # Where the first entry is a Set of dependencies for last generated version of that asset. # Multiple versions are stored since sprockets keeps the last `limit` number of assets # generated present in the system. # # If a "history" of dependencies is present in the cache, each version of "history" will be # yielded to the passed block which is responsible for loading the asset. If found, the existing # history will be saved with the dependency that found a valid asset moved to the front. # # If no history is present, or if none of the histories could be resolved to a valid asset then, # the block is yielded to and expected to return a valid asset. # When this happens the dependencies for the returned asset are added to the "history", and older # entries are removed if the "history" is above `limit`. def fetch_asset_from_dependency_cache(unloaded, limit = 3) key = unloaded.dependency_history_key history = cache.get(key) || [] history.each_with_index do |deps, index| expanded_deps = deps.map do |path| path.start_with?("file-digest://") ? expand_from_root(path) : path end if asset = yield(expanded_deps) cache.set(key, history.rotate!(index)) if index > 0 return asset end end asset = yield deps = asset[:metadata][:dependencies].dup.map! do |uri| uri.start_with?("file-digest://") ? compress_from_root(uri) : uri end cache.set(key, history.unshift(deps).take(limit)) asset end end end sprockets-3.7.2/lib/sprockets/manifest.rb000066400000000000000000000236071331222022000204510ustar00rootroot00000000000000require 'json' require 'time' require 'concurrent' require 'sprockets/manifest_utils' require 'sprockets/utils/gzip' module Sprockets # 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 which 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. class Manifest include ManifestUtils attr_reader :environment # Create new Manifest associated with an `environment`. `filename` is a full # path to the manifest json file. The file may or may not already exist. The # dirname of the `filename` will be used to write compiled assets to. # Otherwise, if the path is a directory, the filename will default a random # ".sprockets-manifest-*.json" file in that directory. # # Manifest.new(environment, "./public/assets/manifest.json") # def initialize(*args) if args.first.is_a?(Base) || args.first.nil? @environment = args.shift end @directory, @filename = args[0], args[1] # Whether the manifest file is using the old manifest-*.json naming convention @legacy_manifest = false # Expand paths @directory = File.expand_path(@directory) if @directory @filename = File.expand_path(@filename) if @filename # If filename is given as the second arg if @directory && File.extname(@directory) != "" @directory, @filename = nil, @directory end # Default dir to the directory of the filename @directory ||= File.dirname(@filename) if @filename # If directory is given w/o filename, pick a random manifest location @rename_filename = nil if @directory && @filename.nil? @filename = find_directory_manifest(@directory) # If legacy manifest name autodetected, mark to rename on save if File.basename(@filename).start_with?("manifest") @rename_filename = File.join(@directory, generate_manifest_path) end end unless @directory && @filename raise ArgumentError, "manifest requires output filename" end data = {} begin if File.exist?(@filename) data = json_decode(File.read(@filename)) end rescue JSON::ParserError => e logger.error "#{@filename} is invalid: #{e.class} #{e.message}" end @data = data end # Returns String path to manifest.json file. attr_reader :filename alias_method :path, :filename attr_reader :directory alias_method :dir, :directory # 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" } # def assets @data['assets'] ||= {} end # 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" } } # def files @data['files'] ||= {} end # Public: Find all assets matching pattern set in environment. # # Returns Enumerator of Assets. def find(*args) unless environment raise Error, "manifest requires environment for compilation" end return to_enum(__method__, *args) unless block_given? paths, filters = args.flatten.partition { |arg| self.class.simple_logical_path?(arg) } filters = filters.map { |arg| self.class.compile_match_filter(arg) } environment = self.environment.cached paths.each do |path| environment.find_all_linked_assets(path) do |asset| yield asset end end if filters.any? environment.logical_paths do |logical_path, filename| if filters.any? { |f| f.call(logical_path, filename) } environment.find_all_linked_assets(filename) do |asset| yield asset end end end end nil end # Public: Find the source of assets by paths. # # Returns Enumerator of assets file content. def find_sources(*args) return to_enum(__method__, *args) unless block_given? if environment find(*args).each do |asset| yield asset.source end else args.each do |path| asset = assets[path] yield File.binread(File.join(dir, asset)) if asset end end end # 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") # def compile(*args) unless environment raise Error, "manifest requires environment for compilation" end filenames = [] concurrent_compressors = [] concurrent_writers = [] find(*args) do |asset| files[asset.digest_path] = { 'logical_path' => asset.logical_path, 'mtime' => asset.mtime.iso8601, 'size' => asset.bytesize, 'digest' => asset.hexdigest, # Deprecated: Remove beta integrity attribute in next release. # Callers should DigestUtils.hexdigest_integrity_uri to compute the # digest themselves. 'integrity' => DigestUtils.hexdigest_integrity_uri(asset.hexdigest) } assets[asset.logical_path] = asset.digest_path if alias_logical_path = self.class.compute_alias_logical_path(asset.logical_path) assets[alias_logical_path] = asset.digest_path end target = File.join(dir, asset.digest_path) if File.exist?(target) logger.debug "Skipping #{target}, already exists" else logger.info "Writing #{target}" write_file = Concurrent::Future.execute { asset.write_to target } concurrent_writers << write_file end filenames << asset.filename next if environment.skip_gzip? gzip = Utils::Gzip.new(asset) next if gzip.cannot_compress?(environment.mime_types) if File.exist?("#{target}.gz") logger.debug "Skipping #{target}.gz, already exists" else logger.info "Writing #{target}.gz" concurrent_compressors << Concurrent::Future.execute do write_file.wait! if write_file gzip.compress(target) end end end concurrent_writers.each(&:wait!) concurrent_compressors.each(&:wait!) save filenames end # Removes file from directory and from manifest. `filename` must # be the name with any directory path. # # manifest.remove("application-2e8e9a7c6b0aafa0c9bdeec90ea30213.js") # def remove(filename) path = File.join(dir, filename) gzip = "#{path}.gz" 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) FileUtils.rm(gzip) if File.exist?(gzip) save logger.info "Removed #{filename}" nil end # Cleanup old assets in the compile directory. By default it will # keep the latest version, 2 backups and any created within the past hour. # # Examples # # To force only 1 backup to be kept, set count=1 and age=0. # # To only keep files created within the last 10 minutes, set count=0 and # age=600. # def clean(count = 2, age = 3600) asset_versions = files.group_by { |_, attrs| attrs['logical_path'] } asset_versions.each do |logical_path, versions| current = assets[logical_path] versions.reject { |path, _| path == current }.sort_by { |_, attrs| # Sort by timestamp Time.parse(attrs['mtime']) }.reverse.each_with_index.drop_while { |(_, attrs), index| _age = [0, Time.now - Time.parse(attrs['mtime'])].max # Keep if under age or within the count limit _age < age || index < count }.each { |(path, _), _| # Remove old assets remove(path) } end end # Wipe directive def clobber FileUtils.rm_r(directory) if File.exist?(directory) logger.info "Removed #{directory}" nil end # Persist manfiest back to FS def save if @rename_filename logger.info "Renaming #{@filename} to #{@rename_filename}" FileUtils.mv(@filename, @rename_filename) @filename = @rename_filename @rename_filename = nil end data = json_encode(@data) FileUtils.mkdir_p File.dirname(@filename) PathUtils.atomic_write(@filename) do |f| f.write(data) end end private def json_decode(obj) JSON.parse(obj, create_additions: false) end def json_encode(obj) JSON.generate(obj) end def logger if environment environment.logger else logger = Logger.new($stderr) logger.level = Logger::FATAL logger end end end end sprockets-3.7.2/lib/sprockets/manifest_utils.rb000066400000000000000000000030211331222022000216550ustar00rootroot00000000000000require 'securerandom' module Sprockets # Public: Manifest utilities. module ManifestUtils extend self MANIFEST_RE = /^\.sprockets-manifest-[0-9a-f]{32}.json$/ LEGACY_MANIFEST_RE = /^manifest(-[0-9a-f]{32})?.json$/ # Public: Generate a new random manifest path. # # Manifests are not intended to be accessed publicly, but typically live # alongside public assets for convenience. To avoid being served, the # filename is prefixed with a "." which is usually hidden by web servers # like Apache. To help in other environments that may not control this, # a random hex string is appended to the filename to prevent people from # guessing the location. If directory indexes are enabled on the server, # all bets are off. # # Return String path. def generate_manifest_path ".sprockets-manifest-#{SecureRandom.hex(16)}.json" end # Public: Find or pick a new manifest filename for target build directory. # # dirname - String dirname # # Examples # # find_directory_manifest("/app/public/assets") # # => "/app/public/assets/.sprockets-manifest-abc123.json" # # Returns String filename. def find_directory_manifest(dirname) entries = File.directory?(dirname) ? Dir.entries(dirname) : [] entry = entries.find { |e| e =~ MANIFEST_RE } || # Deprecated: Will be removed in 4.x entries.find { |e| e =~ LEGACY_MANIFEST_RE } || generate_manifest_path File.join(dirname, entry) end end end sprockets-3.7.2/lib/sprockets/mime.rb000066400000000000000000000071641331222022000175720ustar00rootroot00000000000000require 'sprockets/encoding_utils' require 'sprockets/http_utils' require 'sprockets/utils' module Sprockets module Mime include HTTPUtils, Utils # Public: Mapping of MIME type Strings to properties Hash. # # key - MIME Type String # value - Hash # extensions - Array of extnames # charset - Default Encoding or function to detect encoding # # Returns Hash. def mime_types config[:mime_types] end # Internal: Mapping of MIME extension Strings to MIME type Strings. # # Used for internal fast lookup purposes. # # Examples: # # mime_exts['.js'] #=> 'application/javascript' # # key - MIME extension String # value - MIME Type String # # Returns Hash. def mime_exts config[:mime_exts] end # Public: Register a new mime type. # # mime_type - String MIME Type # options - Hash # extensions: Array of String extnames # charset: Proc/Method that detects the charset of a file. # See EncodingUtils. # # Returns nothing. def register_mime_type(mime_type, options = {}) # Legacy extension argument, will be removed from 4.x if options.is_a?(String) options = { extensions: [options] } end extnames = Array(options[:extensions]).map { |extname| Sprockets::Utils.normalize_extension(extname) } charset = options[:charset] charset ||= :default if mime_type.start_with?('text/') charset = EncodingUtils::CHARSET_DETECT[charset] if charset.is_a?(Symbol) self.computed_config = {} self.config = hash_reassoc(config, :mime_exts) do |mime_exts| extnames.each do |extname| mime_exts[extname] = mime_type end mime_exts end self.config = hash_reassoc(config, :mime_types) do |mime_types| type = { extensions: extnames } type[:charset] = charset if charset mime_types.merge(mime_type => type) end end # Internal: Get detecter function for MIME type. # # mime_type - String MIME type # # Returns Proc detector or nil if none is available. def mime_type_charset_detecter(mime_type) if type = config[:mime_types][mime_type] if detect = type[:charset] return detect end end end # Public: Read file on disk with MIME type specific encoding. # # filename - String path # content_type - String MIME type # # Returns String file contents transcoded to UTF-8 or in its external # encoding. def read_file(filename, content_type = nil) data = File.binread(filename) if detect = mime_type_charset_detecter(content_type) detect.call(data).encode(Encoding::UTF_8, :universal_newline => true) else data end end private def extname_map self.computed_config[:_extnames] ||= compute_extname_map end def compute_extname_map graph = {} ([nil] + pipelines.keys.map(&:to_s)).each do |pipeline| pipeline_extname = ".#{pipeline}" if pipeline ([[nil, nil]] + config[:mime_exts].to_a).each do |format_extname, format_type| 4.times do |n| config[:engines].keys.permutation(n).each do |engine_extnames| key = "#{pipeline_extname}#{format_extname}#{engine_extnames.join}" type = format_type || config[:engine_mime_types][engine_extnames.first] graph[key] = {type: type, engines: engine_extnames, pipeline: pipeline} end end end end graph end end end sprockets-3.7.2/lib/sprockets/path_dependency_utils.rb000066400000000000000000000053431331222022000232120ustar00rootroot00000000000000require 'set' require 'sprockets/path_utils' require 'sprockets/uri_utils' module Sprockets # Internal: Related PathUtils helpers that also track all the file system # calls they make for caching purposes. All functions return a standard # return value and a Set of cache dependency URIs that can be used in the # future to see if the returned value should be invalidated from cache. # # entries_with_dependencies("app/assets/javascripts") # # => [ # # ["application.js", "projects.js", "users.js", ...] # # # # # ] # # The returned dependency set can be passed to resolve_dependencies(deps) # to check if the returned result is still fresh. In this case, entry always # returns a single path, but multiple calls should accumulate dependencies # into a single set thats saved off and checked later. # # resolve_dependencies(deps) # # => "\x01\x02\x03" # # Later, resolving the same set again will produce a different hash if # something on the file system has changed. # # resolve_dependencies(deps) # # => "\x03\x04\x05" # module PathDependencyUtils include PathUtils include URIUtils # Internal: List directory entries and return a set of dependencies that # would invalid the cached return result. # # See PathUtils#entries # # path - String directory path # # Returns an Array of entry names and a Set of dependency URIs. def entries_with_dependencies(path) return entries(path), file_digest_dependency_set(path) end # Internal: List directory filenames and associated Stats under a # directory. # # See PathUtils#stat_directory # # dir - A String directory # # Returns an Array of filenames and a Set of dependency URIs. def stat_directory_with_dependencies(dir) return stat_directory(dir).to_a, file_digest_dependency_set(dir) end # Internal: Returns a set of dependencies for a particular path. # # path - String directory path # # Returns a Set of dependency URIs. def file_digest_dependency_set(path) Set.new([build_file_digest_uri(path)]) end # Internal: List directory filenames and associated Stats under an entire # directory tree. # # See PathUtils#stat_sorted_tree # # dir - A String directory # # Returns an Array of filenames and a Set of dependency URIs. def stat_sorted_tree_with_dependencies(dir) deps = Set.new([build_file_digest_uri(dir)]) results = stat_sorted_tree(dir).map do |path, stat| deps << build_file_digest_uri(path) if stat.directory? [path, stat] end return results, deps end end end sprockets-3.7.2/lib/sprockets/path_digest_utils.rb000066400000000000000000000023541331222022000223520ustar00rootroot00000000000000require 'sprockets/digest_utils' require 'sprockets/path_utils' module Sprockets # Internal: Crossover of path and digest utilities functions. module PathDigestUtils include DigestUtils, PathUtils # Internal: Compute digest for file stat. # # path - String filename # stat - File::Stat # # Returns String digest bytes. def stat_digest(path, stat) if stat.directory? # If its a directive, digest the list of filenames digest_class.digest(self.entries(path).join(',')) elsif stat.file? # If its a file, digest the contents digest_class.file(path.to_s).digest else raise TypeError, "stat was not a directory or file: #{stat.ftype}" end end # Internal: Compute digest for path. # # path - String filename or directory path. # # Returns String digest bytes or nil. def file_digest(path) if stat = self.stat(path) self.stat_digest(path, stat) end end # Internal: Compute digest for a set of paths. # # paths - Array of filename or directory paths. # # Returns String digest bytes. def files_digest(paths) self.digest(paths.map { |path| self.file_digest(path) }) end end end sprockets-3.7.2/lib/sprockets/path_utils.rb000066400000000000000000000162371331222022000210200ustar00rootroot00000000000000module Sprockets # Internal: File and path related utilities. Mixed into Environment. # # Probably would be called FileUtils, but that causes namespace annoyances # when code actually wants to reference ::FileUtils. module PathUtils extend self # Public: Like `File.stat`. # # path - String file or directory path # # Returns nil if the file does not exist. def stat(path) if File.exist?(path) File.stat(path.to_s) else nil end end # Public: Like `File.file?`. # # path - String file path. # # Returns true path exists and is a file. def file?(path) if stat = self.stat(path) stat.file? else false end end # Public: Like `File.directory?`. # # path - String file path. # # Returns true path exists and is a directory. def directory?(path) if stat = self.stat(path) stat.directory? else false end end # Public: A version of `Dir.entries` that filters out `.` files and `~` # swap files. # # path - String directory path # # Returns an empty `Array` if the directory does not exist. def entries(path) if File.directory?(path) entries = Dir.entries(path, :encoding => Encoding.default_internal) entries.reject! { |entry| entry.start_with?(".".freeze) || (entry.start_with?("#".freeze) && entry.end_with?("#".freeze)) || entry.end_with?("~".freeze) } entries.sort! else [] end end # Public: Check if path is absolute or relative. # # path - String path. # # Returns true if path is absolute, otherwise false. if File::ALT_SEPARATOR require 'pathname' # On Windows, ALT_SEPARATOR is \ # Delegate to Pathname since the logic gets complex. def absolute_path?(path) Pathname.new(path).absolute? end else def absolute_path?(path) path[0] == File::SEPARATOR end end if File::ALT_SEPARATOR SEPARATOR_PATTERN = "#{Regexp.quote(File::SEPARATOR)}|#{Regexp.quote(File::ALT_SEPARATOR)}" else SEPARATOR_PATTERN = "#{Regexp.quote(File::SEPARATOR)}" end # Public: Check if path is explicitly relative. # Starts with "./" or "../". # # path - String path. # # Returns true if path is relative, otherwise false. def relative_path?(path) path =~ /^\.\.?($|#{SEPARATOR_PATTERN})/ ? true : false end # Internal: Get relative path for root path and subpath. # # path - String path # subpath - String subpath of path # # Returns relative String path if subpath is a subpath of path, or nil if # subpath is outside of path. def split_subpath(path, subpath) return "" if path == subpath path = File.join(path, '') if subpath.start_with?(path) subpath[path.length..-1] else nil end end # Internal: Detect root path and base for file in a set of paths. # # paths - Array of String paths # filename - String path of file expected to be in one of the paths. # # Returns [String root, String path] def paths_split(paths, filename) paths.each do |path| if subpath = split_subpath(path, filename) return path, subpath end end nil end # Internal: Get path's extensions. # # path - String # # Returns an Array of String extnames. def path_extnames(path) File.basename(path).scan(/\.[^.]+/) end # Internal: Match path extnames against available extensions. # # path - String # extensions - Hash of String extnames to values # # Returns [String extname, Object value] or nil nothing matched. def match_path_extname(path, extensions) basename = File.basename(path) i = basename.index('.'.freeze) while i && i < basename.length - 1 extname = basename[i..-1] if value = extensions[extname] return extname, value end i = basename.index('.'.freeze, i+1) end nil end # Internal: Returns all parents for path # # path - String absolute filename or directory # root - String path to stop at (default: system root) # # Returns an Array of String paths. def path_parents(path, root = nil) root = "#{root}#{File::SEPARATOR}" if root parents = [] loop do parent = File.dirname(path) break if parent == path break if root && !path.start_with?(root) parents << path = parent end parents end # Internal: Find target basename checking upwards from path. # # basename - String filename: ".sprocketsrc" # path - String path to start search: "app/assets/javascripts/app.js" # root - String path to stop at (default: system root) # # Returns String filename or nil. def find_upwards(basename, path, root = nil) path_parents(path, root).each do |dir| filename = File.join(dir, basename) return filename if file?(filename) end nil end # Public: Stat all the files under a directory. # # dir - A String directory # # Returns an Enumerator of [path, stat]. def stat_directory(dir) return to_enum(__method__, dir) unless block_given? self.entries(dir).each do |entry| path = File.join(dir, entry) if stat = self.stat(path) yield path, stat end end nil end # Public: Recursive stat all the files under a directory. # # dir - A String directory # # Returns an Enumerator of [path, stat]. def stat_tree(dir, &block) return to_enum(__method__, dir) unless block_given? self.stat_directory(dir) do |path, stat| yield path, stat if stat.directory? stat_tree(path, &block) end end nil end # Public: Recursive stat all the files under a directory in alphabetical # order. # # dir - A String directory # # Returns an Enumerator of [path, stat]. def stat_sorted_tree(dir, &block) return to_enum(__method__, dir) unless block_given? self.stat_directory(dir).sort_by { |path, stat| stat.directory? ? "#{path}/" : path }.each do |path, stat| yield path, stat if stat.directory? stat_sorted_tree(path, &block) end end nil end # Public: Write to a file atomically. Useful for situations where you # don't want other processes or threads to see half-written files. # # Utils.atomic_write('important.file') do |file| # file.write('hello') # end # # Returns nothing. def atomic_write(filename) dirname, basename = File.split(filename) basename = [ basename, Thread.current.object_id, Process.pid, rand(1000000) ].join('.') tmpname = File.join(dirname, basename) File.open(tmpname, 'wb+') do |f| yield f end File.rename(tmpname, filename) ensure File.delete(tmpname) if File.exist?(tmpname) end end end sprockets-3.7.2/lib/sprockets/paths.rb000066400000000000000000000037721331222022000177630ustar00rootroot00000000000000require 'sprockets/path_utils' require 'sprockets/utils' module Sprockets module Paths include PathUtils, Utils # Returns `Environment` root. # # All relative paths are expanded with root as its base. To be # useful set this to your applications root directory. (`Rails.root`) def root config[:root] end # Internal: Change Environment root. # # Only the initializer should change the root. def root=(path) self.config = hash_reassoc(config, :root) do File.expand_path(path) end end private :root= # Returns an `Array` of path `String`s. # # These paths will be used for asset logical path lookups. def paths config[:paths] end # Prepend a `path` to the `paths` list. # # Paths at the end of the `Array` have the least priority. def prepend_path(path) self.config = hash_reassoc(config, :paths) do |paths| path = File.expand_path(path, config[:root]).freeze paths.unshift(path) end end # Append a `path` to the `paths` list. # # Paths at the beginning of the `Array` have a higher priority. def append_path(path) self.config = hash_reassoc(config, :paths) do |paths| path = File.expand_path(path, config[:root]).freeze paths.push(path) end end # Clear all paths and start fresh. # # There is no mechanism for reordering paths, so its best to # completely wipe the paths list and reappend them in the order # you want. def clear_paths self.config = hash_reassoc(config, :paths) do |paths| paths.clear end end # Public: Iterate over every file under all load paths. # # Returns Enumerator if no block is given. def each_file return to_enum(__method__) unless block_given? paths.each do |root| stat_tree(root).each do |filename, stat| if stat.file? yield filename end end end nil end end end sprockets-3.7.2/lib/sprockets/processing.rb000066400000000000000000000201031331222022000210030ustar00rootroot00000000000000require 'sprockets/engines' require 'sprockets/file_reader' require 'sprockets/legacy_proc_processor' require 'sprockets/legacy_tilt_processor' require 'sprockets/mime' require 'sprockets/processor_utils' require 'sprockets/uri_utils' require 'sprockets/utils' module Sprockets # `Processing` is an internal mixin whose public methods are exposed on # the `Environment` and `CachedEnvironment` classes. module Processing include ProcessorUtils, URIUtils, Utils def pipelines config[:pipelines] end def register_pipeline(name, proc = nil, &block) proc ||= block self.config = hash_reassoc(config, :pipelines) do |pipelines| pipelines.merge(name.to_sym => proc) end end # Preprocessors are ran before Postprocessors and Engine # processors. def preprocessors config[:preprocessors] end alias_method :processors, :preprocessors # Postprocessors are ran after Preprocessors and Engine processors. def postprocessors config[:postprocessors] end # Registers a new Preprocessor `klass` for `mime_type`. # # register_preprocessor 'text/css', Sprockets::DirectiveProcessor # # A block can be passed for to create a shorthand processor. # # register_preprocessor 'text/css', :my_processor do |context, data| # data.gsub(...) # end # def register_preprocessor(*args, &block) register_config_processor(:preprocessors, *args, &block) end alias_method :register_processor, :register_preprocessor # Registers a new Postprocessor `klass` for `mime_type`. # # register_postprocessor 'application/javascript', Sprockets::DirectiveProcessor # # A block can be passed for to create a shorthand processor. # # register_postprocessor 'application/javascript', :my_processor do |context, data| # data.gsub(...) # end # def register_postprocessor(*args, &block) register_config_processor(:postprocessors, *args, &block) end # Remove Preprocessor `klass` for `mime_type`. # # unregister_preprocessor 'text/css', Sprockets::DirectiveProcessor # def unregister_preprocessor(*args) unregister_config_processor(:preprocessors, *args) end alias_method :unregister_processor, :unregister_preprocessor # Remove Postprocessor `klass` for `mime_type`. # # unregister_postprocessor 'text/css', Sprockets::DirectiveProcessor # def unregister_postprocessor(*args) unregister_config_processor(:postprocessors, *args) end # Bundle Processors are ran on concatenated assets rather than # individual files. def bundle_processors config[:bundle_processors] end # Registers a new Bundle Processor `klass` for `mime_type`. # # register_bundle_processor 'application/javascript', Sprockets::DirectiveProcessor # # A block can be passed for to create a shorthand processor. # # register_bundle_processor 'application/javascript', :my_processor do |context, data| # data.gsub(...) # end # def register_bundle_processor(*args, &block) register_config_processor(:bundle_processors, *args, &block) end # Remove Bundle Processor `klass` for `mime_type`. # # unregister_bundle_processor 'application/javascript', Sprockets::DirectiveProcessor # def unregister_bundle_processor(*args) unregister_config_processor(:bundle_processors, *args) end # Public: Register bundle metadata reducer function. # # Examples # # Sprockets.register_bundle_metadata_reducer 'application/javascript', :jshint_errors, [], :+ # # Sprockets.register_bundle_metadata_reducer 'text/css', :selector_count, 0 { |total, count| # total + count # } # # mime_type - String MIME Type. Use '*/*' applies to all types. # key - Symbol metadata key # initial - Initial memo to pass to the reduce funciton (default: nil) # block - Proc accepting the memo accumulator and current value # # Returns nothing. def register_bundle_metadata_reducer(mime_type, key, *args, &block) case args.size when 0 reducer = block when 1 if block_given? initial = args[0] reducer = block else initial = nil reducer = args[0].to_proc end when 2 initial = args[0] reducer = args[1].to_proc else raise ArgumentError, "wrong number of arguments (#{args.size} for 0..2)" end self.config = hash_reassoc(config, :bundle_reducers, mime_type) do |reducers| reducers.merge(key => [initial, reducer]) end end protected def resolve_processors_cache_key_uri(uri) params = parse_uri_query_params(uri[11..-1]) params[:engine_extnames] = params[:engines] ? params[:engines].split(',') : [] processors = processors_for(params[:type], params[:file_type], params[:engine_extnames], params[:pipeline]) processors_cache_keys(processors) end def build_processors_uri(type, file_type, engine_extnames, pipeline) engines = engine_extnames.join(',') if engine_extnames.any? query = encode_uri_query_params( type: type, file_type: file_type, engines: engines, pipeline: pipeline ) "processors:#{query}" end def processors_for(type, file_type, engine_extnames, pipeline) pipeline ||= :default config[:pipelines][pipeline.to_sym].call(self, type, file_type, engine_extnames) end def default_processors_for(type, file_type, engine_extnames) bundled_processors = config[:bundle_processors][type] if bundled_processors.any? bundled_processors else self_processors_for(type, file_type, engine_extnames) end end def self_processors_for(type, file_type, engine_extnames) processors = [] processors.concat config[:postprocessors][type] if type != file_type && processor = config[:transformers][file_type][type] processors << processor end processors.concat engine_extnames.map { |ext| engines[ext] } processors.concat config[:preprocessors][file_type] if processors.any? || mime_type_charset_detecter(type) processors << FileReader end processors end private def register_config_processor(type, mime_type, klass, proc = nil, &block) proc ||= block processor = wrap_processor(klass, proc) self.config = hash_reassoc(config, type, mime_type) do |processors| processors.unshift(processor) processors end compute_transformers! end def unregister_config_processor(type, mime_type, klass) if klass.is_a?(String) || klass.is_a?(Symbol) klass = config[type][mime_type].detect do |cls| cls.respond_to?(:name) && cls.name == "Sprockets::LegacyProcProcessor (#{klass})" end end self.config = hash_reassoc(config, type, mime_type) do |processors| processors.delete(klass) processors end compute_transformers! end def deprecate_legacy_processor_interface(interface) msg = "You are using a deprecated processor interface #{ interface.inspect }.\n" + "Please update your processor interface:\n" + "https://github.com/rails/sprockets/blob/master/guides/extending_sprockets.md#supporting-all-versions-of-sprockets-in-processors\n" Deprecation.new([caller[3]]).warn msg end def wrap_processor(klass, proc) if !proc if klass.respond_to?(:call) klass else deprecate_legacy_processor_interface(klass) LegacyTiltProcessor.new(klass) end elsif proc.respond_to?(:arity) && proc.arity == 2 deprecate_legacy_processor_interface(proc) LegacyProcProcessor.new(klass.to_s, proc) else proc end end end end sprockets-3.7.2/lib/sprockets/processor_utils.rb000066400000000000000000000133101331222022000220700ustar00rootroot00000000000000require 'set' module Sprockets # Functional utilities for dealing with Processor functions. # # A Processor is a general function that my modify or transform an asset as # part of the pipeline. CoffeeScript to JavaScript conversion, Minification # or Concatenation are all implemented as seperate Processor steps. # # Processors maybe any object that responds to call. So procs or a class that # defines a self.call method. # # For ergonomics, processors may return a number of shorthand values. # Unfortunately, this means that processors can not compose via ordinary # function composition. The composition helpers here can help. module ProcessorUtils extend self # Public: Compose processors in right to left order. # # processors - Array of processors callables # # Returns a composed Proc. def compose_processors(*processors) context = self if processors.length == 1 obj = method(:call_processor).to_proc.curry[processors.first] else obj = method(:call_processors).to_proc.curry[processors] end metaclass = (class << obj; self; end) metaclass.send(:define_method, :cache_key) do context.processors_cache_keys(processors) end obj end # Public: Invoke list of processors in right to left order. # # The right to left order processing mirrors standard function composition. # Think about: # # bundle.call(uglify.call(coffee.call(input))) # # processors - Array of processor callables # input - Hash of input data to pass to each processor # # Returns a Hash with :data and other processor metadata key/values. def call_processors(processors, input) data = input[:data] || "" metadata = (input[:metadata] || {}).dup processors.reverse_each do |processor| result = call_processor(processor, input.merge(data: data, metadata: metadata)) data = result.delete(:data) metadata.merge!(result) end metadata.merge(data: data) end # Public: Invoke processor. # # processor - Processor callables # input - Hash of input data to pass to processor # # Returns a Hash with :data and other processor metadata key/values. def call_processor(processor, input) metadata = (input[:metadata] || {}).dup metadata[:data] = input[:data] case result = processor.call({data: "", metadata: {}}.merge(input)) when NilClass metadata when Hash metadata.merge(result) when String metadata.merge(data: result) else raise TypeError, "invalid processor return type: #{result.class}" end end # Internal: Get processor defined cached key. # # processor - Processor function # # Returns JSON serializable key or nil. def processor_cache_key(processor) processor.cache_key if processor.respond_to?(:cache_key) end # Internal: Get combined cache keys for set of processors. # # processors - Array of processor functions # # Returns Array of JSON serializable keys. def processors_cache_keys(processors) processors.map { |processor| processor_cache_key(processor) } end # Internal: Set of all "simple" value types allowed to be returned in # processor metadata. VALID_METADATA_VALUE_TYPES = Set.new([ String, Symbol, TrueClass, FalseClass, NilClass ] + (0.class == Integer ? [Integer] : [Bignum, Fixnum])).freeze # Internal: Set of all nested compound metadata types that can nest values. VALID_METADATA_COMPOUND_TYPES = Set.new([ Array, Hash, Set ]).freeze # Internal: Hash of all "simple" value types allowed to be returned in # processor metadata. VALID_METADATA_VALUE_TYPES_HASH = VALID_METADATA_VALUE_TYPES.each_with_object({}) do |type, hash| hash[type] = true end.freeze # Internal: Hash of all nested compound metadata types that can nest values. VALID_METADATA_COMPOUND_TYPES_HASH = VALID_METADATA_COMPOUND_TYPES.each_with_object({}) do |type, hash| hash[type] = true end.freeze # Internal: Set of all allowed metadata types. VALID_METADATA_TYPES = (VALID_METADATA_VALUE_TYPES + VALID_METADATA_COMPOUND_TYPES).freeze # Internal: Validate returned result of calling a processor pipeline and # raise a friendly user error message. # # result - Metadata Hash returned from call_processors # # Returns result or raises a TypeError. def validate_processor_result!(result) if !result.instance_of?(Hash) raise TypeError, "processor metadata result was expected to be a Hash, but was #{result.class}" end if !result[:data].instance_of?(String) raise TypeError, "processor :data was expected to be a String, but as #{result[:data].class}" end result.each do |key, value| if !key.instance_of?(Symbol) raise TypeError, "processor metadata[#{key.inspect}] expected to be a Symbol" end if !valid_processor_metadata_value?(value) raise TypeError, "processor metadata[:#{key}] returned a complex type: #{value.inspect}\n" + "Only #{VALID_METADATA_TYPES.to_a.join(", ")} maybe used." end end result end # Internal: Validate object is in validate metadata whitelist. # # value - Any Object # # Returns true if class is in whitelist otherwise false. def valid_processor_metadata_value?(value) if VALID_METADATA_VALUE_TYPES_HASH[value.class] true elsif VALID_METADATA_COMPOUND_TYPES_HASH[value.class] value.all? { |v| valid_processor_metadata_value?(v) } else false end end end end sprockets-3.7.2/lib/sprockets/resolve.rb000066400000000000000000000154341331222022000203210ustar00rootroot00000000000000require 'set' require 'sprockets/http_utils' require 'sprockets/path_dependency_utils' require 'sprockets/uri_utils' module Sprockets module Resolve include HTTPUtils, PathDependencyUtils, URIUtils # Public: Find Asset URI for given a logical path by searching the # environment's load paths. # # resolve("application.js") # # => "file:///path/to/app/javascripts/application.js?type=application/javascript" # # An accept content type can be given if the logical path doesn't have a # format extension. # # resolve("application", accept: "application/javascript") # # => "file:///path/to/app/javascripts/application.coffee?type=application/javascript" # # The String Asset URI is returned or nil if no results are found. def resolve(path, options = {}) path = path.to_s paths = options[:load_paths] || config[:paths] accept = options[:accept] if valid_asset_uri?(path) uri, deps = resolve_asset_uri(path) elsif absolute_path?(path) filename, type, deps = resolve_absolute_path(paths, path, accept) elsif relative_path?(path) filename, type, pipeline, deps = resolve_relative_path(paths, path, options[:base_path], accept) else filename, type, pipeline, deps = resolve_logical_path(paths, path, accept) end if filename params = {} params[:type] = type if type params[:pipeline] = pipeline if pipeline params[:pipeline] = options[:pipeline] if options[:pipeline] uri = build_asset_uri(filename, params) end return uri, deps end # Public: Same as resolve() but raises a FileNotFound exception instead of # nil if no assets are found. def resolve!(path, options = {}) uri, deps = resolve(path, options.merge(compat: false)) unless uri message = "couldn't find file '#{path}'" if relative_path?(path) && options[:base_path] load_path, _ = paths_split(config[:paths], options[:base_path]) message << " under '#{load_path}'" end message << " with type '#{options[:accept]}'" if options[:accept] message << "\nChecked in these paths: \n #{ config[:paths].join("\n ") }" raise FileNotFound, message end return uri, deps end protected def resolve_asset_uri(uri) filename, _ = parse_asset_uri(uri) return uri, Set.new([build_file_digest_uri(filename)]) end def resolve_absolute_path(paths, filename, accept) deps = Set.new filename = File.expand_path(filename) # Ensure path is under load paths return nil, nil, deps unless paths_split(paths, filename) _, mime_type, _, _ = parse_path_extnames(filename) type = resolve_transform_type(mime_type, accept) return nil, nil, deps if accept && !type return nil, nil, deps unless file?(filename) deps << build_file_digest_uri(filename) return filename, type, deps end def resolve_relative_path(paths, path, dirname, accept) filename = File.expand_path(path, dirname) load_path, _ = paths_split(paths, dirname) if load_path && logical_path = split_subpath(load_path, filename) resolve_logical_path([load_path], logical_path, accept) else return nil, nil, Set.new end end def resolve_logical_path(paths, logical_path, accept) logical_name, mime_type, _, pipeline = parse_path_extnames(logical_path) parsed_accept = parse_accept_options(mime_type, accept) transformed_accepts = expand_transform_accepts(parsed_accept) filename, mime_type, deps = resolve_under_paths(paths, logical_name, transformed_accepts) if filename deps << build_file_digest_uri(filename) type = resolve_transform_type(mime_type, parsed_accept) return filename, type, pipeline, deps else return nil, nil, nil, deps end end def resolve_under_paths(paths, logical_name, accepts) all_deps = Set.new return nil, nil, all_deps if accepts.empty? logical_basename = File.basename(logical_name) paths.each do |load_path| candidates, deps = path_matches(load_path, logical_name, logical_basename) all_deps.merge(deps) candidate = find_best_q_match(accepts, candidates) do |c, matcher| match_mime_type?(c[1] || "application/octet-stream", matcher) end return candidate + [all_deps] if candidate end return nil, nil, all_deps end def parse_accept_options(mime_type, types) accepts = [] accepts += parse_q_values(types) if types if mime_type if accepts.empty? || accepts.any? { |accept, _| match_mime_type?(mime_type, accept) } accepts = [[mime_type, 1.0]] else return [] end end if accepts.empty? accepts << ['*/*', 1.0] end accepts end def path_matches(load_path, logical_name, logical_basename) dirname = File.dirname(File.join(load_path, logical_name)) candidates = dirname_matches(dirname, logical_basename) deps = file_digest_dependency_set(dirname) result = resolve_alternates(load_path, logical_name) result[0].each do |fn| candidates << [fn, parse_path_extnames(fn)[1]] end deps.merge(result[1]) dirname = File.join(load_path, logical_name) if directory? dirname result = dirname_matches(dirname, "index") candidates.concat(result) end deps.merge(file_digest_dependency_set(dirname)) return candidates.select { |fn, _| file?(fn) }, deps end def dirname_matches(dirname, basename) candidates = [] entries = self.entries(dirname) entries.each do |entry| next unless File.basename(entry).start_with?(basename) name, type, _, _ = parse_path_extnames(entry) if basename == name candidates << [File.join(dirname, entry), type] end end candidates end def resolve_alternates(load_path, logical_name) return [], Set.new end # Internal: Returns the name, mime type and `Array` of engine extensions. # # "foo.js.coffee.erb" # # => ["foo", "application/javascript", [".coffee", ".erb"]] # def parse_path_extnames(path) engines = [] extname, value = match_path_extname(path, extname_map) if extname path = path.chomp(extname) type, engines, pipeline = value.values_at(:type, :engines, :pipeline) end return path, type, engines, pipeline end end end sprockets-3.7.2/lib/sprockets/sass_cache_store.rb000066400000000000000000000015511331222022000221450ustar00rootroot00000000000000require 'sass' module Sprockets class SassProcessor # Internal: Cache wrapper for Sprockets cache adapter. class CacheStore < ::Sass::CacheStores::Base VERSION = '1' def initialize(cache, version) @cache, @version = cache, "#{VERSION}/#{version}" end def _store(key, version, sha, contents) @cache.set("#{@version}/#{version}/#{key}/#{sha}", contents, true) end def _retrieve(key, version, sha) @cache.get("#{@version}/#{version}/#{key}/#{sha}", true) end def path_to(key) key end end end # Deprecated: Use Sprockets::SassProcessor::CacheStore instead. class SassCacheStore < SassProcessor::CacheStore def initialize(*args) Deprecation.new.warn "SassCacheStore is deprecated please use SassProcessor::CacheStore instead" super end end end sprockets-3.7.2/lib/sprockets/sass_compressor.rb000066400000000000000000000022241331222022000220600ustar00rootroot00000000000000require 'sprockets/autoload' require 'sprockets/digest_utils' module Sprockets # Public: Sass CSS minifier. # # To accept the default options # # environment.register_bundle_processor 'text/css', # Sprockets::SassCompressor # # Or to pass options to the Sass::Engine class. # # environment.register_bundle_processor 'text/css', # Sprockets::SassCompressor.new({ ... }) # class SassCompressor VERSION = '1' # Public: Return singleton instance with default options. # # Returns SassCompressor object. def self.instance @instance ||= new end def self.call(input) instance.call(input) end def self.cache_key instance.cache_key end attr_reader :cache_key def initialize(options = {}) @options = { syntax: :scss, cache: false, read_cache: false, style: :compressed }.merge(options).freeze @cache_key = "#{self.class.name}:#{Autoload::Sass::VERSION}:#{VERSION}:#{DigestUtils.digest(options)}".freeze end def call(input) Autoload::Sass::Engine.new(input[:data], @options).render end end end sprockets-3.7.2/lib/sprockets/sass_functions.rb000066400000000000000000000001321331222022000216700ustar00rootroot00000000000000# Deprecated: Require sprockets/sass_processor instead require 'sprockets/sass_processor' sprockets-3.7.2/lib/sprockets/sass_importer.rb000066400000000000000000000001321331222022000215210ustar00rootroot00000000000000# Deprecated: Require sprockets/sass_processor instead require 'sprockets/sass_processor' sprockets-3.7.2/lib/sprockets/sass_processor.rb000066400000000000000000000176241331222022000217150ustar00rootroot00000000000000require 'rack/utils' require 'sprockets/autoload' require 'uri' module Sprockets # Processor engine class for the SASS/SCSS compiler. Depends on the `sass` gem. # # For more infomation see: # # https://github.com/sass/sass # https://github.com/rails/sass-rails # class SassProcessor autoload :CacheStore, 'sprockets/sass_cache_store' # Internal: Defines default sass syntax to use. Exposed so the ScssProcessor # may override it. def self.syntax :sass end # Public: Return singleton instance with default options. # # Returns SassProcessor object. def self.instance @instance ||= new end def self.call(input) instance.call(input) end def self.cache_key instance.cache_key end attr_reader :cache_key # Public: Initialize template with custom options. # # options - Hash # cache_version - String custom cache version. Used to force a cache # change after code changes are made to Sass Functions. # def initialize(options = {}, &block) @cache_version = options[:cache_version] @cache_key = "#{self.class.name}:#{VERSION}:#{Autoload::Sass::VERSION}:#{@cache_version}".freeze @functions = Module.new do include Functions include options[:functions] if options[:functions] class_eval(&block) if block_given? end end def call(input) context = input[:environment].context_class.new(input) options = { filename: input[:filename], syntax: self.class.syntax, cache_store: build_cache_store(input, @cache_version), load_paths: input[:environment].paths, sprockets: { context: context, environment: input[:environment], dependencies: context.metadata[:dependencies] } } engine = Autoload::Sass::Engine.new(input[:data], options) css = Utils.module_include(Autoload::Sass::Script::Functions, @functions) do engine.render end # Track all imported files sass_dependencies = Set.new([input[:filename]]) engine.dependencies.map do |dependency| sass_dependencies << dependency.options[:filename] context.metadata[:dependencies] << URIUtils.build_file_digest_uri(dependency.options[:filename]) end context.metadata.merge(data: css, sass_dependencies: sass_dependencies) end # Public: Build the cache store to be used by the Sass engine. # # input - the input hash. # version - the cache version. # # Override this method if you need to use a different cache than the # Sprockets cache. def build_cache_store(input, version) CacheStore.new(input[:cache], version) end private :build_cache_store # Public: Functions injected into Sass context during Sprockets evaluation. # # This module may be extended to add global functionality to all Sprockets # Sass environments. Though, scoping your functions to just your environment # is preferred. # # module Sprockets::SassProcessor::Functions # def asset_path(path, options = {}) # end # end # module Functions # Public: Generate a url for asset path. # # Default implementation is deprecated. Currently defaults to # Context#asset_path. # # Will raise NotImplementedError in the future. Users should provide their # own base implementation. # # Returns a Sass::Script::String. def asset_path(path, options = {}) path = path.value path, _, query, fragment = URI.split(path)[5..8] path = sprockets_context.asset_path(path, options) query = "?#{query}" if query fragment = "##{fragment}" if fragment Autoload::Sass::Script::String.new("#{path}#{query}#{fragment}", :string) end # Public: Generate a asset url() link. # # path - Sass::Script::String URL path # # Returns a Sass::Script::String. def asset_url(path, options = {}) Autoload::Sass::Script::String.new("url(#{asset_path(path, options).value})") end # Public: Generate url for image path. # # path - Sass::Script::String URL path # # Returns a Sass::Script::String. def image_path(path) asset_path(path, type: :image) end # Public: Generate a image url() link. # # path - Sass::Script::String URL path # # Returns a Sass::Script::String. def image_url(path) asset_url(path, type: :image) end # Public: Generate url for video path. # # path - Sass::Script::String URL path # # Returns a Sass::Script::String. def video_path(path) asset_path(path, type: :video) end # Public: Generate a video url() link. # # path - Sass::Script::String URL path # # Returns a Sass::Script::String. def video_url(path) asset_url(path, type: :video) end # Public: Generate url for audio path. # # path - Sass::Script::String URL path # # Returns a Sass::Script::String. def audio_path(path) asset_path(path, type: :audio) end # Public: Generate a audio url() link. # # path - Sass::Script::String URL path # # Returns a Sass::Script::String. def audio_url(path) asset_url(path, type: :audio) end # Public: Generate url for font path. # # path - Sass::Script::String URL path # # Returns a Sass::Script::String. def font_path(path) asset_path(path, type: :font) end # Public: Generate a font url() link. # # path - Sass::Script::String URL path # # Returns a Sass::Script::String. def font_url(path) asset_url(path, type: :font) end # Public: Generate url for javascript path. # # path - Sass::Script::String URL path # # Returns a Sass::Script::String. def javascript_path(path) asset_path(path, type: :javascript) end # Public: Generate a javascript url() link. # # path - Sass::Script::String URL path # # Returns a Sass::Script::String. def javascript_url(path) asset_url(path, type: :javascript) end # Public: Generate url for stylesheet path. # # path - Sass::Script::String URL path # # Returns a Sass::Script::String. def stylesheet_path(path) asset_path(path, type: :stylesheet) end # Public: Generate a stylesheet url() link. # # path - Sass::Script::String URL path # # Returns a Sass::Script::String. def stylesheet_url(path) asset_url(path, type: :stylesheet) end # Public: Generate a data URI for asset path. # # path - Sass::Script::String logical asset path # # Returns a Sass::Script::String. def asset_data_url(path) url = sprockets_context.asset_data_uri(path.value) Autoload::Sass::Script::String.new("url(" + url + ")") end protected # Public: The Environment. # # Returns Sprockets::Environment. def sprockets_environment options[:sprockets][:environment] end # Public: Mutatable set of dependencies. # # Returns a Set. def sprockets_dependencies options[:sprockets][:dependencies] end # Deprecated: Get the Context instance. Use APIs on # sprockets_environment or sprockets_dependencies directly. # # Returns a Context instance. def sprockets_context options[:sprockets][:context] end end end class ScssProcessor < SassProcessor def self.syntax :scss end end # Deprecated: Use Sprockets::SassProcessor::Functions instead. SassFunctions = SassProcessor::Functions end sprockets-3.7.2/lib/sprockets/sass_template.rb000066400000000000000000000006721331222022000215040ustar00rootroot00000000000000require 'sprockets/sass_processor' module Sprockets # Deprecated class SassTemplate < SassProcessor def self.call(*args) Deprecation.new.warn "SassTemplate is deprecated please use SassProcessor instead" super end end # Deprecated class ScssTemplate < ScssProcessor def self.call(*args) Deprecation.new.warn "ScssTemplate is deprecated please use ScssProcessor instead" super end end end sprockets-3.7.2/lib/sprockets/server.rb000066400000000000000000000215201331222022000201410ustar00rootroot00000000000000require 'time' require 'rack/utils' module Sprockets # `Server` is a concern mixed into `Environment` and # `CachedEnvironment` that provides a Rack compatible `call` # interface and url generation helpers. module Server # `call` implements the Rack 1.x specification which accepts an # `env` Hash and returns a three item tuple with the status code, # headers, and body. # # Mapping your environment at a url prefix will serve all assets # in the path. # # map "/assets" do # run Sprockets::Environment.new # end # # A request for `"/assets/foo/bar.js"` will search your # environment for `"foo/bar.js"`. def call(env) start_time = Time.now.to_f time_elapsed = lambda { ((Time.now.to_f - start_time) * 1000).to_i } if !['GET', 'HEAD'].include?(env['REQUEST_METHOD']) return method_not_allowed_response end msg = "Served asset #{env['PATH_INFO']} -" # Extract the path from everything after the leading slash path = Rack::Utils.unescape(env['PATH_INFO'].to_s.sub(/^\//, '')) # Strip fingerprint if fingerprint = path_fingerprint(path) path = path.sub("-#{fingerprint}", '') end # URLs containing a `".."` are rejected for security reasons. if forbidden_request?(path) return forbidden_response(env) end # Look up the asset. options = {} options[:pipeline] = :self if body_only?(env) asset = find_asset(path, options) # 2.x/3.x compatibility hack. Just ignore fingerprints on ?body=1 requests. # 3.x/4.x prefers strong validation of fingerprint to body contents, but # 2.x just ignored it. if asset && parse_asset_uri(asset.uri)[1][:pipeline] == "self" fingerprint = nil end if fingerprint if_match = fingerprint elsif env['HTTP_IF_MATCH'] if_match = env['HTTP_IF_MATCH'][/^"(\w+)"$/, 1] end if env['HTTP_IF_NONE_MATCH'] if_none_match = env['HTTP_IF_NONE_MATCH'][/^"(\w+)"$/, 1] end if asset.nil? status = :not_found elsif fingerprint && asset.etag != fingerprint status = :not_found elsif if_match && asset.etag != if_match status = :precondition_failed elsif if_none_match && asset.etag == if_none_match status = :not_modified else status = :ok end case status when :ok logger.info "#{msg} 200 OK (#{time_elapsed.call}ms)" ok_response(asset, env) when :not_modified logger.info "#{msg} 304 Not Modified (#{time_elapsed.call}ms)" not_modified_response(env, if_none_match) when :not_found logger.info "#{msg} 404 Not Found (#{time_elapsed.call}ms)" not_found_response(env) when :precondition_failed logger.info "#{msg} 412 Precondition Failed (#{time_elapsed.call}ms)" precondition_failed_response(env) end rescue Exception => e logger.error "Error compiling asset #{path}:" logger.error "#{e.class.name}: #{e.message}" case File.extname(path) when ".js" # Re-throw JavaScript asset exceptions to the browser logger.info "#{msg} 500 Internal Server Error\n\n" return javascript_exception_response(e) when ".css" # Display CSS asset exceptions in the browser logger.info "#{msg} 500 Internal Server Error\n\n" return css_exception_response(e) else raise end end private def forbidden_request?(path) # Prevent access to files elsewhere on the file system # # http://example.org/assets/../../../etc/passwd # path.include?("..") || absolute_path?(path) || path.include?("://") end def head_request?(env) env['REQUEST_METHOD'] == 'HEAD' end # Returns a 200 OK response tuple def ok_response(asset, env) if head_request?(env) [ 200, headers(env, asset, 0), [] ] else [ 200, headers(env, asset, asset.length), asset ] end end # Returns a 304 Not Modified response tuple def not_modified_response(env, etag) [ 304, cache_headers(env, etag), [] ] end # Returns a 403 Forbidden response tuple def forbidden_response(env) if head_request?(env) [ 403, { "Content-Type" => "text/plain", "Content-Length" => "0" }, [] ] else [ 403, { "Content-Type" => "text/plain", "Content-Length" => "9" }, [ "Forbidden" ] ] end end # Returns a 404 Not Found response tuple def not_found_response(env) if head_request?(env) [ 404, { "Content-Type" => "text/plain", "Content-Length" => "0", "X-Cascade" => "pass" }, [] ] else [ 404, { "Content-Type" => "text/plain", "Content-Length" => "9", "X-Cascade" => "pass" }, [ "Not found" ] ] end end def method_not_allowed_response [ 405, { "Content-Type" => "text/plain", "Content-Length" => "18" }, [ "Method Not Allowed" ] ] end def precondition_failed_response(env) if head_request?(env) [ 412, { "Content-Type" => "text/plain", "Content-Length" => "0", "X-Cascade" => "pass" }, [] ] else [ 412, { "Content-Type" => "text/plain", "Content-Length" => "19", "X-Cascade" => "pass" }, [ "Precondition Failed" ] ] end end # Returns a JavaScript response that re-throws a Ruby exception # in the browser def javascript_exception_response(exception) err = "#{exception.class.name}: #{exception.message}\n (in #{exception.backtrace[0]})" body = "throw Error(#{err.inspect})" [ 200, { "Content-Type" => "application/javascript", "Content-Length" => body.bytesize.to_s }, [ body ] ] end # Returns a CSS response that hides all elements on the page and # displays the exception def css_exception_response(exception) message = "\n#{exception.class.name}: #{exception.message}" backtrace = "\n #{exception.backtrace.first}" body = <<-CSS html { padding: 18px 36px; } head { display: block; } body { margin: 0; padding: 0; } body > * { display: none !important; } head:after, body:before, body:after { display: block !important; } head:after { font-family: sans-serif; font-size: large; font-weight: bold; content: "Error compiling CSS asset"; } body:before, body:after { font-family: monospace; white-space: pre-wrap; } body:before { font-weight: bold; content: "#{escape_css_content(message)}"; } body:after { content: "#{escape_css_content(backtrace)}"; } CSS [ 200, { "Content-Type" => "text/css; charset=utf-8", "Content-Length" => body.bytesize.to_s }, [ body ] ] end # Escape special characters for use inside a CSS content("...") string def escape_css_content(content) content. gsub('\\', '\\\\005c '). gsub("\n", '\\\\000a '). gsub('"', '\\\\0022 '). gsub('/', '\\\\002f ') end # Test if `?body=1` or `body=true` query param is set def body_only?(env) env["QUERY_STRING"].to_s =~ /body=(1|t)/ end def cache_headers(env, etag) headers = {} # Set caching headers headers["Cache-Control"] = "public" headers["ETag"] = %("#{etag}") # If the request url contains a fingerprint, set a long # expires on the response if path_fingerprint(env["PATH_INFO"]) headers["Cache-Control"] << ", max-age=31536000" # Otherwise set `must-revalidate` since the asset could be modified. else headers["Cache-Control"] << ", must-revalidate" headers["Vary"] = "Accept-Encoding" end headers end def headers(env, asset, length) headers = {} # Set content length header headers["Content-Length"] = length.to_s # Set content type header if type = asset.content_type # Set charset param for text/* mime types if type.start_with?("text/") && asset.charset type += "; charset=#{asset.charset}" end headers["Content-Type"] = type end headers.merge(cache_headers(env, asset.etag)) end # Gets ETag fingerprint. # # "foo-0aa2105d29558f3eb790d411d7d8fb66.js" # # => "0aa2105d29558f3eb790d411d7d8fb66" # def path_fingerprint(path) path[/-([0-9a-f]{7,128})\.[^.]+\z/, 1] end end end sprockets-3.7.2/lib/sprockets/transformers.rb000066400000000000000000000105521331222022000213630ustar00rootroot00000000000000require 'sprockets/http_utils' require 'sprockets/processor_utils' require 'sprockets/utils' module Sprockets module Transformers include HTTPUtils, ProcessorUtils, Utils # Public: Two level mapping of a source mime type to a target mime type. # # environment.transformers # # => { 'text/coffeescript' => { # 'application/javascript' => ConvertCoffeeScriptToJavaScript # } # } # def transformers config[:transformers] end # Public: Register a transformer from and to a mime type. # # from - String mime type # to - String mime type # proc - Callable block that accepts an input Hash. # # Examples # # register_transformer 'text/coffeescript', 'application/javascript', # ConvertCoffeeScriptToJavaScript # # register_transformer 'image/svg+xml', 'image/png', ConvertSvgToPng # # Returns nothing. def register_transformer(from, to, proc) self.config = hash_reassoc(config, :registered_transformers, from) do |transformers| transformers.merge(to => proc) end compute_transformers! end # Internal: Resolve target mime type that the source type should be # transformed to. # # type - String from mime type # accept - String accept type list (default: '*/*') # # Examples # # resolve_transform_type('text/plain', 'text/plain') # # => 'text/plain' # # resolve_transform_type('image/svg+xml', 'image/png, image/*') # # => 'image/png' # # resolve_transform_type('text/css', 'image/png') # # => nil # # Returns String mime type or nil is no type satisfied the accept value. def resolve_transform_type(type, accept) find_best_mime_type_match(accept || '*/*', [type].compact + config[:transformers][type].keys) end # Internal: Expand accept type list to include possible transformed types. # # parsed_accepts - Array of accept q values # # Examples # # expand_transform_accepts([['application/javascript', 1.0]]) # # => [['application/javascript', 1.0], ['text/coffeescript', 0.8]] # # Returns an expanded Array of q values. def expand_transform_accepts(parsed_accepts) accepts = [] parsed_accepts.each do |(type, q)| accepts.push([type, q]) config[:inverted_transformers][type].each do |subtype| accepts.push([subtype, q * 0.8]) end end accepts end # Internal: Compose multiple transformer steps into a single processor # function. # # transformers - Two level Hash of a source mime type to a target mime type # types - Array of mime type steps # # Returns Processor. def compose_transformers(transformers, types) if types.length < 2 raise ArgumentError, "too few transform types: #{types.inspect}" end i = 0 processors = [] loop do src = types[i] dst = types[i+1] break unless src && dst unless processor = transformers[src][dst] raise ArgumentError, "missing transformer for type: #{src} to #{dst}" end processors.concat config[:postprocessors][src] processors << processor processors.concat config[:preprocessors][dst] i += 1 end if processors.size > 1 compose_processors(*processors.reverse) elsif processors.size == 1 processors.first end end private def compute_transformers! registered_transformers = self.config[:registered_transformers] transformers = Hash.new { {} } inverted_transformers = Hash.new { Set.new } registered_transformers.keys.flat_map do |key| dfs_paths([key]) { |k| registered_transformers[k].keys } end.each do |types| src, dst = types.first, types.last processor = compose_transformers(registered_transformers, types) transformers[src] = {} unless transformers.key?(src) transformers[src][dst] = processor inverted_transformers[dst] = Set.new unless inverted_transformers.key?(dst) inverted_transformers[dst] << src end self.config = hash_reassoc(config, :transformers) { transformers } self.config = hash_reassoc(config, :inverted_transformers) { inverted_transformers } end end end sprockets-3.7.2/lib/sprockets/uglifier_compressor.rb000066400000000000000000000025571331222022000227260ustar00rootroot00000000000000require 'sprockets/autoload' require 'sprockets/digest_utils' module Sprockets # Public: Uglifier/Uglify compressor. # # To accept the default options # # environment.register_bundle_processor 'application/javascript', # Sprockets::UglifierCompressor # # Or to pass options to the Uglifier class. # # environment.register_bundle_processor 'application/javascript', # Sprockets::UglifierCompressor.new(comments: :copyright) # class UglifierCompressor VERSION = '1' # Public: Return singleton instance with default options. # # Returns UglifierCompressor object. def self.instance @instance ||= new end def self.call(input) instance.call(input) end def self.cache_key instance.cache_key end attr_reader :cache_key def initialize(options = {}) # Feature detect Uglifier 2.0 option support if Autoload::Uglifier::DEFAULTS[:copyright] # Uglifier < 2.x options[:copyright] ||= false else # Uglifier >= 2.x options[:comments] ||= :none end @options = options @cache_key = "#{self.class.name}:#{Autoload::Uglifier::VERSION}:#{VERSION}:#{DigestUtils.digest(options)}".freeze end def call(input) @uglifier ||= Autoload::Uglifier.new(@options) @uglifier.compile(input[:data]) end end end sprockets-3.7.2/lib/sprockets/unloaded_asset.rb000066400000000000000000000121241331222022000216250ustar00rootroot00000000000000require 'sprockets/uri_utils' require 'sprockets/uri_tar' module Sprockets # Internal: Used to parse and store the URI to an unloaded asset # Generates keys used to store and retrieve items from cache class UnloadedAsset # Internal: Initialize object for generating cache keys # # uri - A String containing complete URI to a file including scheme # and full path such as # "file:///Path/app/assets/js/app.js?type=application/javascript" # env - The current "environment" that assets are being loaded into. # We need it so we know where the +root+ (directory where sprockets # is being invoked). We also need for the `file_digest` method, # since, for some strange reason, memoization is provided by # overriding methods such as `stat` in the `PathUtils` module. # # Returns UnloadedAsset. def initialize(uri, env) @uri = uri.to_s @env = env @compressed_path = URITar.new(uri, env).compressed_path @params = nil # lazy loaded @filename = nil # lazy loaded end attr_reader :compressed_path, :uri # Internal: Full file path without schema # # This returns a string containing the full path to the asset without the schema. # Information is loaded lazilly since we want `UnloadedAsset.new(dep, self).relative_path` # to be fast. Calling this method the first time allocates an array and a hash. # # Example # # If the URI is `file:///Full/path/app/assets/javascripts/application.js"` then the # filename would be `"/Full/path/app/assets/javascripts/application.js"` # # Returns a String. def filename unless @filename load_file_params end @filename end # Internal: Hash of param values # # This information is generated and used internally by sprockets. # Known keys include `:type` which store the asset's mime-type, `:id` which is a fully resolved # digest for the asset (includes dependency digest as opposed to a digest of only file contents) # and `:pipeline`. Hash may be empty. # # Example # # If the URI is `file:///Full/path/app/assets/javascripts/application.js"type=application/javascript` # Then the params would be `{type: "application/javascript"}` # # Returns a Hash. def params unless @params load_file_params end @params end # Internal: Key of asset # # Used to retrieve an asset from the cache based on "compressed" path to asset. # A "compressed" path can either be relative to the root of the project or an # absolute path. # # Returns a String. def asset_key "asset-uri:#{compressed_path}" end # Public: Dependency History key # # Used to retrieve an array of "histories" each of which contain a set of stored dependencies # for a given asset path and filename digest. # # A dependency can refer to either an asset i.e. index.js # may rely on jquery.js (so jquery.js is a dependency), or other factors that may affect # compilation, such as the VERSION of sprockets (i.e. the environment) and what "processors" # are used. # # For example a history array with one Set of dependencies may look like: # # [["environment-version", "environment-paths", "processors:type=text/css&file_type=text/css", # "file-digest:///Full/path/app/assets/stylesheets/application.css", # "processors:type=text/css&file_type=text/css&pipeline=self", # "file-digest:///Full/path/app/assets/stylesheets"]] # # This method of asset lookup is used to ensure that none of the dependencies have been modified # since last lookup. If one of them has, the key will be different and a new entry must be stored. # # URI depndencies are later converted to "compressed" paths # # Returns a String. def dependency_history_key "asset-uri-cache-dependencies:#{compressed_path}:#{ @env.file_digest(filename) }" end # Internal: Digest key # # Used to retrieve a string containing the "compressed" path to an asset based on # a digest. The digest is generated from dependencies stored via information stored in # the `dependency_history_key` after each of the "dependencies" is "resolved" for example # "environment-version" may be resolved to "environment-1.0-3.2.0" for version "3.2.0" of sprockets # # Returns a String. def digest_key(digest) "asset-uri-digest:#{compressed_path}:#{digest}" end # Internal: File digest key # # The digest for a given file won't change if the path and the stat time hasn't changed # We can save time by not re-computing this information and storing it in the cache # # Returns a String. def file_digest_key(stat) "file_digest:#{compressed_path}:#{stat}" end private # Internal: Parses uri into filename and params hash # # Returns Array with filename and params hash def load_file_params @filename, @params = URIUtils.parse_asset_uri(uri) end end end sprockets-3.7.2/lib/sprockets/uri_tar.rb000066400000000000000000000052431331222022000203040ustar00rootroot00000000000000require 'sprockets/path_utils' module Sprockets # Internal: used to "expand" and "compress" values for storage class URITar attr_reader :scheme, :root, :path # Internal: Initialize object for compression or expansion # # uri - A String containing URI that may or may not contain the scheme # env - The current "environment" that assets are being loaded into. def initialize(uri, env) @root = env.root @env = env uri = uri.to_s if uri.include?("://".freeze) @scheme, _, @path = uri.partition("://".freeze) @scheme << "://".freeze else @scheme = "".freeze @path = uri end end # Internal: Converts full uri to a "compressed" uri # # If a uri is inside of an environment's root it will # be shortened to be a relative path. # # If a uri is outside of the environment's root the original # uri will be returned. # # Returns String def compress scheme + compressed_path end # Internal: Tells us if we are using an absolute path # # Nix* systems start with a `/` like /Users/schneems. # Windows systems start with a drive letter than colon and slash # like C:/Schneems. def absolute_path? PathUtils.absolute_path?(path) end # Internal: Convert a "compressed" uri to an absolute path # # If a uri is inside of the environment's root it will not # start with a slash for example: # # file://this/is/a/relative/path # # If a uri is outside the root, it will start with a slash: # # file:///This/is/an/absolute/path # # Returns String def expand if absolute_path? # Stored path was absolute, don't add root scheme + path else if scheme.empty? File.join(root, path) else # We always want to return an absolute uri, # make sure the path starts with a slash. scheme + File.join("/".freeze, root, path) end end end # Internal: Returns "compressed" path # # If the input uri is relative to the environment root # it will return a path relative to the environment root. # Otherwise an absolute path will be returned. # # Only path information is returned, and not scheme. # # Returns String def compressed_path # windows if !@root.start_with?("/".freeze) && path.start_with?("/".freeze) consistent_root = "/".freeze + @root else consistent_root = @root end if compressed_path = PathUtils.split_subpath(consistent_root, path) compressed_path else path end end end end sprockets-3.7.2/lib/sprockets/uri_utils.rb000066400000000000000000000121661331222022000206600ustar00rootroot00000000000000require 'uri' module Sprockets # Internal: Asset URI related parsing utilities. Mixed into Environment. # # An Asset URI identifies the compiled Asset result. It shares the file: # scheme and requires an absolute path. # # Other query parameters # # type - String output content type. Otherwise assumed from file extension. # This maybe different than the extension if the asset is transformed # from one content type to another. For an example .coffee -> .js. # # id - Unique fingerprint of the entire asset and all its metadata. Assets # will only have the same id if they serialize to an identical value. # # pipeline - String name of pipeline. # module URIUtils extend self # Internal: Parse URI into component parts. # # uri - String uri # # Returns Array of components. def split_uri(uri) URI.split(uri) end # Internal: Join URI component parts into String. # # Returns String. def join_uri(scheme, userinfo, host, port, registry, path, opaque, query, fragment) URI::Generic.new(scheme, userinfo, host, port, registry, path, opaque, query, fragment).to_s end # Internal: Parse file: URI into component parts. # # uri - String uri # # Returns [scheme, host, path, query]. def split_file_uri(uri) scheme, _, host, _, _, path, _, query, _ = URI.split(uri) path = URI::Generic::DEFAULT_PARSER.unescape(path) path.force_encoding(Encoding::UTF_8) # Hack for parsing Windows "file:///C:/Users/IEUser" paths path.gsub!(/^\/([a-zA-Z]:)/, '\1'.freeze) [scheme, host, path, query] end # Internal: Join file: URI component parts into String. # # Returns String. def join_file_uri(scheme, host, path, query) str = "#{scheme}://" str << host if host path = "/#{path}" unless path.start_with?("/") str << URI::Generic::DEFAULT_PARSER.escape(path) str << "?#{query}" if query str end # Internal: Check if String is a valid Asset URI. # # str - Possible String asset URI. # # Returns true or false. def valid_asset_uri?(str) # Quick prefix check before attempting a full parse str.start_with?("file://") && parse_asset_uri(str) ? true : false rescue URI::InvalidURIError false end # Internal: Parse Asset URI. # # Examples # # parse("file:///tmp/js/application.coffee?type=application/javascript") # # => "/tmp/js/application.coffee", {type: "application/javascript"} # # uri - String asset URI # # Returns String path and Hash of symbolized parameters. def parse_asset_uri(uri) scheme, _, path, query = split_file_uri(uri) unless scheme == 'file' raise URI::InvalidURIError, "expected file:// scheme: #{uri}" end return path, parse_uri_query_params(query) end # Internal: Build Asset URI. # # Examples # # build("/tmp/js/application.coffee", type: "application/javascript") # # => "file:///tmp/js/application.coffee?type=application/javascript" # # path - String file path # params - Hash of optional parameters # # Returns String URI. def build_asset_uri(path, params = {}) join_file_uri("file", nil, path, encode_uri_query_params(params)) end # Internal: Parse file-digest dependency URI. # # Examples # # parse("file-digest:/tmp/js/application.js") # # => "/tmp/js/application.js" # # uri - String file-digest URI # # Returns String path. def parse_file_digest_uri(uri) scheme, _, path, _ = split_file_uri(uri) unless scheme == 'file-digest'.freeze raise URI::InvalidURIError, "expected file-digest scheme: #{uri}" end path end # Internal: Build file-digest dependency URI. # # Examples # # build("/tmp/js/application.js") # # => "file-digest:/tmp/js/application.js" # # path - String file path # # Returns String URI. def build_file_digest_uri(path) join_file_uri('file-digest'.freeze, nil, path, nil) end # Internal: Serialize hash of params into query string. # # params - Hash of params to serialize # # Returns String query or nil if empty. def encode_uri_query_params(params) query = [] params.each do |key, value| case value when Integer query << "#{key}=#{value}" when String, Symbol query << "#{key}=#{URI::Generic::DEFAULT_PARSER.escape(value.to_s)}" when TrueClass query << "#{key}" when FalseClass, NilClass else raise TypeError, "unexpected type: #{value.class}" end end "#{query.join('&')}" if query.any? end # Internal: Parse query string into hash of params # # query - String query string # # Return Hash of params. def parse_uri_query_params(query) query.to_s.split('&').reduce({}) do |h, p| k, v = p.split('=', 2) v = URI::Generic::DEFAULT_PARSER.unescape(v) if v h[k.to_sym] = v || true h end end end end sprockets-3.7.2/lib/sprockets/utils.rb000066400000000000000000000137261331222022000200040ustar00rootroot00000000000000require 'set' module Sprockets # Internal: Utils, we didn't know where else to put it! Functions may # eventually be shuffled into more specific drawers. module Utils extend self # Internal: Check if object can safely be .dup'd. # # Similar to ActiveSupport #duplicable? check. # # obj - Any Object # # Returns false if .dup would raise a TypeError, otherwise true. def duplicable?(obj) if RUBY_VERSION >= "2.4.0" true else case obj when NilClass, FalseClass, TrueClass, Symbol, Numeric false else true end end end # Internal: Duplicate and store key/value on new frozen hash. # # Seperated for recursive calls, always use hash_reassoc(hash, *keys). # # hash - Hash # key - Object key # # Returns Hash. def hash_reassoc1(hash, key) hash = hash.dup if hash.frozen? old_value = hash[key] old_value = old_value.dup if duplicable?(old_value) new_value = yield old_value new_value.freeze if duplicable?(new_value) hash.store(key, new_value) hash.freeze end # Internal: Duplicate and store key/value on new frozen hash. # # Similar to Hash#store for nested frozen hashes. # # hash - Hash # key - Object keys. Use multiple keys for nested hashes. # block - Receives current value at key. # # Examples # # config = {paths: ["/bin", "/sbin"]}.freeze # new_config = hash_reassoc(config, :paths) do |paths| # paths << "/usr/local/bin" # end # # Returns duplicated frozen Hash. def hash_reassoc(hash, *keys, &block) if keys.size == 1 hash_reassoc1(hash, keys[0], &block) else hash_reassoc1(hash, keys[0]) do |value| hash_reassoc(value, *keys[1..-1], &block) end end end # Internal: Check if string has a trailing semicolon. # # str - String # # Returns true or false. def string_end_with_semicolon?(str) i = str.size - 1 while i >= 0 c = str[i].ord i -= 1 # Need to compare against the ordinals because the string can be UTF_8 or UTF_32LE encoded # 0x0A == "\n" # 0x20 == " " # 0x09 == "\t" # 0x3B == ";" unless c == 0x0A || c == 0x20 || c == 0x09 return c === 0x3B end end true end # Internal: Accumulate asset source to buffer and append a trailing # semicolon if necessary. # # buf - String buffer to append to # source - String source to append # # Returns buf String. def concat_javascript_sources(buf, source) if source.bytesize > 0 buf << source # If the source contains non-ASCII characters, indexing on it becomes O(N). # This will lead to O(N^2) performance in string_end_with_semicolon?, so we should use 32 bit encoding to make sure indexing stays O(1) source = source.encode(Encoding::UTF_32LE) unless source.ascii_only? if !string_end_with_semicolon?(source) buf << ";\n" elsif source[source.size - 1].ord != 0x0A buf << "\n" end end buf end # Internal: Prepends a leading "." to an extension if its missing. # # normalize_extension("js") # # => ".js" # # normalize_extension(".css") # # => ".css" # def normalize_extension(extension) extension = extension.to_s if extension[/^\./] extension else ".#{extension}" end end # Internal: Feature detect if UnboundMethods can #bind to any Object or # just Objects that share the same super class. # Basically if RUBY_VERSION >= 2. UNBOUND_METHODS_BIND_TO_ANY_OBJECT = begin foo = Module.new { def bar; end } foo.instance_method(:bar).bind(Object.new) true rescue TypeError false end # Internal: Inject into target module for the duration of the block. # # mod - Module # # Returns result of block. def module_include(base, mod) old_methods = {} mod.instance_methods.each do |sym| old_methods[sym] = base.instance_method(sym) if base.method_defined?(sym) end unless UNBOUND_METHODS_BIND_TO_ANY_OBJECT base.send(:include, mod) unless base < mod end mod.instance_methods.each do |sym| method = mod.instance_method(sym) base.send(:define_method, sym, method) end yield ensure mod.instance_methods.each do |sym| base.send(:undef_method, sym) if base.method_defined?(sym) end old_methods.each do |sym, method| base.send(:define_method, sym, method) end end # Internal: Post-order Depth-First search algorithm. # # Used for resolving asset dependencies. # # initial - Initial Array of nodes to traverse. # block - # node - Current node to get children of # # Returns a Set of nodes. def dfs(initial) nodes, seen = Set.new, Set.new stack = Array(initial).reverse while node = stack.pop if seen.include?(node) nodes.add(node) else seen.add(node) stack.push(node) stack.concat(Array(yield node).reverse) end end nodes end # Internal: Post-order Depth-First search algorithm that gathers all paths # along the way. # # TODO: Rename function. # # path - Initial Array node path # block - # node - Current node to get children of # # Returns an Array of node Arrays. def dfs_paths(path) paths = [] stack, seen = [path], Set.new while path = stack.pop if !seen.include?(path.last) seen.add(path.last) paths << path if path.size > 1 Array(yield path.last).reverse_each do |node| stack.push(path + [node]) end end end paths end end end sprockets-3.7.2/lib/sprockets/utils/000077500000000000000000000000001331222022000174465ustar00rootroot00000000000000sprockets-3.7.2/lib/sprockets/utils/gzip.rb000066400000000000000000000042511331222022000207460ustar00rootroot00000000000000module Sprockets module Utils class Gzip # Private: Generates a gzipped file based off of reference file. def initialize(asset) @content_type = asset.content_type @source = asset.source @charset = asset.charset end # What non-text mime types should we compress? This list comes from: # https://www.fastly.com/blog/new-gzip-settings-and-deciding-what-compress COMPRESSABLE_MIME_TYPES = { "application/vnd.ms-fontobject" => true, "application/x-font-opentype" => true, "application/x-font-ttf" => true, "image/x-icon" => true, "image/svg+xml" => true } # Private: Returns whether or not an asset can be compressed. # # We want to compress any file that is text based. # You do not want to compress binary # files as they may already be compressed and running them # through a compression algorithm would make them larger. # # Return Boolean. def can_compress?(mime_types) # The "charset" of a mime type is present if the value is # encoded text. We can check this value to see if the asset # can be compressed. # # We also check against our list of non-text compressible mime types @charset || COMPRESSABLE_MIME_TYPES.include?(@content_type) end # Private: Opposite of `can_compress?`. # # Returns Boolean. def cannot_compress?(mime_types) !can_compress?(mime_types) end # Private: Generates a gzipped file based off of reference asset. # # Compresses the target asset's contents and puts it into a file with # the same name plus a `.gz` extension in the same folder as the original. # Does not modify the target asset. # # Returns nothing. def compress(target) mtime = PathUtils.stat(target).mtime PathUtils.atomic_write("#{target}.gz") do |f| gz = Zlib::GzipWriter.new(f, Zlib::BEST_COMPRESSION) gz.mtime = mtime gz.write(@source) gz.close File.utime(mtime, mtime, f.path) end nil end end end end sprockets-3.7.2/lib/sprockets/version.rb000066400000000000000000000000511331222022000203140ustar00rootroot00000000000000module Sprockets VERSION = "3.7.2" end sprockets-3.7.2/lib/sprockets/yui_compressor.rb000066400000000000000000000024541331222022000217220ustar00rootroot00000000000000require 'sprockets/autoload' require 'sprockets/digest_utils' module Sprockets # Public: YUI compressor. # # To accept the default options # # environment.register_bundle_processor 'application/javascript', # Sprockets::YUICompressor # # Or to pass options to the YUI::JavaScriptCompressor class. # # environment.register_bundle_processor 'application/javascript', # Sprockets::YUICompressor.new(munge: true) # class YUICompressor VERSION = '1' # Public: Return singleton instance with default options. # # Returns YUICompressor object. def self.instance @instance ||= new end def self.call(input) instance.call(input) end def self.cache_key instance.cache_key end attr_reader :cache_key def initialize(options = {}) @options = options @cache_key = "#{self.class.name}:#{Autoload::YUI::Compressor::VERSION}:#{VERSION}:#{DigestUtils.digest(options)}".freeze end def call(input) data = input[:data] case input[:content_type] when 'application/javascript' Autoload::YUI::JavaScriptCompressor.new(@options).compress(data) when 'text/css' Autoload::YUI::CssCompressor.new(@options).compress(data) else data end end end end sprockets-3.7.2/sprockets.gemspec000066400000000000000000000027561331222022000171170ustar00rootroot00000000000000$:.unshift File.expand_path("../lib", __FILE__) require "sprockets/version" Gem::Specification.new do |s| s.name = "sprockets" s.version = Sprockets::VERSION s.summary = "Rack-based asset packaging system" s.description = "Sprockets is a Rack-based asset packaging system that concatenates and serves JavaScript, CoffeeScript, CSS, LESS, Sass, and SCSS." s.license = "MIT" s.files = Dir["README.md", "CHANGELOG.md", "LICENSE", "lib/**/*.rb"] s.executables = ["sprockets"] s.add_dependency "rack", "> 1", "< 3" s.add_dependency "concurrent-ruby", "~> 1.0" s.add_development_dependency "closure-compiler", "~> 1.1" s.add_development_dependency "coffee-script-source", "~> 1.6" s.add_development_dependency "coffee-script", "~> 2.2" s.add_development_dependency "eco", "~> 1.0" s.add_development_dependency "ejs", "~> 1.0" s.add_development_dependency "execjs", "~> 2.0" s.add_development_dependency "minitest", "~> 5.0" s.add_development_dependency "nokogiri", "~> 1.3" s.add_development_dependency "rack-test", "~> 0.6" s.add_development_dependency "rake", "~> 10.0" s.add_development_dependency "sass", "~> 3.1" s.add_development_dependency "uglifier", "~> 2.3" s.add_development_dependency "yui-compressor", "~> 0.12" s.required_ruby_version = '>= 1.9.3' s.authors = ["Sam Stephenson", "Joshua Peek"] s.email = ["sstephenson@gmail.com", "josh@joshpeek.com"] s.homepage = "https://github.com/rails/sprockets" s.rubyforge_project = "sprockets" end sprockets-3.7.2/test/000077500000000000000000000000001331222022000145025ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/000077500000000000000000000000001331222022000163535ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/000077500000000000000000000000001331222022000174725ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/POW.png000066400000000000000000001236451331222022000206600ustar00rootroot00000000000000PNG  IHDR,K9tEXtSoftwareAdobe ImageReadyqe<fiTXtXML:com.adobe.xmp pmPLTEjjjlll ޼pppzzy}}}uuuܹddcى􁁁+++[[[SSSKKKBBB333<<<$$$rrr뤤렠nnnԘ ǀ||{xxwppnnnl___rrptttlljggfOOOWWWHHG777///(((g-IIDATx콋[X>@IQ0Y5QT6rDDZѢ>ޟyj=_>vi:3׬^{kmuM/#_/Rͯj~巖_oef~=jK7#(sK7՜EEEMj" K'DUEZTt$A<'j4:pɊ(x~G~ 3y;m :~W\RA7t{ ÐYT0*zV aTiNFw wHoF%ڭ.u^P]P3ڳa TA7Tc5#"x&ͿپKLST>² T=T,ҽ*i hF&>ͯl$+2'_k¦Pdx&)e ,5Z-20$uQ8,!L|tg+~U#0_A{IDނdl]uvFk2߽?(jʜzT_nײمE'uK5烘L&߷eK?FBO"fW0[[Cd .X4 bɐKG-!c3'dN>׫bMS,1י7^:)aYSPS}TC^Qc*tuZyrA e{xEm2„#F.0Sa穊ȵ]5! hॲxej2,i"V{xj&Y^ga@pUm , b,f٣op'p7:_k(xnk|X"0e>Jj9+30ґ׾^f.=s[YsIT{><1Xͨt6ܻ}:'.&Go:fSci80b/( |`Օᘷ!V$U^i>3vڕw&߶gbkS9#OU | jՠSuz66hß6_w) W媩HZDX0$IUv2 GdC'=6F9Fe zxpVbLJ Q8um>8pvNk؂-skͪ돈,"oƘ Jeq|d߲ {F9Z{T=Ea] ' UiNM.O_xY*6C(ӄj"~b>UᙵTUc0=! 2\or>geP*(ź (kk)7)(`6:cWodqb7'ۦEmܝP/d/V͖@qoC;W 2T,Trļ ZK=A ?b|=Lfnb č|x!ف|ܰ ߣ!)·l^'Cn_7 Ѓ ? s?[C@^V:®nX\f؆;>(}U $o|-Fz#FpGی4›։BS[og!؆86?|H9w z5&MxVU`G8$]sUЄЯv[ HG{1;WdR`j"WR8,坦@oz8s x@RT,ZX)˲^BQESTb86|'hM?OmcWOsUѝkwlogq` %8!DQ*# C @0!R V T0 ژ @w}3];\\arsUӬB;{pNp`G]o)1w my[~{=ҹ`Bܶ=C|sw:蝋udٺڝRtYˮ݅iZnơ-by̐Vhz0vfp}uU="WY߀ޒij2uגiWX'C zk孾>oy;O/3@;.ț o7t$ CZRS'\@|3+y瀧gTO>vZ~Z}Li/23 "E4›G o: ?0K`oHc*k鱚r,=Bi*6R+9 D\*$eD1W]m঻XbY t|OyG/Vv u|%3<e![7/Lu sA8bne6Ab0ͲaD4gYjy xsȲ3U?2۟p@B/a"ץj v̈́Pg># :g7г<9&B[LO ?t>;zwEH& ӑ-3]# |D `HT$]Hj 'fQ8m [mli9}+t݉kJ' Y[>gl"q o/fX' (vmض6;ml~ۮS*sk<#X$MBL xEXm'wQTښ1{.#shl9:B7*cӴ{v-g̟Lx-m@hۀ́0aŸ1έ-tfvvFIF8i6Ge4^X3:kb51?Y5do5HU3<3 V3ƖE1`t<'@ Ba|0S&$Vba0=.]>/\tu)V\OKׅF%ݛ|pmaR4V]Iš!Mŋ T=MbqLlwŰpfQgcv&ۼ!&0%¥e4${ՠE W.i[Dhg!1G;Jw ^%El ,oj(&*Ĺ!imwv47 f›%:z6%`;6yJۯޯ>`uW%tPhLFph<^|FIpDROUTtI\/Q h٤TOhb=nZ6aؑ f`*Ithq:Fs~$D[~{e$J&OwW*og:)6pחs}(_XGܗD0qosڶP9%w_ vsN8gݞ[ߒ϶F]3K}3s 1ITVWDPq syݞz ۠pن@zpǁl$p;뺳U[;|Slr%ݼuIp`MF8 @xFh\O`Tmr_=t/[ {D`{FzJ}cʯ%gV_[a:Ge߀LoVWQ`0Iϱ~/T6zI@ 89acGwwΤgEz=p̾A}P?2Xz6k'Fvj|8*sO}%xKa mD>*2l8nx|h[zȷ{x픧fY~m^ϱ{;A(=p x6Z@ۡB-<*h=SU HST9{l\*PEƯo1n/cE0Ÿ"r~]Ax;vmB[+x!xt7k{Å¥m`!W(E(vglmwbvuwk i8?o?`jA'1"v77]_?{7CH |v ZUfܹ϶yOϗ! *qhg4mWw[/8Ȅʇa }ݴai/H,xnXf_ٸ %Ɩ-loApwvmK=[?g "" Lr[REҨ2u=^FVxde]4B9hG!77}G ]uv*kM|(Y^Eވ*MFnr06i#b@o,g=sø{/ 7~ܠAck6ModHAD$U:4MߊĞU, 0\P9u ťer0x̲, ozXvZ#n?._6aX>ZN/Ev?HWi?$;75uxvvX6Cc=pv{)ve=se}=hTE7RUHD:6Cu_CJ!w5zRgx&=cA=!7}~|uٳ~R!UE$֢6&]f `ai:֜_I߇mvέpMD3[Eo)Daw`400[N7B]U8a ^0,D57j l~[Yݮr|9!Bs&3cL@n6VAehnBRa4xk<ڙ@HϻԄ i#?Qiz q{<Ʊ~a^F aBE'{U&ZjֹBƘ"8xj of@=nu'̄tIUb+oSOQqYlb:J8}!h)"HkDCJv0Z%a/U @5ׄ7yu~ o^vK$qQ􄢉 TCMXVz  M(dR7Gq)kTf-fvJcR= ]mv?b)agb8c@'ԊM9Eoe:-g˾A7O|ecvq`*]3OnSWܰ\G! >mGbw(=lF흧۴-z꽟{Q(e%,Ih-*Q XO#93䂌"t56 _x@`!|vx|w'omm葥jIxqZdQsxd4M x=;WڼL܆D/ƳмwIfUx ekHxyfT6AO~'b!ȫۄ2,@+2zь͞A/M(F&|W?hosaQaMx3f H}NMgs@x3eDxs1]z 9<({,}Y {WE-0Ҹ;m#a R; ͆Fгio66m4/-[ 0MaO $aj:0Ȱ GS\pT5j -J [\'+1&6(P?{]qZ .tUE͌zL*ãSa[_}}FrVQ@ v (l&2H6&4 Ꮻ<'U y6Z 1m숻SĒIMKd):j+$!K0hƅyޜ B(VnNQ8Q5NSJ7ϞĪ0^"jQ T&J*@Hsf$NLȏ7Kd #'.jRĒ7L,eMx3H73Ɛ>ah 3(wT^ &h:$ Ah" g 8(j и o~@*g KuRb/?M8 b,2x( `U3!ܟ9|7K@wY3)9 gMTj x YuGPc#RZMVPh(&4ȿ,h//7D>߼@on7m`n1lm]gtN;ڌĶ{s4:r>M`ݦn8BBX;]kz 9YՑsƉ4i@fD/qB#D ?A5q~2J?hC֗Oӊpqt-a; ,4ÒA r 4f|hװN:@͜CxOo3]%FO O5FǛ+s3W"5f/B=l4sUtИ;A/0HO AhB[p4AEgeD;sP97Tn#(+oTx JS'qHvGص(?6iP]KQg8cJ+1jb[5N"eCpҕu*x,UT?JMvov}!zP}*v(|Ç+34`8##=bU0Ûb^5/&T2XV 8LQ QA8µ}x60Xm|?en% Wr5$Ti\?(9~P5tRp(s|}#)pBh8Ni;onhV._.`jpƘzӤ8lll.TΓǏyoL%dj, EB`iEx8}7(ik|ѵh{ݶ#~&㏲naOS}={y6xK"xEZTi>[&3&X*G wtf9 _$fF1h07!;u u2A|WSjo n›{%JIX/oKƽ-] ؍;[ێBg4Bn `;:[VVϷ熆:SSD-9lxi6Bf)ā=#@،1DY#Gs尭=ok裂$pXRWNM ѳ]{sp>%aN%P!FہM Y ۴9s~ar RR$P'+Ffmޠ;5Y t k;Zp₩!2(,@PT]W^2gVA@V-p"D'R۔ȑzi"T3/D^K"StWE"|A r㷓|nR VQ$o9;23C2;TRfd)!qn J&&Ʒx Paq.K3)/[o`[xYSq\U QV#4qԿ$Cs,~&|J£OKQS/.``)jf¹; xXYֻFQ!E1Yj#&eadȔȧɬxv潭-˂9߯z'p!J*9 v\ʶ.t9#6EJq{uGclИL4|.ʽu(L%;"Ř ,p:رjr2]KTqhs"3WpzLL? !pQhogXԩ#_#зP.OωT֪|O#ޜJ}zcOyj8׍}T{uA%xXj1t za|yIAl8'AY+Dt֞_|NRzbU%Y/Sk5»~MbkTx7ڞijqD,KT'amk%9b8Mn}Ѱ146gr@9YfagނR_Aߢ48amL$|}Xu8m,<.negfAp(rKدՉ'2s3@ުˁ̂HvԁU v4[XEGdIR9}P{ ö}k)u۳agล=q'i-Mz.ސD5#!iಆ/2(3uB՜M .OosOw!:os|xo#B =q~Xc/ DHN??Gk"f %#kWx#+)=kyWRmF3#X'mܺl76Aw]S*fl@Q 9.1ubHj%8dNgsniw+?i$~{KPEzM/tpN׌9CcNOw/'{gݲSIH\jyDg!z=dLco}˅8X*׈h8>CzLZLQ1ɝhLoooI o4XWVsJb\ 6\o)|}j%<?y1ȸ_37/P=IsߝBlԂqp櫟GTlvg]ࠫ~0_Ϳԫv#DDF /+NbŊ 'M[ŕ L5H~_Eu}9j$bv=e>琰i_cm@xs/#0ß7~3+Ҩds $qu=L\EՈ Z/ʅAwrϦ;Nm›#|}v.$T'-42oˏa\iLT=+2- Ͽ,,9S_}j`udRu}asw8ѴG2j96ڴhpCLvMfCU2KlNdj£R BX37Y?b›%_Є7@p}7]w7e<MU+ a4֪'~D&)C0k2!&n+sVZeտW^%skgoANM7MQN]cl>kqx4dj$gNQ1(ϾxIs`Mn9 xHC^cg-`›k;(OapcQ@f9h[B1]K.j_s kT=':Y]yhzXv2nFtcDy{d9%ivDǜt]tG^ޅF hxTExzY8?S  i>׏N46 z[T]@vlfBDE -jRЂ/@[WI,BKž8wh|\LwcSTu"u14bO47e23pcuA$5D2+otQ"X>T{Z](#y/dBw֊]N ]M`,u 6&___kaVLTLdq[u(X)εBNWߋR1ڗUd}B_Ӕ~N쾨+U!UUTؤͦJVFm8w` LΓ5+b9BtF곰ə'dq##UHldEL .KjV4V\Pȸ鮷@nQm5){8ji\\SULNg\~CI ;sNfO6|G̢-k#[Z|ypfT&SiG.2>9asI@I:ܐLfiEΕC0&fjQeE&wͺ ̩YbYwG NN1+{z q~ LYژj_|i vU3KXHt'%TL;;26#2",WXA@bN 9AXg*m3Tc\ O@yGvT˲XbaR#Z5xy kG̋_fʇ,]`/9o`ݓb'1kOca^>$n,ʻ䡈c^Y-ObV+J&z)y;`dOQ7y_CXVjYF*554QѸ-Vo^|5, rݤ5' nH.}C B !14Q k ;s̞Evp=\p@FyuZCR"kM{eKd7]m)&^dDF)*r˨/7F@dZ"S(hƠ ^c UwBzf=e: RcluZPrF,0"!?f[cK"C 15RGg 59xJ03` I_;"C a%v |Pg"Ef.vVly?ԓ`ޗ9J&W[HYDUƁL5{`gtYXxITcs6)ޤR3O=a4T6"fᡃVWOz#<*>0W:C"DQ8AMT׺Yod~;VfU.x}Yąz(.W4K?O59'4 :]88.9! 5ikx,RcK!!?bѓm، $_>\4`I]zk,>ۦpfV/+SR}WlB@g堏=ZtnjEY0Lw5nFkp Lg`!/"ZM5ē w }KaJ7Gotk2-޴s^|}l!j%^GԕG>X ,Y*24W_cOس).ezV ܼZ}S) q\-kl1|TUƞ]x\XUR0-rX S 岌'v;/ Ւ9Xa/ 6y(ijbu] T3٭C{Heq2)j'9i2 jH>xU -su&l cA+fdDhAI0 ly1iac`I=mgQh'ʭw"%.H:^.3n@P;zWͣɛH70w],۝^E<|sזᶨHsY1ų'hŗ?ϒU NPB->Ym A /7<5s:x5-[u Nxfg2l `{ęsނ 2S ,"' ,2w[u}=|o䬅f>"/Ջ3 [0r][OsUC '[ "+Dkŀ QL3|д¿Q"ZJaոY iÄjU[qX5vGFh82>dϋ+A}}ԻYrLG*|]8Gٕ +%O z!Hu_9t[d= T,hn?Iab_nɝ8>ZDNQ[1դ&u r'psW}%~}"z35:W1UCBE%y<3$mӤeXZ!džjBDMޒ ֑::xpSV,A('@N>iYLwdQT M>~]+aןV ?MIЄvwxk3ɲ H6hh C'vpbA<}U;B&^ہ~JJ:QMIG܊ ۞M?S3 S 9㑏et 9uI3hҟUM71 `y {mC70EMU)yȪyBOj߈$>0vsykHo<>7w`4m22UN4u߮Zs[:$< 7[Z膰W-82 !W,^I98WdCl>=º{v=o|C[.ྷ8}I9̈k4XdTSV[xT@\0jEaI,]`hq#w0E+}t AzpO^[:[FcDe:oQT#c! ӱX,QzPZxfmquv*Qoh$4"}}~Ot 9a:^$: X~ؾtLIVǔi: e,Z?_MtPDdg9FjtvZc?Jf qRoV'}l[gS2ͮө 'cidF$Tb^LYOgP_FHF5_;;~홗o|XS)x ߜ֍8>G~h g& ~)pRE蚠0;S 2D*YdD.y3_~Y|]?,\lg.fËo̖8Y 6PMCz*Z՛W/za Mdh̾k] 0hR.L۲Ju4<%Sy|R&kn=8^X ( jk;pk'rEV&ao87岄D l~InةgG!A e^:"W$5"N]w\3Ul\ĩZ`4uGl:_Q5 UPT6-2}>_tjA*Շ&'p{ RY,(|äCx!tfG-k5bO>bi~.(g$fFcki Ɂ$ Д̀2.XxzC͇|X!;4WBΐ1V.W/)b ]7hAkkxs'/2wlmxHyEfZi:W6=r:\b]}-p/K|PGt/x02 -k[TXlDM3fSA"@|``p(*zPIJm]})Y+vi{Szo9ѸFT9 䎅bec{Ƭ~M38]"*)ԵD0LrK( -G9_0͐_s&Q5fVc*\۾٠U*Uf䧻Yjl*fxjcWI5vr ,,z)-dz,'+Ps(mYd$6=Ȳ;,p/6$ZmԧT:/r wF7TMjDj/[L cuK+K2yx`@: ! <EL, yƲ8,zٛmAm++hOyX7 KEE]i̹*,ΰh;r<BÖAHwHqaUhK}_kvom ؠ+5,J"'_wm0&{猿93ڮ~ߪzުd@ I@}'ԇ %f,hiP'q&k䝋}41s6 /LyscV u73y4Dd<]ͪ^ut45_$ob^ lzQ@K/Dwj5||G˜Kh,Fa:%gJ-@Zn"ʻ4-]!x3гPrޢ߇Z)rHo{07w9[2oXWoYt?dBk^kl&Jy~ .~>+8e]q Q6>ۭwbYLfؗ\Q4ɕH61Mk7u9phsޡMUC5M#EB %Z+ĩ 3*l\pq8.&)TࡅC K#%"(lAQHrda6MisΆ- s_rㅸRJ,',_E34 \X'[4M}&o[^Z+ei& ×I? $WmͧtH9}1Qh72qK%=*9c[.P,O|\9 b!W MCI|TXګĿnd,XcF %<Θi⣏t@L 84+nhY*FS vw ؅Yo  ̳1SvXXӐ|n'lJ-~&nӳ)Xs z sU!'> 6ՂE#NW#v 6]q7M @SFIȕeگWCˍ&d4F3wi&wXn| /=§J4M}Jh|TS_=y` \EWNPm:BvRu=#|V2zY K2g~u_")adc=OIC6H,gq>bW-2Y=OyYa`AXB.`y r3`{X5W_͎f%8c'`!u+] e 囕T;>@Z]tznIx'IiQWEbPN;QzO0$1]_52:ſe&Az)kfCo6y>)7Jh˨xoӛE*~ؐZ/ei19Nq%Lwfx|9fx1h((ZEn9uBВgw?s()?cuiꒈ.KKv3HmRS4ЭjeIRgdH5KA-lrwYCz3~DkҒIK=s~LRһ )d7<Vtv20dztK~qB$*pNWEJ fL Φ& -/S*9} X):>TPQ*6F䎺nI^lH61iY!@_x%fC k\uoU|xh4 uߗIjql ?6MH:rx3LJΉNJP Xyo: gD=v,RP`N_m`P[jjUk3|yi[ﳩաWXMCA~Q;i_2np 6I ? <$〶= ~JXkGV tn (?mςh\3i40,z3fЛo|Ebry wN1r41KXrY^s& :NQϲ%GY>("v,km MC+%й՚fͰІct+C"y=+j: qǁpޤl_ЛICEpے\p`ޡ7 I&L"P*퀛fd4o#rJ؜DXz_*I4LƻyBiQ@Nw ϰB)vNX嗹6gi;%Fo\X,FFo+6UkS|^$[HS+]>GZ֡#Qn<.}U#1 յ,XwBkY:R*zZVEF ykfJ\qǺ42k?~4ZEׂ6k%T! 6oM4frTzqqמ*kiB@0FNZZ8r$CvSoR?nIj3ed:xdDV 9o%*T]^F͡(=~49k)[=#~Çs>fNGJi7l/j9Sx?p_!5,_q@&㱉FWub<&:-jY!Yhms;$wk!FKs7GirpónirXҮRE< fb[72W>Uo>hDzKEٰzsF]%;RRow!ab.{]E4Yq@uKjbIA\bciu"iN5H<<;b~`vDK'pE.`I&81lyQm!޽ DoSiZB̑"lÕﻦFR^t:d=.ǗD8Pt[865ih7P^d!PQcV3ڗ^4;WA媊&IKi_|m)>(?+?Ж64D\@BY"ы]SYF\QWkKH󔼯 L3ÍM=pF@vhQ_]!B#m oY&'?'_m[ov8~׶wG=q-ҟ,}4V$f^lim8a$7MjeIӰNI$%iI+<&3S8%xJi Z[rR\8`WB?C|o5~DhUZMf$AvLM{&߈48YWgX3-[j"H$u-c h{83@l)%daM9sxlƊ#De(|V`#G̸[ $r Tl8lxܘw~ ĠlW`Ko#m ygQ@!Hq"x&%Qcy/(?cٍ^9x8>7gՇ,b=ˆjn\3ATJ>|f#wH놜PԢn4oB QD?Mz=2o.>TKw{UM$XiFOԆpG '`+ɤDpIhXx_D }#kD%r(HhiɖhS1%Ngj,4ײd4uJ>Л76FL[ <83Wӂ& ^ =J. q&WVrP/dՐbauCaPXQ]_(_!Z r" As #~-c:B ^ӳ՞$!1{(fMA@=t Z⹩Q|3#7z5h 9n[٫c+sju,[WmOcEܪ .TYˤhkp"ug$uX#çٔX.iKwVG2RsРgHE7׎kP]UơZF"[67HEʓiRGDiR 5Id4ul)+B#{͉ةa|2 pN!yNo0KX`]IQOb*iAU C~5G&߽\8Ms6ۭ&Z`[;4g5{?$cN7zhb~bncb7u 񑦵LyIMQ԰wBDZzE b.y]* 0,#bEJĮG WJ$j;{ML~G$啵g:J$i ĹstXPh:kEśv8xewl{l;Ht^JȮ1ҫPO&n lx(R@9رa>9 uX=ƭUJ:!Y&GMJ({ zvYgG.i"+_mev@vcymmYVILowkӗdȫ% 7_ / ט& dӬ҃꾀n7c^Gz33~xhMD=AYg#$+oU6Ud4uzu[4TZڬ|PWYY$?ջ$FŸ2XT )27/Vh aaяe!F0—GxPE)ɝJ ;!dF57}5WҏDEfGpRi Üb€7\2\ZZe;]'-8\e2Iz9NfGz/L{2Et!NߘI:oKL3eD$.[|smn V:)v~E< Q֞=6H\|״x]4:8^`ch,G3%\4 II#oc\֘OOtjj?~OwZϯ5۱AiC#,%l5/d&&CWkRI3 '}m{oѳ7S4<_s WvBʴ?yڿXc6D^3zshaW-!`~hMwΕ-쇷hvtG%?ʻ1o'&XPo>74juCVU__8=kMU_􏲊R5ͻ}+'8i F <ݳk""BQ\e`*lh=h` ;[s`s&,iJ跸t璷e'GY,18֘ >8z$`ҹ/j s3\FC'9 8A#$3y_>`m&Ϫֶb&foeި0gy 4r&]57UZG; .{مwUXY *n5zy(H" ]d+]_Ci=]$9rCQu$bsKEuNf޹~O?ec9ЛtO&m<`t_-{/y OETOIA zA혧|f#D(]hc&zp/}^b{ s\C_sAMfŗdJgioZ+Cj 3ZAr*8]-A$_}ez)_/Bt"Evlħ=Ch';󷅼hW쯛q)?˫y}L; X7zuE]oZ*a>Rl$Y>KŖ^pvc}h.G1Qs1K<Kn` |ٸD<"6'P50So+Y~bci95_#v`sX`.Ȫk&|mx4X']&uTsx1"]o's C_yӒL\QߎQq_7 F͒ AHn)Vwe <r3vʏ!@y6tXXQ1N`4fC1enm`'[T OC Phš(ٗW##WA {> 3(˲EzӪ}WIM?Hnb' !p9yݍ⾧zQWپPHS& |$EۗVB87}Z;/QMs@c3҈髋nk0UlVV6#۞ƚz;^%ie>揅GMyo5 hc̺k: /2796 ZSkLcia+g>^8=;m3!O)i=5e.8 udn}y.'e7ڠLF] p+h 5Lcȝb өRI!:Ib[zyUJrﯚ&C4{y-M1qMlF3hDz8ٖs p l~pf)ϑgN;9-jc&9L08ۃ ^h-ka?}YC>@QNuCӱE액1r@EuZ85ڬz.`VmVv1񘋺h0z3`suZ!\y$+:g=һ[4ޙu^Az:tCݾr+1YzпWLDvo RjHr UAa[ æ\gbm*d&4`:n'Vi<.2BD3h1Z6>I5lhYЛs(=rܫe33A悅k۲–z*\V7Ul 5'0C]2qv nd_q-C Ov4F$ʼn_0u'n&A9 nvj .}$ {ЛMB1y &E!NuMMVTʙF ;x~+^ 80`CoNi^47q.0\9 Iz@\\eaWߵt 83:g6(;%6!-yBkpXH*Gސߠ"F2o>Gm'zݓRy4 yd(綰ZUd4YE,]$3;$>k0:Y*cWA@q_`1wOxG˜O#Pa=1 \m#p͛-̝ᛁr٨qojp~ӖS~M]/f7'|"Xm 6~6$|9crK7UZK-Iaͬc);U!ԡ7MH7 YAz37vDMBoZ`CoFS ꔾ%[ U+J_޹4FfGf IeI׽zϢ=se^`P F~vOrU3;u+}~ߝ&~W;9Rݞz"_ύ/>;j4SJvC?gMvyrܨ鶚>psG0 ڜWݕfml{AVI7#7cGۃA}pͱhfncM> lo6czcs;>pLxn"H|6,Fܪi.3Fyn x;u3[j_#LM伾X̺'& _sF%FB3X3^N}D͘#L8A9VSG.x49}| 5Zw8:\Ӕnx6Jڭi|QC*=`T r]7ymz3ڡ7( Ku"|tT[/ xjHoXhT[!f!nH@ ^rw=j7; " tIPTuiIa>c'Lw[6ARU-ٛyCEnwP,jzJڛmsEVe& ;rj\3gGgA?r7uif WMfsFU_qFZ3:4T]_Qq[3[Ztc9u{ș5:=cfh,k&X@u{uVUmӢc0|w]8MD'"hiK {ҍٰIӦ)< RvhgMk9v́` V30䞰 fmh$, @٦7y qHoބdf4]NIg6f`K k> ̥3 \~)Ѵ^l-` ؑ뼄 \"hA,B6*)- nA&1A U\RExr)%K I𝩨S~4uVƕ ٛ2|Gِi .>g16uf Xt` HH7پ#}>qic.OuD6ty! f=?0PLTͩ, #ۡ3~+g.^EVt"aܺ1+A BvD7#5n-謤i%˫貾 Fc{~y9\>\>"ɁxVd2 >1Cϭix=1|uJ+gGg|xrZZ^\xVi4Wdi?w CHh& `psgǹpLJsF%.0llC!7ِKP ܐ>zqJHpBnP񗋡^u;S +7![e fPE`t^K_C:p/vߐ[ѫ:~EP 3m%TO{nENzS%镝LA"V/k=y.u5 ` I1خ%?9 QԚyV󉚥pmL\6̫M*aTs [1Z\vÃñ9SP`}FflҎBd'UOࣵ/ 1R;AuS+H``/{JU2 psaq:ׄDIVy0Z5͖@2Y~,*amʃD#%<,Žm+*% 3L(_`}낡(f3e8KQFhHPRAk P Q8bu@a\@mQ3ru /=RU8e{ak奤DVX>ij,lak/[ƭbއ%ILZA3tµ-C2a쬐ꄦB> ~rJi S7i +v/ßoT44$f3#;Ja4 2dK5,` ;Lfb1_Z0OJTQ>)9LC~i LB11|< Uؔ(" :D칄Cm[ =Ic˖P4#RC됫%]MdM#nцEt#idmB;<3R@}K{C[5@f"`tw:6u#(~ u,ۿccnl`onh:#;VLm7$29c(*;v?)X${;c0"ѝ*so,"bN 2}H_1'IОWϟ44V$Q[)%i+=,/K$R'O Fd ILqM{B:W6Z .'vyӆJԥ/l*J^-2Ο6Dk]z^]ʉ ߏڽ:SՍԪ~nWtF7Q&sW|Wpwm7SCop}3R9 pM,ax˰wؠj0uju^MUoI'= e SsLUrRnU_$?Y__@ E'MɧK[Vrmv~X&ӏjöT<Ф. xj10`k..1MdTbd5h8!m4pe婰as3R]5r+T]AiiZzfTFʰH Cƫ>BMܰ3W(se;f"Z(E@D׻0N7u{d@-= kCCnTT]ֳ}3rV7eZ*EֆTvy,jqϻ]l 2}b(~.&)BK0izIsP5DR1%?4=]oHȢŦ i-W8^.ԁ9NMwKQS  QgR3OPq,׽k] j1[97L-fy&^a|TQF8NAk<dT=5c= pf ejY,bxʐ=`z)3$(qOӶVuzfO '/_2QMglXQ{)69eil{xm3JfNEk)'6 >rv6O |SN犨(I5%k sA&/OhYoWB:=T-nZꭾRd7y ҏL\ki`» Х6bLYtgpqҏ{l3A٪ 3j?`#:lG7/=|x]`.>\|_ێ^Z~YulO1-f W9燫̬ǜ9̼2`m8L|T+mO\I&pצ\%ӨC?mϮFx9Au蔢CR`W*yL׼8!+m`iMELݪo(mUe Wz^*m?ffw6j(7LPύ }nTc,ъh* 4JH/g$~4? kL$j5=:F`֥W7Cf HĕAkJ_8y;'m65Ngżq94[)7}l`=H[1;QHbHjj%jN,jav^5fsnhkKS%ZBH-o^Q?[Wz˿i664Jr֩.famz#EQQd4 ޜ'`jO2"֖nFoRSh+\_י!f4>7]p P&/+I-WB۾C߬/iX٣4F+XcMoDFz&CFqф[f4gh0RT-r:Fhv7!͟ ١7hh|(?EyjЛ:'9XFoNFЛ|r4ÈfI^]' Fxp_7.^{:U1"ڏl*CG27Fvw-< {9/"WrE}ĨccS޷ћŜwŘO -ŰCq'b E 7BEWjq xT%epoi6-КJA9rE]nfG6pA]%fS6M$\gԅeOܶF|:qkR:z>H(hQXUo9v2zX,.u{tlZ75F:δ$69IzPxY.5zSc420.қA'z 6 7gQr<#y 6omzGQp뜧a4w6"ʤdى;g _ o\5g4z&\A ίO߰uTY{k{nh C $y7t+BoR` ^\s /焖V|\ɴi,87W?ӛ FfP@ǜ%$G+eM9ɷMh2%2MH|?UdGraqWf'#z62yvŝcHż>uIb٬INU=^z+~O,7{k]x8N$( K53kUXuWG7\ۙ8kqƼGgJOC1cTA2q" @*htu5tGMoFMxf&7lI4MNWQz=Y֕hh;bŠ'zϪ5q 1Qab]b)'қoDsT4 y[TZE B;i%\JoJϨ >O ~Oz5`^Pg*u^u$)E"1,&13f ϲJ FP6 ?qdiTlҤKw2}fϩ\ћ<Ģs߁5q*X4${~Ko`3zSc4hcZ0 ?t8?\g5zseiMg;j7ۀ ,5v>\]47 12̐Ǵ_{ eIPk?kIg)~e{# ;9 &CزO緝i ' cu͘Q-}$Uʥ~i)y+7C.]FF_CrkwX%/=U|yEelmբia>~f.e@Z0}mkl4^ ϳ@M/bf/8dcu{YYIh˫]>B3:eFjD9r83ѽ>>oQFUz9\Z5z*Ju" ^&p t4s1;[ICi]cxڱ_G}.kRQ.D"dX<+h6;1xj2bԚpIsSM#N"HijD{'X+DO9^qglw|>^Yf2b<5F.7 r2A5vq+3?[1F3E|lfۿBi0͞^jʦ8 8x#y'o!qnRk@JS&{%8fkIJ &eiA:6Cn@rƶ~X]{P[~޻.{y6(}FTQ!30yfZg޹=7G7kφXγ5^3?V>o~N4(kX,N1%(rWgyHެ.ZJ$, sfnU?'`5_*튁a'ds]x6zV˶Kgk;u?pJ;Gp4L'{Y4U Mkve;P5%8lG`es&7a؏΅ {e|kŹİ ..| f |~G%&pMl4 j@g/y"H̚Dɕƥ-4Ꮝqp0Z_M(phRh[2(t'ij gcU$dnYnkX_]=2%E4k:{NId9 <% depend_on(File.expand_path('../dependencies/a.js', __FILE__)) %> <% depend_on(File.expand_path('../dependencies/b.js', __FILE__)) %> <% depend_on(File.expand_path('../dependencies/c.js', __FILE__)) %> sprockets-3.7.2/test/fixtures/asset/application.css000066400000000000000000000000101331222022000224760ustar00rootroot00000000000000#app {} sprockets-3.7.2/test/fixtures/asset/application.js000066400000000000000000000001551331222022000223340ustar00rootroot00000000000000// =require "project" // =require "users" document.on('dom:loaded', function() { $('search').focus(); }); sprockets-3.7.2/test/fixtures/asset/bar-utf8.css000066400000000000000000000000321331222022000216270ustar00rootroot00000000000000@charset "UTF-8"; .bar {} sprockets-3.7.2/test/fixtures/asset/blue.png000066400000000000000000000001251331222022000211250ustar00rootroot00000000000000PNG  IHDR(4PLTE;k| IDAT[c`b@OhIENDB`sprockets-3.7.2/test/fixtures/asset/charset.css000066400000000000000000000000521331222022000216320ustar00rootroot00000000000000//= require foo-utf8 //= require bar-utf8 sprockets-3.7.2/test/fixtures/asset/circle/000077500000000000000000000000001331222022000207335ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/circle/a.js000066400000000000000000000000341331222022000215060ustar00rootroot00000000000000//= require circle/b var A; sprockets-3.7.2/test/fixtures/asset/circle/b.js000066400000000000000000000000341331222022000215070ustar00rootroot00000000000000//= require circle/c var B; sprockets-3.7.2/test/fixtures/asset/circle/c.js000066400000000000000000000000341331222022000215100ustar00rootroot00000000000000//= require circle/a var C; sprockets-3.7.2/test/fixtures/asset/default_mime_type.js000066400000000000000000000000271331222022000235230ustar00rootroot00000000000000// =require "noformat" sprockets-3.7.2/test/fixtures/asset/dependencies/000077500000000000000000000000001331222022000221205ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/dependencies/a.js000066400000000000000000000000141331222022000226710ustar00rootroot00000000000000var A = {}; sprockets-3.7.2/test/fixtures/asset/dependencies/b.js000066400000000000000000000000141331222022000226720ustar00rootroot00000000000000var B = {}; sprockets-3.7.2/test/fixtures/asset/dependencies/c.js000066400000000000000000000000141331222022000226730ustar00rootroot00000000000000var C = {}; sprockets-3.7.2/test/fixtures/asset/dependency_paths.js.erb000066400000000000000000000001571331222022000241170ustar00rootroot00000000000000<% depend_on('dependencies/a.js') %> <% depend_on('dependencies/b.js') %> <% depend_on('dependencies/c.js') %> sprockets-3.7.2/test/fixtures/asset/filename.js.erb000066400000000000000000000000421331222022000223530ustar00rootroot00000000000000var filename = "<%= __FILE__ %>"; sprockets-3.7.2/test/fixtures/asset/foo-utf8.css000066400000000000000000000000321331222022000216460ustar00rootroot00000000000000@charset "UTF-8"; .foo {} sprockets-3.7.2/test/fixtures/asset/jquery.tmpl.min.js000066400000000000000000000000141331222022000230770ustar00rootroot00000000000000var jQuery; sprockets-3.7.2/test/fixtures/asset/link/000077500000000000000000000000001331222022000204275ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/link/all/000077500000000000000000000000001331222022000211775ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/link/all/README.md000066400000000000000000000000071331222022000224530ustar00rootroot00000000000000# Tree sprockets-3.7.2/test/fixtures/asset/link/all/b.css000066400000000000000000000000401331222022000221240ustar00rootroot00000000000000/* b.css */ b { display: none } sprockets-3.7.2/test/fixtures/asset/link/all/b.js.erb000066400000000000000000000000201331222022000225150ustar00rootroot00000000000000ok("b.js.erb"); sprockets-3.7.2/test/fixtures/asset/link/all/b/000077500000000000000000000000001331222022000214205ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/link/all/b/c.js000066400000000000000000000000161331222022000221750ustar00rootroot00000000000000ok("b/c.js"); sprockets-3.7.2/test/fixtures/asset/link/all/b/c/000077500000000000000000000000001331222022000216425ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/link/all/b/c/d.js000066400000000000000000000000361331222022000224220ustar00rootroot00000000000000//= link ../c ok("b/c/d.js"); sprockets-3.7.2/test/fixtures/asset/link/all/b/c/e.js000066400000000000000000000000201331222022000224140ustar00rootroot00000000000000ok("b/c/e.js"); sprockets-3.7.2/test/fixtures/asset/link/all/d/000077500000000000000000000000001331222022000214225ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/link/all/d/c.js.coffee000066400000000000000000000000231331222022000234230ustar00rootroot00000000000000ok "d/c.js.coffee" sprockets-3.7.2/test/fixtures/asset/link/all/d/e.js000066400000000000000000000000161331222022000222010ustar00rootroot00000000000000ok("d/e.js"); sprockets-3.7.2/test/fixtures/asset/link/all_with_require.js000066400000000000000000000002641331222022000243260ustar00rootroot00000000000000//= link ./all/README.md //= link ./all/b.css //= link ./all/b.js //= link ./all/b/c.js //= link ./all/b/c/d.js //= link ./all/b/c/e.js //= link ./all/d/c.js //= link ./all/d/e.js sprockets-3.7.2/test/fixtures/asset/link/all_with_require_directory.js000066400000000000000000000000311331222022000264020ustar00rootroot00000000000000//= link_directory ./all sprockets-3.7.2/test/fixtures/asset/link/all_with_require_directory_as_js.js000066400000000000000000000000601331222022000275630ustar00rootroot00000000000000//= link_directory ./all application/javascript sprockets-3.7.2/test/fixtures/asset/link/all_with_require_tree.js000066400000000000000000000000241331222022000253370ustar00rootroot00000000000000//= link_tree ./all sprockets-3.7.2/test/fixtures/asset/link/alpha/000077500000000000000000000000001331222022000215145ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/link/alpha/a.js000066400000000000000000000000241331222022000222660ustar00rootroot00000000000000//= link ./b var a; sprockets-3.7.2/test/fixtures/asset/link/alpha/b.js000066400000000000000000000000241331222022000222670ustar00rootroot00000000000000//= link ./c var b; sprockets-3.7.2/test/fixtures/asset/link/alpha/c.js000066400000000000000000000000071331222022000222710ustar00rootroot00000000000000var c; sprockets-3.7.2/test/fixtures/asset/link/asset_uri.css.erb000066400000000000000000000001621331222022000237050ustar00rootroot00000000000000<% uri = resolve("POW.png", :compat => false) %> .logo { background: url(<%= link_asset(uri).digest_path %>); } sprockets-3.7.2/test/fixtures/asset/link/directory/000077500000000000000000000000001331222022000224335ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/link/directory/application.js000066400000000000000000000000361331222022000252730ustar00rootroot00000000000000//= link_directory . var App; sprockets-3.7.2/test/fixtures/asset/link/directory/bar.js000066400000000000000000000000111331222022000235250ustar00rootroot00000000000000var Bar; sprockets-3.7.2/test/fixtures/asset/link/directory/foo.js000066400000000000000000000000111331222022000235440ustar00rootroot00000000000000var Foo; sprockets-3.7.2/test/fixtures/asset/link/require_tree_alpha.js000066400000000000000000000000261331222022000246230ustar00rootroot00000000000000//= link_tree ./alpha sprockets-3.7.2/test/fixtures/asset/link/require_tree_alpha_as_js.js000066400000000000000000000000311331222022000257760ustar00rootroot00000000000000//= link_tree ./alpha js sprockets-3.7.2/test/fixtures/asset/link/tree/000077500000000000000000000000001331222022000213665ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/link/tree/application.js000066400000000000000000000000311331222022000242210ustar00rootroot00000000000000//= link_tree . var App; sprockets-3.7.2/test/fixtures/asset/link/tree/bar.js000066400000000000000000000000111331222022000224600ustar00rootroot00000000000000var Bar; sprockets-3.7.2/test/fixtures/asset/link/tree/foo.js000066400000000000000000000000111331222022000224770ustar00rootroot00000000000000var Foo; sprockets-3.7.2/test/fixtures/asset/link/with_logical_path/000077500000000000000000000000001331222022000241105ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/link/with_logical_path/a/000077500000000000000000000000001331222022000243305ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/link/with_logical_path/a/a.js000066400000000000000000000000041331222022000251000ustar00rootroot00000000000000a() sprockets-3.7.2/test/fixtures/asset/link/with_logical_path/require_tree_with_logical_path.js000066400000000000000000000000201331222022000326720ustar00rootroot00000000000000//= link_tree a sprockets-3.7.2/test/fixtures/asset/link/with_logical_path/require_tree_with_nonexistent_path.js000066400000000000000000000000301331222022000336370ustar00rootroot00000000000000//= link_tree ./missing sprockets-3.7.2/test/fixtures/asset/link/without_argument/000077500000000000000000000000001331222022000240345ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/link/without_argument/a.js000066400000000000000000000000051331222022000246050ustar00rootroot00000000000000a(); sprockets-3.7.2/test/fixtures/asset/link/without_argument/b.js000066400000000000000000000000051331222022000246060ustar00rootroot00000000000000b(); sprockets-3.7.2/test/fixtures/asset/link/without_argument/require_tree_without_argument.js000066400000000000000000000000161331222022000325470ustar00rootroot00000000000000//= link_tree sprockets-3.7.2/test/fixtures/asset/log.txt000066400000000000000000000000061331222022000210100ustar00rootroot00000000000000Hello sprockets-3.7.2/test/fixtures/asset/mismatch.js000066400000000000000000000000321331222022000216300ustar00rootroot00000000000000// =require "project.css" sprockets-3.7.2/test/fixtures/asset/multiple.js000066400000000000000000000000571331222022000216650ustar00rootroot00000000000000// =require "project" // =require "project.js" sprockets-3.7.2/test/fixtures/asset/multipleengine.js000066400000000000000000000000331331222022000230450ustar00rootroot00000000000000// =require "users.js.erb" sprockets-3.7.2/test/fixtures/asset/noengine.js000066400000000000000000000000271331222022000216310ustar00rootroot00000000000000// =require "users.js" sprockets-3.7.2/test/fixtures/asset/noformat.coffee000066400000000000000000000000171331222022000224660ustar00rootroot00000000000000"CoffeeScript" sprockets-3.7.2/test/fixtures/asset/one.css000066400000000000000000000000101331222022000207540ustar00rootroot00000000000000.one {} sprockets-3.7.2/test/fixtures/asset/oneengine.js000066400000000000000000000000331331222022000217730ustar00rootroot00000000000000// =require "users.js.erb" sprockets-3.7.2/test/fixtures/asset/project.css000066400000000000000000000000141331222022000216450ustar00rootroot00000000000000.project {} sprockets-3.7.2/test/fixtures/asset/project.js.erb000066400000000000000000000000551331222022000222450ustar00rootroot00000000000000var Project = { find: function(id) { } };sprockets-3.7.2/test/fixtures/asset/relative/000077500000000000000000000000001331222022000213055ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/relative/require.js000066400000000000000000000000271331222022000233160ustar00rootroot00000000000000//= require ../project sprockets-3.7.2/test/fixtures/asset/relative/require_other_load_path.js000066400000000000000000000000421331222022000265270ustar00rootroot00000000000000//= require ../../default/gallery sprockets-3.7.2/test/fixtures/asset/relative/require_outside_path.js000066400000000000000000000000421331222022000260630ustar00rootroot00000000000000//= require ../../default/gallery sprockets-3.7.2/test/fixtures/asset/require_manifest.js.erb000066400000000000000000000005161331222022000241430ustar00rootroot00000000000000<% link_asset "application.js" %> <% link_asset "application.css" %> <% link_asset "POW.png" %> define("application.js", <%= environment["application.js"].digest_path.inspect %>) define("application.css", <%= environment["application.css"].digest_path.inspect %>) define("POW.png", <%= environment["POW.png"].digest_path.inspect %>) sprockets-3.7.2/test/fixtures/asset/require_manifest2.js.erb000066400000000000000000000004601331222022000242230ustar00rootroot00000000000000//= link application.js //= link application.css //= link POW.png define("application.js", <%= environment["application.js"].digest_path.inspect %>) define("application.css", <%= environment["application.css"].digest_path.inspect %>) define("POW.png", <%= environment["POW.png"].digest_path.inspect %>) sprockets-3.7.2/test/fixtures/asset/require_self.css000066400000000000000000000001141331222022000226650ustar00rootroot00000000000000/* *= require tree/all/b *= require_self *= require project */ body {} sprockets-3.7.2/test/fixtures/asset/require_self_twice.css000066400000000000000000000001351331222022000240630ustar00rootroot00000000000000/* *= require tree/all/b *= require_self *= require project *= require_self */ body {} sprockets-3.7.2/test/fixtures/asset/required_assets.js000066400000000000000000000001211331222022000232240ustar00rootroot00000000000000//= require dependencies/a //= require dependencies/b //= require dependencies/c sprockets-3.7.2/test/fixtures/asset/semicolons/000077500000000000000000000000001331222022000216455ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/semicolons/bar.js000066400000000000000000000000101331222022000227360ustar00rootroot00000000000000var Bar sprockets-3.7.2/test/fixtures/asset/semicolons/index.js000066400000000000000000000000561331222022000233130ustar00rootroot00000000000000//= require ./bar (function() { var Foo }) sprockets-3.7.2/test/fixtures/asset/sprite.css.erb000066400000000000000000000003631331222022000222630ustar00rootroot00000000000000/* *= depend_on "POW.png" */ <% require 'base64' path = File.expand_path("../POW.png", __FILE__) data = Base64.encode64(File.open(path, "rb") { |f| f.read }) %> .pow { background: url(data:image/png;base64,<%= data %>) no-repeat; } sprockets-3.7.2/test/fixtures/asset/stub/000077500000000000000000000000001331222022000204475ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/stub/application.js000066400000000000000000000000751331222022000233120ustar00rootroot00000000000000//= require ./jquery //= require ./foo //= stub ./frameworks sprockets-3.7.2/test/fixtures/asset/stub/foo.js000066400000000000000000000000161331222022000215650ustar00rootroot00000000000000var Foo = {}; sprockets-3.7.2/test/fixtures/asset/stub/frameworks.js000066400000000000000000000000551331222022000231650ustar00rootroot00000000000000//= require ./jquery //= require ./jquery-ui sprockets-3.7.2/test/fixtures/asset/stub/jquery-ui.js000066400000000000000000000000511331222022000227330ustar00rootroot00000000000000//= require ./jquery var jQuery.UI = {}; sprockets-3.7.2/test/fixtures/asset/stub/jquery.js000066400000000000000000000000211331222022000223150ustar00rootroot00000000000000var jQuery = {}; sprockets-3.7.2/test/fixtures/asset/stub/skip_jquery.js000066400000000000000000000000521331222022000233470ustar00rootroot00000000000000//= require ./jquery-ui //= stub ./jquery sprockets-3.7.2/test/fixtures/asset/tree/000077500000000000000000000000001331222022000204315ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/tree/all/000077500000000000000000000000001331222022000212015ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/tree/all/README.md000066400000000000000000000000071331222022000224550ustar00rootroot00000000000000# Tree sprockets-3.7.2/test/fixtures/asset/tree/all/b.css000066400000000000000000000000401331222022000221260ustar00rootroot00000000000000/* b.css */ b { display: none } sprockets-3.7.2/test/fixtures/asset/tree/all/b.js.erb000066400000000000000000000000201331222022000225170ustar00rootroot00000000000000ok("b.js.erb"); sprockets-3.7.2/test/fixtures/asset/tree/all/b/000077500000000000000000000000001331222022000214225ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/tree/all/b/c.js000066400000000000000000000000161331222022000221770ustar00rootroot00000000000000ok("b/c.js"); sprockets-3.7.2/test/fixtures/asset/tree/all/b/c/000077500000000000000000000000001331222022000216445ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/tree/all/b/c/d.js000066400000000000000000000000411331222022000224200ustar00rootroot00000000000000// =require ../c ok("b/c/d.js"); sprockets-3.7.2/test/fixtures/asset/tree/all/b/c/e.js000066400000000000000000000000201331222022000224160ustar00rootroot00000000000000ok("b/c/e.js"); sprockets-3.7.2/test/fixtures/asset/tree/all/d/000077500000000000000000000000001331222022000214245ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/tree/all/d/c.js.coffee000066400000000000000000000000231331222022000234250ustar00rootroot00000000000000ok "d/c.js.coffee" sprockets-3.7.2/test/fixtures/asset/tree/all/d/e.js000066400000000000000000000000161331222022000222030ustar00rootroot00000000000000ok("d/e.js"); sprockets-3.7.2/test/fixtures/asset/tree/all_with_require.js000066400000000000000000000002071331222022000243250ustar00rootroot00000000000000// =require ./all/b // =require ./all/b/c // =require ./all/b/c/d // =require ./all/b/c/e // =require ./all/d/c // =require ./all/d/e sprockets-3.7.2/test/fixtures/asset/tree/all_with_require_directory.js000066400000000000000000000000341331222022000264070ustar00rootroot00000000000000// =require_directory ./all sprockets-3.7.2/test/fixtures/asset/tree/all_with_require_tree.js000066400000000000000000000000301331222022000253360ustar00rootroot00000000000000// =require_tree ./all sprockets-3.7.2/test/fixtures/asset/tree/alpha/000077500000000000000000000000001331222022000215165ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/tree/alpha/a.js000066400000000000000000000000301331222022000222650ustar00rootroot00000000000000//= require ./b var a; sprockets-3.7.2/test/fixtures/asset/tree/alpha/b.js000066400000000000000000000000271331222022000222740ustar00rootroot00000000000000//= require ./c var b; sprockets-3.7.2/test/fixtures/asset/tree/alpha/c.js000066400000000000000000000000071331222022000222730ustar00rootroot00000000000000var c; sprockets-3.7.2/test/fixtures/asset/tree/directory/000077500000000000000000000000001331222022000224355ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/tree/directory/application.js000066400000000000000000000000411331222022000252710ustar00rootroot00000000000000//= require_directory . var App; sprockets-3.7.2/test/fixtures/asset/tree/directory/bar.js000066400000000000000000000000111331222022000235270ustar00rootroot00000000000000var Bar; sprockets-3.7.2/test/fixtures/asset/tree/directory/foo.js000066400000000000000000000000111331222022000235460ustar00rootroot00000000000000var Foo; sprockets-3.7.2/test/fixtures/asset/tree/require_tree_alpha.js000066400000000000000000000000311331222022000246210ustar00rootroot00000000000000//= require_tree ./alpha sprockets-3.7.2/test/fixtures/asset/tree/tree/000077500000000000000000000000001331222022000213705ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/tree/tree/application.js000066400000000000000000000000341331222022000242260ustar00rootroot00000000000000//= require_tree . var App; sprockets-3.7.2/test/fixtures/asset/tree/tree/bar.js000066400000000000000000000000111331222022000224620ustar00rootroot00000000000000var Bar; sprockets-3.7.2/test/fixtures/asset/tree/tree/foo.js000066400000000000000000000000111331222022000225010ustar00rootroot00000000000000var Foo; sprockets-3.7.2/test/fixtures/asset/tree/with_logical_path/000077500000000000000000000000001331222022000241125ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/tree/with_logical_path/a/000077500000000000000000000000001331222022000243325ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/tree/with_logical_path/a/a.js000066400000000000000000000000041331222022000251020ustar00rootroot00000000000000a() sprockets-3.7.2/test/fixtures/asset/tree/with_logical_path/require_tree_with_logical_path.js000066400000000000000000000000231331222022000326770ustar00rootroot00000000000000// =require_tree a sprockets-3.7.2/test/fixtures/asset/tree/with_logical_path/require_tree_with_nonexistent_path.js000066400000000000000000000000331331222022000336440ustar00rootroot00000000000000//= require_tree ./missing sprockets-3.7.2/test/fixtures/asset/tree/without_argument/000077500000000000000000000000001331222022000240365ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/asset/tree/without_argument/a.js000066400000000000000000000000051331222022000246070ustar00rootroot00000000000000a(); sprockets-3.7.2/test/fixtures/asset/tree/without_argument/b.js000066400000000000000000000000051331222022000246100ustar00rootroot00000000000000b(); sprockets-3.7.2/test/fixtures/asset/tree/without_argument/require_tree_without_argument.js000066400000000000000000000000211331222022000325450ustar00rootroot00000000000000// =require_tree sprockets-3.7.2/test/fixtures/asset/two.css000066400000000000000000000000101331222022000210040ustar00rootroot00000000000000.two {} sprockets-3.7.2/test/fixtures/asset/unicode.js000066400000000000000000000000101331222022000214450ustar00rootroot00000000000000"☃"; sprockets-3.7.2/test/fixtures/asset/unknown_directives.js000066400000000000000000000001271331222022000237500ustar00rootroot00000000000000//= require project // // = Foo // // == Examples // // Foo.bar() // => "baz" var Foo; sprockets-3.7.2/test/fixtures/asset/unknownexts.min.js000066400000000000000000000000711331222022000232130ustar00rootroot00000000000000// =require "users.js.erb" // =require "jquery.tmpl.min" sprockets-3.7.2/test/fixtures/asset/users.js.erb000066400000000000000000000000541331222022000217370ustar00rootroot00000000000000var Users = { find: function(id) { } }; sprockets-3.7.2/test/fixtures/compass/000077500000000000000000000000001331222022000200205ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/compass/_compass.scss000066400000000000000000000000301331222022000225120ustar00rootroot00000000000000@import "compass/css3"; sprockets-3.7.2/test/fixtures/compass/compass/000077500000000000000000000000001331222022000214655ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/compass/compass/css3.scss000066400000000000000000000002231331222022000232320ustar00rootroot00000000000000@mixin box-sizing($bs) { $bs: unquote($bs); @include experimental(box-sizing, $bs, -moz, -webkit, not -o, -ms, not -khtml, official ); } sprockets-3.7.2/test/fixtures/compass/foo.css000066400000000000000000000000001331222022000213030ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/compass/foo.js000066400000000000000000000000001331222022000211270ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/compass/foo.mov000066400000000000000000000000001331222022000213140ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/compass/foo.mp3000066400000000000000000000000001331222022000212120ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/compass/foo.svg000066400000000000000000000000001331222022000213120ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/compass/foo.woff000066400000000000000000000000001331222022000214540ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/context/000077500000000000000000000000001331222022000200375ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/context/POW.png000066400000000000000000001236451331222022000212250ustar00rootroot00000000000000PNG  IHDR,K9tEXtSoftwareAdobe ImageReadyqe<fiTXtXML:com.adobe.xmp pmPLTEjjjlll ޼pppzzy}}}uuuܹddcى􁁁+++[[[SSSKKKBBB333<<<$$$rrr뤤렠nnnԘ ǀ||{xxwppnnnl___rrptttlljggfOOOWWWHHG777///(((g-IIDATx콋[X>@IQ0Y5QT6rDDZѢ>ޟyj=_>vi:3׬^{kmuM/#_/Rͯj~巖_oef~=jK7#(sK7՜EEEMj" K'DUEZTt$A<'j4:pɊ(x~G~ 3y;m :~W\RA7t{ ÐYT0*zV aTiNFw wHoF%ڭ.u^P]P3ڳa TA7Tc5#"x&ͿپKLST>² T=T,ҽ*i hF&>ͯl$+2'_k¦Pdx&)e ,5Z-20$uQ8,!L|tg+~U#0_A{IDނdl]uvFk2߽?(jʜzT_nײمE'uK5烘L&߷eK?FBO"fW0[[Cd .X4 bɐKG-!c3'dN>׫bMS,1י7^:)aYSPS}TC^Qc*tuZyrA e{xEm2„#F.0Sa穊ȵ]5! hॲxej2,i"V{xj&Y^ga@pUm , b,f٣op'p7:_k(xnk|X"0e>Jj9+30ґ׾^f.=s[YsIT{><1Xͨt6ܻ}:'.&Go:fSci80b/( |`Օᘷ!V$U^i>3vڕw&߶gbkS9#OU | jՠSuz66hß6_w) W媩HZDX0$IUv2 GdC'=6F9Fe zxpVbLJ Q8um>8pvNk؂-skͪ돈,"oƘ Jeq|d߲ {F9Z{T=Ea] ' UiNM.O_xY*6C(ӄj"~b>UᙵTUc0=! 2\or>geP*(ź (kk)7)(`6:cWodqb7'ۦEmܝP/d/V͖@qoC;W 2T,Trļ ZK=A ?b|=Lfnb č|x!ف|ܰ ߣ!)·l^'Cn_7 Ѓ ? s?[C@^V:®nX\f؆;>(}U $o|-Fz#FpGی4›։BS[og!؆86?|H9w z5&MxVU`G8$]sUЄЯv[ HG{1;WdR`j"WR8,坦@oz8s x@RT,ZX)˲^BQESTb86|'hM?OmcWOsUѝkwlogq` %8!DQ*# C @0!R V T0 ژ @w}3];\\arsUӬB;{pNp`G]o)1w my[~{=ҹ`Bܶ=C|sw:蝋udٺڝRtYˮ݅iZnơ-by̐Vhz0vfp}uU="WY߀ޒij2uגiWX'C zk孾>oy;O/3@;.ț o7t$ CZRS'\@|3+y瀧gTO>vZ~Z}Li/23 "E4›G o: ?0K`oHc*k鱚r,=Bi*6R+9 D\*$eD1W]m঻XbY t|OyG/Vv u|%3<e![7/Lu sA8bne6Ab0ͲaD4gYjy xsȲ3U?2۟p@B/a"ץj v̈́Pg># :g7г<9&B[LO ?t>;zwEH& ӑ-3]# |D `HT$]Hj 'fQ8m [mli9}+t݉kJ' Y[>gl"q o/fX' (vmض6;ml~ۮS*sk<#X$MBL xEXm'wQTښ1{.#shl9:B7*cӴ{v-g̟Lx-m@hۀ́0aŸ1έ-tfvvFIF8i6Ge4^X3:kb51?Y5do5HU3<3 V3ƖE1`t<'@ Ba|0S&$Vba0=.]>/\tu)V\OKׅF%ݛ|pmaR4V]Iš!Mŋ T=MbqLlwŰpfQgcv&ۼ!&0%¥e4${ՠE W.i[Dhg!1G;Jw ^%El ,oj(&*Ĺ!imwv47 f›%:z6%`;6yJۯޯ>`uW%tPhLFph<^|FIpDROUTtI\/Q h٤TOhb=nZ6aؑ f`*Ithq:Fs~$D[~{e$J&OwW*og:)6pחs}(_XGܗD0qosڶP9%w_ vsN8gݞ[ߒ϶F]3K}3s 1ITVWDPq syݞz ۠pن@zpǁl$p;뺳U[;|Slr%ݼuIp`MF8 @xFh\O`Tmr_=t/[ {D`{FzJ}cʯ%gV_[a:Ge߀LoVWQ`0Iϱ~/T6zI@ 89acGwwΤgEz=p̾A}P?2Xz6k'Fvj|8*sO}%xKa mD>*2l8nx|h[zȷ{x픧fY~m^ϱ{;A(=p x6Z@ۡB-<*h=SU HST9{l\*PEƯo1n/cE0Ÿ"r~]Ax;vmB[+x!xt7k{Å¥m`!W(E(vglmwbvuwk i8?o?`jA'1"v77]_?{7CH |v ZUfܹ϶yOϗ! *qhg4mWw[/8Ȅʇa }ݴai/H,xnXf_ٸ %Ɩ-loApwvmK=[?g "" Lr[REҨ2u=^FVxde]4B9hG!77}G ]uv*kM|(Y^Eވ*MFnr06i#b@o,g=sø{/ 7~ܠAck6ModHAD$U:4MߊĞU, 0\P9u ťer0x̲, ozXvZ#n?._6aX>ZN/Ev?HWi?$;75uxvvX6Cc=pv{)ve=se}=hTE7RUHD:6Cu_CJ!w5zRgx&=cA=!7}~|uٳ~R!UE$֢6&]f `ai:֜_I߇mvέpMD3[Eo)Daw`400[N7B]U8a ^0,D57j l~[Yݮr|9!Bs&3cL@n6VAehnBRa4xk<ڙ@HϻԄ i#?Qiz q{<Ʊ~a^F aBE'{U&ZjֹBƘ"8xj of@=nu'̄tIUb+oSOQqYlb:J8}!h)"HkDCJv0Z%a/U @5ׄ7yu~ o^vK$qQ􄢉 TCMXVz  M(dR7Gq)kTf-fvJcR= ]mv?b)agb8c@'ԊM9Eoe:-g˾A7O|ecvq`*]3OnSWܰ\G! >mGbw(=lF흧۴-z꽟{Q(e%,Ih-*Q XO#93䂌"t56 _x@`!|vx|w'omm葥jIxqZdQsxd4M x=;WڼL܆D/ƳмwIfUx ekHxyfT6AO~'b!ȫۄ2,@+2zь͞A/M(F&|W?hosaQaMx3f H}NMgs@x3eDxs1]z 9<({,}Y {WE-0Ҹ;m#a R; ͆Fгio66m4/-[ 0MaO $aj:0Ȱ GS\pT5j -J [\'+1&6(P?{]qZ .tUE͌zL*ãSa[_}}FrVQ@ v (l&2H6&4 Ꮻ<'U y6Z 1m숻SĒIMKd):j+$!K0hƅyޜ B(VnNQ8Q5NSJ7ϞĪ0^"jQ T&J*@Hsf$NLȏ7Kd #'.jRĒ7L,eMx3H73Ɛ>ah 3(wT^ &h:$ Ah" g 8(j и o~@*g KuRb/?M8 b,2x( `U3!ܟ9|7K@wY3)9 gMTj x YuGPc#RZMVPh(&4ȿ,h//7D>߼@on7m`n1lm]gtN;ڌĶ{s4:r>M`ݦn8BBX;]kz 9YՑsƉ4i@fD/qB#D ?A5q~2J?hC֗Oӊpqt-a; ,4ÒA r 4f|hװN:@͜CxOo3]%FO O5FǛ+s3W"5f/B=l4sUtИ;A/0HO AhB[p4AEgeD;sP97Tn#(+oTx JS'qHvGص(?6iP]KQg8cJ+1jb[5N"eCpҕu*x,UT?JMvov}!zP}*v(|Ç+34`8##=bU0Ûb^5/&T2XV 8LQ QA8µ}x60Xm|?en% Wr5$Ti\?(9~P5tRp(s|}#)pBh8Ni;onhV._.`jpƘzӤ8lll.TΓǏyoL%dj, EB`iEx8}7(ik|ѵh{ݶ#~&㏲naOS}={y6xK"xEZTi>[&3&X*G wtf9 _$fF1h07!;u u2A|WSjo n›{%JIX/oKƽ-] ؍;[ێBg4Bn `;:[VVϷ熆:SSD-9lxi6Bf)ā=#@،1DY#Gs尭=ok裂$pXRWNM ѳ]{sp>%aN%P!FہM Y ۴9s~ar RR$P'+Ffmޠ;5Y t k;Zp₩!2(,@PT]W^2gVA@V-p"D'R۔ȑzi"T3/D^K"StWE"|A r㷓|nR VQ$o9;23C2;TRfd)!qn J&&Ʒx Paq.K3)/[o`[xYSq\U QV#4qԿ$Cs,~&|J£OKQS/.``)jf¹; xXYֻFQ!E1Yj#&eadȔȧɬxv潭-˂9߯z'p!J*9 v\ʶ.t9#6EJq{uGclИL4|.ʽu(L%;"Ř ,p:رjr2]KTqhs"3WpzLL? !pQhogXԩ#_#зP.OωT֪|O#ޜJ}zcOyj8׍}T{uA%xXj1t za|yIAl8'AY+Dt֞_|NRzbU%Y/Sk5»~MbkTx7ڞijqD,KT'amk%9b8Mn}Ѱ146gr@9YfagނR_Aߢ48amL$|}Xu8m,<.negfAp(rKدՉ'2s3@ުˁ̂HvԁU v4[XEGdIR9}P{ ö}k)u۳agล=q'i-Mz.ސD5#!iಆ/2(3uB՜M .OosOw!:os|xo#B =q~Xc/ DHN??Gk"f %#kWx#+)=kyWRmF3#X'mܺl76Aw]S*fl@Q 9.1ubHj%8dNgsniw+?i$~{KPEzM/tpN׌9CcNOw/'{gݲSIH\jyDg!z=dLco}˅8X*׈h8>CzLZLQ1ɝhLoooI o4XWVsJb\ 6\o)|}j%<?y1ȸ_37/P=IsߝBlԂqp櫟GTlvg]ࠫ~0_Ϳԫv#DDF /+NbŊ 'M[ŕ L5H~_Eu}9j$bv=e>琰i_cm@xs/#0ß7~3+Ҩds $qu=L\EՈ Z/ʅAwrϦ;Nm›#|}v.$T'-42oˏa\iLT=+2- Ͽ,,9S_}j`udRu}asw8ѴG2j96ڴhpCLvMfCU2KlNdj£R BX37Y?b›%_Є7@p}7]w7e<MU+ a4֪'~D&)C0k2!&n+sVZeտW^%skgoANM7MQN]cl>kqx4dj$gNQ1(ϾxIs`Mn9 xHC^cg-`›k;(OapcQ@f9h[B1]K.j_s kT=':Y]yhzXv2nFtcDy{d9%ivDǜt]tG^ޅF hxTExzY8?S  i>׏N46 z[T]@vlfBDE -jRЂ/@[WI,BKž8wh|\LwcSTu"u14bO47e23pcuA$5D2+otQ"X>T{Z](#y/dBw֊]N ]M`,u 6&___kaVLTLdq[u(X)εBNWߋR1ڗUd}B_Ӕ~N쾨+U!UUTؤͦJVFm8w` LΓ5+b9BtF곰ə'dq##UHldEL .KjV4V\Pȸ鮷@nQm5){8ji\\SULNg\~CI ;sNfO6|G̢-k#[Z|ypfT&SiG.2>9asI@I:ܐLfiEΕC0&fjQeE&wͺ ̩YbYwG NN1+{z q~ LYژj_|i vU3KXHt'%TL;;26#2",WXA@bN 9AXg*m3Tc\ O@yGvT˲XbaR#Z5xy kG̋_fʇ,]`/9o`ݓb'1kOca^>$n,ʻ䡈c^Y-ObV+J&z)y;`dOQ7y_CXVjYF*554QѸ-Vo^|5, rݤ5' nH.}C B !14Q k ;s̞Evp=\p@FyuZCR"kM{eKd7]m)&^dDF)*r˨/7F@dZ"S(hƠ ^c UwBzf=e: RcluZPrF,0"!?f[cK"C 15RGg 59xJ03` I_;"C a%v |Pg"Ef.vVly?ԓ`ޗ9J&W[HYDUƁL5{`gtYXxITcs6)ޤR3O=a4T6"fᡃVWOz#<*>0W:C"DQ8AMT׺Yod~;VfU.x}Yąz(.W4K?O59'4 :]88.9! 5ikx,RcK!!?bѓm، $_>\4`I]zk,>ۦpfV/+SR}WlB@g堏=ZtnjEY0Lw5nFkp Lg`!/"ZM5ē w }KaJ7Gotk2-޴s^|}l!j%^GԕG>X ,Y*24W_cOس).ezV ܼZ}S) q\-kl1|TUƞ]x\XUR0-rX S 岌'v;/ Ւ9Xa/ 6y(ijbu] T3٭C{Heq2)j'9i2 jH>xU -su&l cA+fdDhAI0 ly1iac`I=mgQh'ʭw"%.H:^.3n@P;zWͣɛH70w],۝^E<|sזᶨHsY1ų'hŗ?ϒU NPB->Ym A /7<5s:x5-[u Nxfg2l `{ęsނ 2S ,"' ,2w[u}=|o䬅f>"/Ջ3 [0r][OsUC '[ "+Dkŀ QL3|д¿Q"ZJaոY iÄjU[qX5vGFh82>dϋ+A}}ԻYrLG*|]8Gٕ +%O z!Hu_9t[d= T,hn?Iab_nɝ8>ZDNQ[1դ&u r'psW}%~}"z35:W1UCBE%y<3$mӤeXZ!džjBDMޒ ֑::xpSV,A('@N>iYLwdQT M>~]+aןV ?MIЄvwxk3ɲ H6hh C'vpbA<}U;B&^ہ~JJ:QMIG܊ ۞M?S3 S 9㑏et 9uI3hҟUM71 `y {mC70EMU)yȪyBOj߈$>0vsykHo<>7w`4m22UN4u߮Zs[:$< 7[Z膰W-82 !W,^I98WdCl>=º{v=o|C[.ྷ8}I9̈k4XdTSV[xT@\0jEaI,]`hq#w0E+}t AzpO^[:[FcDe:oQT#c! ӱX,QzPZxfmquv*Qoh$4"}}~Ot 9a:^$: X~ؾtLIVǔi: e,Z?_MtPDdg9FjtvZc?Jf qRoV'}l[gS2ͮө 'cidF$Tb^LYOgP_FHF5_;;~홗o|XS)x ߜ֍8>G~h g& ~)pRE蚠0;S 2D*YdD.y3_~Y|]?,\lg.fËo̖8Y 6PMCz*Z՛W/za Mdh̾k] 0hR.L۲Ju4<%Sy|R&kn=8^X ( jk;pk'rEV&ao87岄D l~InةgG!A e^:"W$5"N]w\3Ul\ĩZ`4uGl:_Q5 UPT6-2}>_tjA*Շ&'p{ RY,(|äCx!tfG-k5bO>bi~.(g$fFcki Ɂ$ Д̀2.XxzC͇|X!;4WBΐ1V.W/)b ]7hAkkxs'/2wlmxHyEfZi:W6=r:\b]}-p/K|PGt/x02 -k[TXlDM3fSA"@|``p(*zPIJm]})Y+vi{Szo9ѸFT9 䎅bec{Ƭ~M38]"*)ԵD0LrK( -G9_0͐_s&Q5fVc*\۾٠U*Uf䧻Yjl*fxjcWI5vr ,,z)-dz,'+Ps(mYd$6=Ȳ;,p/6$ZmԧT:/r wF7TMjDj/[L cuK+K2yx`@: ! <EL, yƲ8,zٛmAm++hOyX7 KEE]i̹*,ΰh;r<BÖAHwHqaUhK}_kvom ؠ+5,J"'_wm0&{猿93ڮ~ߪzުd@ I@}'ԇ %f,hiP'q&k䝋}41s6 /LyscV u73y4Dd<]ͪ^ut45_$ob^ lzQ@K/Dwj5||G˜Kh,Fa:%gJ-@Zn"ʻ4-]!x3гPrޢ߇Z)rHo{07w9[2oXWoYt?dBk^kl&Jy~ .~>+8e]q Q6>ۭwbYLfؗ\Q4ɕH61Mk7u9phsޡMUC5M#EB %Z+ĩ 3*l\pq8.&)TࡅC K#%"(lAQHrda6MisΆ- s_rㅸRJ,',_E34 \X'[4M}&o[^Z+ei& ×I? $WmͧtH9}1Qh72qK%=*9c[.P,O|\9 b!W MCI|TXګĿnd,XcF %<Θi⣏t@L 84+nhY*FS vw ؅Yo  ̳1SvXXӐ|n'lJ-~&nӳ)Xs z sU!'> 6ՂE#NW#v 6]q7M @SFIȕeگWCˍ&d4F3wi&wXn| /=§J4M}Jh|TS_=y` \EWNPm:BvRu=#|V2zY K2g~u_")adc=OIC6H,gq>bW-2Y=OyYa`AXB.`y r3`{X5W_͎f%8c'`!u+] e 囕T;>@Z]tznIx'IiQWEbPN;QzO0$1]_52:ſe&Az)kfCo6y>)7Jh˨xoӛE*~ؐZ/ei19Nq%Lwfx|9fx1h((ZEn9uBВgw?s()?cuiꒈ.KKv3HmRS4ЭjeIRgdH5KA-lrwYCz3~DkҒIK=s~LRһ )d7<Vtv20dztK~qB$*pNWEJ fL Φ& -/S*9} X):>TPQ*6F䎺nI^lH61iY!@_x%fC k\uoU|xh4 uߗIjql ?6MH:rx3LJΉNJP Xyo: gD=v,RP`N_m`P[jjUk3|yi[ﳩաWXMCA~Q;i_2np 6I ? <$〶= ~JXkGV tn (?mςh\3i40,z3fЛo|Ebry wN1r41KXrY^s& :NQϲ%GY>("v,km MC+%й՚fͰІct+C"y=+j: qǁpޤl_ЛICEpے\p`ޡ7 I&L"P*퀛fd4o#rJ؜DXz_*I4LƻyBiQ@Nw ϰB)vNX嗹6gi;%Fo\X,FFo+6UkS|^$[HS+]>GZ֡#Qn<.}U#1 յ,XwBkY:R*zZVEF ykfJ\qǺ42k?~4ZEׂ6k%T! 6oM4frTzqqמ*kiB@0FNZZ8r$CvSoR?nIj3ed:xdDV 9o%*T]^F͡(=~49k)[=#~Çs>fNGJi7l/j9Sx?p_!5,_q@&㱉FWub<&:-jY!Yhms;$wk!FKs7GirpónirXҮRE< fb[72W>Uo>hDzKEٰzsF]%;RRow!ab.{]E4Yq@uKjbIA\bciu"iN5H<<;b~`vDK'pE.`I&81lyQm!޽ DoSiZB̑"lÕﻦFR^t:d=.ǗD8Pt[865ih7P^d!PQcV3ڗ^4;WA媊&IKi_|m)>(?+?Ж64D\@BY"ы]SYF\QWkKH󔼯 L3ÍM=pF@vhQ_]!B#m oY&'?'_m[ov8~׶wG=q-ҟ,}4V$f^lim8a$7MjeIӰNI$%iI+<&3S8%xJi Z[rR\8`WB?C|o5~DhUZMf$AvLM{&߈48YWgX3-[j"H$u-c h{83@l)%daM9sxlƊ#De(|V`#G̸[ $r Tl8lxܘw~ ĠlW`Ko#m ygQ@!Hq"x&%Qcy/(?cٍ^9x8>7gՇ,b=ˆjn\3ATJ>|f#wH놜PԢn4oB QD?Mz=2o.>TKw{UM$XiFOԆpG '`+ɤDpIhXx_D }#kD%r(HhiɖhS1%Ngj,4ײd4uJ>Л76FL[ <83Wӂ& ^ =J. q&WVrP/dՐbauCaPXQ]_(_!Z r" As #~-c:B ^ӳ՞$!1{(fMA@=t Z⹩Q|3#7z5h 9n[٫c+sju,[WmOcEܪ .TYˤhkp"ug$uX#çٔX.iKwVG2RsРgHE7׎kP]UơZF"[67HEʓiRGDiR 5Id4ul)+B#{͉ةa|2 pN!yNo0KX`]IQOb*iAU C~5G&߽\8Ms6ۭ&Z`[;4g5{?$cN7zhb~bncb7u 񑦵LyIMQ԰wBDZzE b.y]* 0,#bEJĮG WJ$j;{ML~G$啵g:J$i ĹstXPh:kEśv8xewl{l;Ht^JȮ1ҫPO&n lx(R@9رa>9 uX=ƭUJ:!Y&GMJ({ zvYgG.i"+_mev@vcymmYVILowkӗdȫ% 7_ / ט& dӬ҃꾀n7c^Gz33~xhMD=AYg#$+oU6Ud4uzu[4TZڬ|PWYY$?ջ$FŸ2XT )27/Vh aaяe!F0—GxPE)ɝJ ;!dF57}5WҏDEfGpRi Üb€7\2\ZZe;]'-8\e2Iz9NfGz/L{2Et!NߘI:oKL3eD$.[|smn V:)v~E< Q֞=6H\|״x]4:8^`ch,G3%\4 II#oc\֘OOtjj?~OwZϯ5۱AiC#,%l5/d&&CWkRI3 '}m{oѳ7S4<_s WvBʴ?yڿXc6D^3zshaW-!`~hMwΕ-쇷hvtG%?ʻ1o'&XPo>74juCVU__8=kMU_􏲊R5ͻ}+'8i F <ݳk""BQ\e`*lh=h` ;[s`s&,iJ跸t璷e'GY,18֘ >8z$`ҹ/j s3\FC'9 8A#$3y_>`m&Ϫֶb&foeި0gy 4r&]57UZG; .{مwUXY *n5zy(H" ]d+]_Ci=]$9rCQu$bsKEuNf޹~O?ec9ЛtO&m<`t_-{/y OETOIA zA혧|f#D(]hc&zp/}^b{ s\C_sAMfŗdJgioZ+Cj 3ZAr*8]-A$_}ez)_/Bt"Evlħ=Ch';󷅼hW쯛q)?˫y}L; X7zuE]oZ*a>Rl$Y>KŖ^pvc}h.G1Qs1K<Kn` |ٸD<"6'P50So+Y~bci95_#v`sX`.Ȫk&|mx4X']&uTsx1"]o's C_yӒL\QߎQq_7 F͒ AHn)Vwe <r3vʏ!@y6tXXQ1N`4fC1enm`'[T OC Phš(ٗW##WA {> 3(˲EzӪ}WIM?Hnb' !p9yݍ⾧zQWپPHS& |$EۗVB87}Z;/QMs@c3҈髋nk0UlVV6#۞ƚz;^%ie>揅GMyo5 hc̺k: /2796 ZSkLcia+g>^8=;m3!O)i=5e.8 udn}y.'e7ڠLF] p+h 5Lcȝb өRI!:Ib[zyUJrﯚ&C4{y-M1qMlF3hDz8ٖs p l~pf)ϑgN;9-jc&9L08ۃ ^h-ka?}YC>@QNuCӱE액1r@EuZ85ڬz.`VmVv1񘋺h0z3`suZ!\y$+:g=һ[4ޙu^Az:tCݾr+1YzпWLDvo RjHr UAa[ æ\gbm*d&4`:n'Vi<.2BD3h1Z6>I5lhYЛs(=rܫe33A悅k۲–z*\V7Ul 5'0C]2qv nd_q-C Ov4F$ʼn_0u'n&A9 nvj .}$ {ЛMB1y &E!NuMMVTʙF ;x~+^ 80`CoNi^47q.0\9 Iz@\\eaWߵt 83:g6(;%6!-yBkpXH*Gސߠ"F2o>Gm'zݓRy4 yd(綰ZUd4YE,]$3;$>k0:Y*cWA@q_`1wOxG˜O#Pa=1 \m#p͛-̝ᛁr٨qojp~ӖS~M]/f7'|"Xm 6~6$|9crK7UZK-Iaͬc);U!ԡ7MH7 YAz37vDMBoZ`CoFS ꔾ%[ U+J_޹4FfGf IeI׽zϢ=se^`P F~vOrU3;u+}~ߝ&~W;9Rݞz"_ύ/>;j4SJvC?gMvyrܨ鶚>psG0 ڜWݕfml{AVI7#7cGۃA}pͱhfncM> lo6czcs;>pLxn"H|6,Fܪi.3Fyn x;u3[j_#LM伾X̺'& _sF%FB3X3^N}D͘#L8A9VSG.x49}| 5Zw8:\Ӕnx6Jڭi|QC*=`T r]7ymz3ڡ7( Ku"|tT[/ xjHoXhT[!f!nH@ ^rw=j7; " tIPTuiIa>c'Lw[6ARU-ٛyCEnwP,jzJڛmsEVe& ;rj\3gGgA?r7uif WMfsFU_qFZ3:4T]_Qq[3[Ztc9u{ș5:=cfh,k&X@u{uVUmӢc0|w]8MD'"hiK {ҍٰIӦ)< RvhgMk9v́` V30䞰 fmh$, @٦7y qHoބdf4]NIg6f`K k> ̥3 \~)Ѵ^l-` ؑ뼄 \"hA,B6*)- nA&1A U\RExr)%K I𝩨S~4uVƕ ٛ2|Gِi .>g16uf Xt` HH7پ#}>qic.OuD6ty! f=?0PLTͩ, #ۡ3~+g.^EVt"aܺ1+A BvD7#5n-謤i%˫貾 Fc{~y9\>\>"ɁxVd2 >1Cϭix=1|uJ+gGg|xrZZ^\xVi4Wdi?w CHh& `psgǹpLJsF%.0llC!7ِKP ܐ>zqJHpBnP񗋡^u;S +7![e fPE`t^K_C:p/vߐ[ѫ:~EP 3m%TO{nENzS%镝LA"V/k=y.u5 ` I1خ%?9 QԚyV󉚥pmL\6̫M*aTs [1Z\vÃñ9SP`}FflҎBd'UOࣵ/ 1R;AuS+H``/{JU2 psaq:ׄDIVy0Z5͖@2Y~,*amʃD#%<,Žm+*% 3L(_`}낡(f3e8KQFhHPRAk P Q8bu@a\@mQ3ru /=RU8e{ak奤DVX>ij,lak/[ƭbއ%ILZA3tµ-C2a쬐ꄦB> ~rJi S7i +v/ßoT44$f3#;Ja4 2dK5,` ;Lfb1_Z0OJTQ>)9LC~i LB11|< Uؔ(" :D칄Cm[ =Ic˖P4#RC됫%]MdM#nцEt#idmB;<3R@}K{C[5@f"`tw:6u#(~ u,ۿccnl`onh:#;VLm7$29c(*;v?)X${;c0"ѝ*so,"bN 2}H_1'IОWϟ44V$Q[)%i+=,/K$R'O Fd ILqM{B:W6Z .'vyӆJԥ/l*J^-2Ο6Dk]z^]ʉ ߏڽ:SՍԪ~nWtF7Q&sW|Wpwm7SCop}3R9 pM,ax˰wؠj0uju^MUoI'= e SsLUrRnU_$?Y__@ E'MɧK[Vrmv~X&ӏjöT<Ф. xj10`k..1MdTbd5h8!m4pe婰as3R]5r+T]AiiZzfTFʰH Cƫ>BMܰ3W(se;f"Z(E@D׻0N7u{d@-= kCCnTT]ֳ}3rV7eZ*EֆTvy,jqϻ]l 2}b(~.&)BK0izIsP5DR1%?4=]oHȢŦ i-W8^.ԁ9NMwKQS  QgR3OPq,׽k] j1[97L-fy&^a|TQF8NAk<dT=5c= pf ejY,bxʐ=`z)3$(qOӶVuzfO '/_2QMglXQ{)69eil{xm3JfNEk)'6 >rv6O |SN犨(I5%k sA&/OhYoWB:=T-nZꭾRd7y ҏL\ki`» Х6bLYtgpqҏ{l3A٪ 3j?`#:lG7/=|x]`.>\|_ێ^Z~YulO1-f W9燫̬ǜ9̼2`m8L|T+mO\I&pצ\%ӨC?mϮFx9Au蔢CR`W*yL׼8!+m`iMELݪo(mUe Wz^*m?ffw6j(7LPύ }nTc,ъh* 4JH/g$~4? kL$j5=:F`֥W7Cf HĕAkJ_8y;'m65Ngżq94[)7}l`=H[1;QHbHjj%jN,jav^5fsnhkKS%ZBH-o^Q?[Wz˿i664Jr֩.famz#EQQd4 ޜ'`jO2"֖nFoRSh+\_י!f4>7]p P&/+I-WB۾C߬/iX٣4F+XcMoDFz&CFqф[f4gh0RT-r:Fhv7!͟ ١7hh|(?EyjЛ:'9XFoNFЛ|r4ÈfI^]' Fxp_7.^{:U1"ڏl*CG27Fvw-< {9/"WrE}ĨccS޷ћŜwŘO -ŰCq'b E 7BEWjq xT%epoi6-КJA9rE]nfG6pA]%fS6M$\gԅeOܶF|:qkR:z>H(hQXUo9v2zX,.u{tlZ75F:δ$69IzPxY.5zSc420.қA'z 6 7gQr<#y 6omzGQp뜧a4w6"ʤdى;g _ o\5g4z&\A ίO߰uTY{k{nh C $y7t+BoR` ^\s /焖V|\ɴi,87W?ӛ FfP@ǜ%$G+eM9ɷMh2%2MH|?UdGraqWf'#z62yvŝcHż>uIb٬INU=^z+~O,7{k]x8N$( K53kUXuWG7\ۙ8kqƼGgJOC1cTA2q" @*htu5tGMoFMxf&7lI4MNWQz=Y֕hh;bŠ'zϪ5q 1Qab]b)'қoDsT4 y[TZE B;i%\JoJϨ >O ~Oz5`^Pg*u^u$)E"1,&13f ϲJ FP6 ?qdiTlҤKw2}fϩ\ћ<Ģs߁5q*X4${~Ko`3zSc4hcZ0 ?t8?\g5zseiMg;j7ۀ ,5v>\]47 12̐Ǵ_{ eIPk?kIg)~e{# ;9 &CزO緝i ' cu͘Q-}$Uʥ~i)y+7C.]FF_CrkwX%/=U|yEelmբia>~f.e@Z0}mkl4^ ϳ@M/bf/8dcu{YYIh˫]>B3:eFjD9r83ѽ>>oQFUz9\Z5z*Ju" ^&p t4s1;[ICi]cxڱ_G}.kRQ.D"dX<+h6;1xj2bԚpIsSM#N"HijD{'X+DO9^qglw|>^Yf2b<5F.7 r2A5vq+3?[1F3E|lfۿBi0͞^jʦ8 8x#y'o!qnRk@JS&{%8fkIJ &eiA:6Cn@rƶ~X]{P[~޻.{y6(}FTQ!30yfZg޹=7G7kφXγ5^3?V>o~N4(kX,N1%(rWgyHެ.ZJ$, sfnU?'`5_*튁a'ds]x6zV˶Kgk;u?pJ;Gp4L'{Y4U Mkve;P5%8lG`es&7a؏΅ {e|kŹİ ..| f |~G%&pMl4 j@g/y"H̚Dɕƥ-4Ꮝqp0Z_M(phRh[2(t'ij gcU$dnYnkX_]=2%E4k:{NId9:<%= environment.object_id %> sprockets-3.7.2/test/fixtures/context/environment.js.erb000066400000000000000000000001231331222022000235040ustar00rootroot00000000000000//= require environment-dep <%= environment.class %>:<%= environment.object_id %>; sprockets-3.7.2/test/fixtures/context/foo.js000066400000000000000000000000171331222022000211560ustar00rootroot00000000000000var Foo = {}; sprockets-3.7.2/test/fixtures/context/helpers.css.erb000066400000000000000000000001651331222022000227640ustar00rootroot00000000000000.pow { background: url(data:image/png;base64,<%= datauri File.expand_path("../POW.png", __FILE__) %>) no-repeat; } sprockets-3.7.2/test/fixtures/context/properties.js.erb000066400000000000000000000003001331222022000233310ustar00rootroot00000000000000{ "filename" : "<%= filename %>", "__FILE__" : "<%= __FILE__ %>", "root_path" : "<%= root_path %>", "logical_path" : "<%= logical_path %>", "content_type" : "<%= content_type %>" }; sprockets-3.7.2/test/fixtures/context/properties.with.periods.js.erb000066400000000000000000000003001331222022000257470ustar00rootroot00000000000000{ "filename" : "<%= filename %>", "__FILE__" : "<%= __FILE__ %>", "root_path" : "<%= root_path %>", "logical_path" : "<%= logical_path %>", "content_type" : "<%= content_type %>" }; sprockets-3.7.2/test/fixtures/context/require_glob.js000066400000000000000000000000321331222022000230470ustar00rootroot00000000000000//= require_glob "fo*.js" sprockets-3.7.2/test/fixtures/context/resolve_content_type.js.erb000066400000000000000000000002721331222022000254170ustar00rootroot00000000000000<%= resolve("foo.js", compat: true) %>; <%= resolve("foo.js", :content_type => "application/javascript", compat: true) %>; <%= resolve("foo.js", :content_type => :self, compat: true) %> sprockets-3.7.2/test/fixtures/context/sprite.css.embed000066400000000000000000000000611331222022000231270ustar00rootroot00000000000000.pow { background: url("POW.png") no-repeat; } sprockets-3.7.2/test/fixtures/context/sprite2.css000066400000000000000000000000611331222022000221360ustar00rootroot00000000000000.pow { background: url("POW.png") no-repeat; } sprockets-3.7.2/test/fixtures/context/utf8.js.erb000066400000000000000000000000561331222022000220330ustar00rootroot00000000000000console.log("Snowman: <%= "\xe2\x98\x83" %>") sprockets-3.7.2/test/fixtures/default/000077500000000000000000000000001331222022000177775ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/+plus.js000066400000000000000000000000461331222022000213730ustar00rootroot00000000000000function plus(a, b) { return a + b; } sprockets-3.7.2/test/fixtures/default/README.md000066400000000000000000000000111331222022000212460ustar00rootroot00000000000000# README sprockets-3.7.2/test/fixtures/default/app/000077500000000000000000000000001331222022000205575ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/app/main.js000066400000000000000000000000231331222022000220340ustar00rootroot00000000000000//= require jquery sprockets-3.7.2/test/fixtures/default/application.js.coffee000066400000000000000000000001031331222022000240600ustar00rootroot00000000000000# My Application # =require "project.js" # =require qunit hello() sprockets-3.7.2/test/fixtures/default/blank.gif000066400000000000000000000000531331222022000215530ustar00rootroot00000000000000GIF89a!,D;sprockets-3.7.2/test/fixtures/default/bower/000077500000000000000000000000001331222022000211155ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/bower/bower.json000066400000000000000000000001631331222022000231260ustar00rootroot00000000000000{ "name": "bower", "version": "1.0.0", "main": "./main.js", "dependencies": { "jquery": "~1.7.2" } } sprockets-3.7.2/test/fixtures/default/bower/main.js000066400000000000000000000000131331222022000223710ustar00rootroot00000000000000var bower; sprockets-3.7.2/test/fixtures/default/coffee/000077500000000000000000000000001331222022000212265ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/coffee/foo.coffee000066400000000000000000000000161331222022000231570ustar00rootroot00000000000000foo = 'hello' sprockets-3.7.2/test/fixtures/default/coffee/index.js000066400000000000000000000000461331222022000226730ustar00rootroot00000000000000//= require ./foo return typeof foo; sprockets-3.7.2/test/fixtures/default/empty000066400000000000000000000000001331222022000210460ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/erb/000077500000000000000000000000001331222022000205475ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/erb/a.erb000066400000000000000000000000001331222022000214470ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/erb/b.txt.erb000066400000000000000000000000001331222022000222660ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/erb/c.js.erb000066400000000000000000000000001331222022000220640ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/erb/d.css.erb000066400000000000000000000000001331222022000222410ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/erb/e.html.erb000066400000000000000000000000001331222022000224160ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/erb/f.yml.erb000066400000000000000000000000001331222022000222540ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/explore-link.js000066400000000000000000000000311331222022000227400ustar00rootroot00000000000000//= link gallery-link.js sprockets-3.7.2/test/fixtures/default/favicon.ico000066400000000000000000000004761331222022000221270ustar00rootroot00000000000000(( sprockets-3.7.2/test/fixtures/default/gallery-link.js000066400000000000000000000000241331222022000227230ustar00rootroot00000000000000//= link gallery.js sprockets-3.7.2/test/fixtures/default/gallery.css.erb000066400000000000000000000000331331222022000227130ustar00rootroot00000000000000.gallery { color: red; } sprockets-3.7.2/test/fixtures/default/gallery.js000066400000000000000000000000221331222022000217660ustar00rootroot00000000000000var Gallery = {}; sprockets-3.7.2/test/fixtures/default/goodbye.jst.eco000066400000000000000000000000251331222022000227130ustar00rootroot00000000000000Goodbye <%= @name %> sprockets-3.7.2/test/fixtures/default/hello.jst.ejs000066400000000000000000000000231331222022000223770ustar00rootroot00000000000000hello: <%= name %> sprockets-3.7.2/test/fixtures/default/hello.txt000066400000000000000000000000141331222022000216360ustar00rootroot00000000000000Hello world sprockets-3.7.2/test/fixtures/default/hello2.jst2.ejs000066400000000000000000000000241331222022000225440ustar00rootroot00000000000000hello2: <%= name %> sprockets-3.7.2/test/fixtures/default/homepage-links.html.erb000066400000000000000000000004231331222022000243360ustar00rootroot00000000000000

Hello, World!

sprockets-3.7.2/test/fixtures/default/interpolation.js000066400000000000000000000000421331222022000232200ustar00rootroot00000000000000var Interpolation = <%= 1 + 1 %>; sprockets-3.7.2/test/fixtures/default/jquery.tmpl.min.js000066400000000000000000000000141331222022000234040ustar00rootroot00000000000000var jQuery; sprockets-3.7.2/test/fixtures/default/logo.svg000066400000000000000000000001641331222022000214610ustar00rootroot00000000000000 sprockets-3.7.2/test/fixtures/default/manifest.js.yml000066400000000000000000000000371331222022000227430ustar00rootroot00000000000000require: - foo.js - bar.js sprockets-3.7.2/test/fixtures/default/menu/000077500000000000000000000000001331222022000207435ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/menu/menu.css000066400000000000000000000000111331222022000224110ustar00rootroot00000000000000.menu {} sprockets-3.7.2/test/fixtures/default/menu/menu.html000066400000000000000000000000161331222022000225720ustar00rootroot00000000000000 sprockets-3.7.2/test/fixtures/default/menu/menu.js000066400000000000000000000000201331222022000222350ustar00rootroot00000000000000$.fn.menu = {}; sprockets-3.7.2/test/fixtures/default/missing_absolute_depend_on.js000066400000000000000000000000461331222022000257170ustar00rootroot00000000000000//= depend_on /tmp/sprockets/notfound sprockets-3.7.2/test/fixtures/default/missing_depend_on.js000066400000000000000000000000271331222022000240200ustar00rootroot00000000000000//= depend_on notfound sprockets-3.7.2/test/fixtures/default/missing_require.js000066400000000000000000000000271331222022000235410ustar00rootroot00000000000000// =require "notfound" sprockets-3.7.2/test/fixtures/default/mobile-min/000077500000000000000000000000001331222022000220275ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/mobile-min/index.min.js000066400000000000000000000000071331222022000242530ustar00rootroot00000000000000var $; sprockets-3.7.2/test/fixtures/default/mobile/000077500000000000000000000000001331222022000212465ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/mobile/a.js000066400000000000000000000000071331222022000220210ustar00rootroot00000000000000var A; sprockets-3.7.2/test/fixtures/default/mobile/b.js000066400000000000000000000000071331222022000220220ustar00rootroot00000000000000var B; sprockets-3.7.2/test/fixtures/default/mobile/c.css000066400000000000000000000000061331222022000221760ustar00rootroot00000000000000.c {} sprockets-3.7.2/test/fixtures/default/mobile/d.css000066400000000000000000000000061331222022000221770ustar00rootroot00000000000000.d {} sprockets-3.7.2/test/fixtures/default/mobile/index.css000066400000000000000000000000321331222022000230620ustar00rootroot00000000000000/* *= require_tree . */ sprockets-3.7.2/test/fixtures/default/mobile/index.js000066400000000000000000000000231331222022000227060ustar00rootroot00000000000000//= require_tree . sprockets-3.7.2/test/fixtures/default/ng-view.ngt000066400000000000000000000000241331222022000220610ustar00rootroot00000000000000
sprockets-3.7.2/test/fixtures/default/nokogiri-html.html.builder000066400000000000000000000001361331222022000250750ustar00rootroot00000000000000doc.html do doc.body do doc.span.bold do doc.text "Hello world" end end end sprockets-3.7.2/test/fixtures/default/nokogiri-xml.xml.builder000066400000000000000000000001651331222022000245670ustar00rootroot00000000000000xml.root do xml.products do xml.widget do xml.id_ "10" xml.name "Awesome widget" end end end sprockets-3.7.2/test/fixtures/default/noreturn.js000066400000000000000000000000101331222022000222000ustar00rootroot00000000000000var Foo;sprockets-3.7.2/test/fixtures/default/project.js.coffee.erb000066400000000000000000000000671331222022000240030ustar00rootroot00000000000000window.Project = class Project VERSION: <%= "1.0" %> sprockets-3.7.2/test/fixtures/default/qunit/000077500000000000000000000000001331222022000211375ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/qunit/bower.json000066400000000000000000000001251331222022000231460ustar00rootroot00000000000000{ "name": "qunit", "version": "1.0.0", "main": ["./qunit.js", "./qunit.css"] } sprockets-3.7.2/test/fixtures/default/qunit/qunit.css000066400000000000000000000000121331222022000230020ustar00rootroot00000000000000.qunit {} sprockets-3.7.2/test/fixtures/default/qunit/qunit.js000066400000000000000000000000131331222022000226270ustar00rootroot00000000000000var qunit; sprockets-3.7.2/test/fixtures/default/rails/000077500000000000000000000000001331222022000211115ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/rails/bower.json000066400000000000000000000000641331222022000231220ustar00rootroot00000000000000{ "name": "rails", "main": ["./rails.coffee"] } sprockets-3.7.2/test/fixtures/default/rails/rails.coffee000066400000000000000000000000131331222022000233660ustar00rootroot00000000000000Rails = {} sprockets-3.7.2/test/fixtures/default/rand.js.erb000066400000000000000000000000361331222022000220270ustar00rootroot00000000000000<% @dependencies << "rand" %> sprockets-3.7.2/test/fixtures/default/requirejs/000077500000000000000000000000001331222022000220105ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/requirejs/bower.json000066400000000000000000000001061331222022000240160ustar00rootroot00000000000000{ "name": "requirejs", "main": ["require.min.js", "require.js"] } sprockets-3.7.2/test/fixtures/default/requirejs/require.js000066400000000000000000000000301331222022000240130ustar00rootroot00000000000000function requirejs() {} sprockets-3.7.2/test/fixtures/default/schneems.js000066400000000000000000000001531331222022000221410ustar00rootroot00000000000000//= stub interpolation.js //= require ./noreturn.js //= require_self //= link logo.svg var dog = "cinco"; sprockets-3.7.2/test/fixtures/default/symlink000077700000000000000000000000001331222022000225752mobileustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/troll.png000066400000000000000000001707061331222022000216540ustar00rootroot00000000000000PNG  IHDRmgAMA|Q cHRMR@}y<sLl[,#ep2 p\5,3@Ȉ0⅄ qH"D"H%R ]H?r /a`g?&dcbc1G1>-(fKŪcMNl 6-Vbc۰ww8N gsbqոV\n7*xS >ƋEcs!8L"X| qa#D8K"LfrD}1%$]q,IdHr!ERIHUEC2Cv$*qe(#EbBSĔ#}*j@uQEFcL WfLL̐KYrU'eoȾ#yɱȝ[ɇgoo"?W0PQ**R0FCh4/@Hz* }>hXxFQ(((+*Pi,Z^YM]\ܪ|G CG%MeJ#UjjՋ/jjbjaupԯhhjidiոBSI]3UBMUUuNCHgT1b:YCH::tI,$ ^i=-`fD}~~[ : &  W6>4e6ӌ4MLRLjLn¦|fX3G3Y0`2J7wгio2ݲrJ*jUkkkum:NW<hvv[z; [9 PveG:nǏNN"N93Ӝ'.-lX8vs2\\JܴnnOuݹ'<=R=yzyrZxy{(DTKw//pY+U/?Bv{lBtBSgv=/qyuVpx.rDKRydKʔ|/~5Ujm#isA/S33?s04(K픽;{Z$<,HY<[!/*d| JVN]jj k<ԭ&]pzG76m}o7Eo*(\_8ossLhxڭl[|IJv?YT܎pe;v-/_U>+xW{TV!T-ܫl;55m~?w-%ޫk7<;{iCTCϬ.9hѾF&fY|EѿSu}:fzoTykw&tw?|8SټU_t} p.cnobw_KbE aL Kɐ̧$c3k(B??CaJ ߵzX3^OyG0~3Q< =3 6s~gEZ)'O(`K+bƜL/0cX[Z:dc=) ꝱͽ1_ҹٺ/h/z ?i3 pHYs..\d:tEXtSoftwarePaint.NET v3.5.100rIDATxw\eǟ3Ν;mKB  @H4E4)4( REQ0JAi6@ @Nsq}&M oGfgvfsBZhg[Zh!@B -Hh - $BZB Zh!@B - $BZB Zh!@B -Hh - $B Zh!@B -Hh - $BZB Zh - $BZB Zh!@B -Hh - ZϹs tN$X0p Bq$I$G~Vau&%`p\!Bɵl&L8Q9qbDH A &YLllr(QE6y )bccK)R )Q(9,bҤ%KL yzY5X؊ًC8/s6W}.l`bS&1<)(2YC vdK֥A EPHcHKDv51w,K lZsdgs4,d6ʳ4, CgKH&CSŔeI# +79Y~R%p$Ez ܎Y(#n#6Y}g]G? =@eO9F~D:Y\^|A <=)Prj<șRyHI.\Oƒ1#pJbG:W#e6e-QDI -Trx?||:~ 9 N&ѱN&Uk+E$?D!J15"D1tasI"9y9XLRdȐ E<Codo&c%Cc]; Vѷ#SpI2;?"I8Q"x?aňhSL/}L`5f#6ac6g{vElWvfcldeVfɮLa{as6dm&=XQXĻv. q [ӟ6)R$(K![%0wEy I,r$1$IIlɎ¹\_g%b6ҢiӢIpi0Ԩ0im7#]1<-Z842\f28q#q 5+E I$YRL)1s(듕Ú@$y)('+٢>:L)$) I L ʺlÞ\̵C<ś Pw9-Tr44PrGEKܦA:U{8IK~*4iQ_TFMjoҢE&r7g2"a&K&ilr(&qɒ$A,z(!A^9)t&SY@I㝦ؒ}8/s 7r? jƕՖcX)PpS&0qAy ^b:^~Ώ˹ 6s)?&~Ƀ×xyۤN!j_=:oݕoC0/A y$9 ˁw$HHbPɫ7T'U t+S"ہ1\1 M9-(j4ppi30 ҫ<\Ye<9 YY؆؍C8/p's p2q;۲}283ixCG®N>32r ~ζR&..MKF|nKiơؓ HV'K46% Rϒ@AD;K4O'3ɕGxGnֶ:ӔkF dH¬v :W\ƗٗY]9Rd'p>Ӹy7+b\,r3Y6(2gg6spiQ,RnkyE\vibpPIYI(D>佑,8NdM"(2$(I*%#vX#.Ia1"~}͆c(R$1 ؃W-N`u,[9?n[⊇y ٖ"Q1i>/ZԩkQ`СIFԚqA9LPA1+aP&-u*/)p(cc!ITv1؄9+xgy 2Ġ>u* 0x4^napGie]V:Q\Lge@ԥڹ#E^ߩ-uWos}?Cŗ#YGs QH`LZy. 1("yGdlI)"G"a(1<:axy !g\ʁLa=Ht(N>Vae]c21OTdH48ilVa3rr5fQ3h9rPkЊܠ;rug@C%G j8CVVX&SE - Aj "G DRFq,!@оȪ(R4!Oiʡ6٘;y!RK!p#vʎס nۜAD #Ĉ'M/lV>)~";0r$fooRFSBF'45x:>"V{@N=u40VGa5W񦀤Iͥ0ДoAlb1rD&G8dKS(!G4y=44ks fQc8PtJ?\S zή;j@yſyO/ASvaJw,3Яס Td6Q.bblU# q[(IR MY%24eL&M< x]j[ G =#.t =f|s!w1S@!݁hkxSěū^`%>\Zx6m 7~4AlU &_*)cǯ6f.$bkQDK$NuهKy! v콸l.g"&aV 4{.jd+r"YRɒ:BlkylH&M E^PJ* `mL@e a Û#I"Ȳ;q:xWx?GSܕרIbvU\]H pr {1+cnIRڕن㸞2էq::ojѠ*ڔLäЦ,.AVIQb.1j@MhӐ!YX(dX_Jz O$v/ lK F "6)R0  (bcJaƤ,qz9lj38\86_UdWx;S9ؔ)4HF>ُo#~kT\,Pu]lYs_ƑƦIx)2hJ:S9xYnQh1*,pdtUcHԢq''$ hfAUW\)0ɣ|AKjūMCtV%N.g%ePXI'IQ{VM*4%zfQ(呮4yi\ȉ'ؐ FIMVbcvfD\w+].|TN@aWaV$cy YP&I(Ybo.af>~*5黸tl΋OvG QFK`HSs(ϓ&#A7e0ICw00u%T{4ؑ'2$=MZ})6|͙ٝ@DNK~!NTXd2gLƱun)") S7pum]qtլ5b2'S CbD9 :Sl&#b#~ JDU,/Ju#GTs(G}O>'Q`'K"iLzQ9 ] tgjTAnO/:5Z0 Uez&ɶۥzMQ6~ą g;=k8g<+3l'ؓ8p7u"aLC^CC"|Y=`?k >\M_AMCT< (5\d<`!MZԁkQIƠM g'M4L X1ҋ<$Q>Ey 'y[H$x|I[.0 1f3 f629 2,dw- 2SSYVpDq 4_Cځz/ |M G,xhaMlQYvCGQ䇸L,Ag.ԛYPl!@vFa&er&5\`BnTX~۰K'LV–MځSTD?762qvH_ht;ҟbl~EgRx%HCM)W_ .M$L,iN\Րn4i(=u,./<5m"cVr fkY$4ccZr@:"y㼧0*1NҖ_d6} e'(etzKM#ƕi5=:yĂsiN SOMh!$3 qӜFE4-a)J/'#"BFFGpy($(E26oՒF0O dQl_i2W&*]j~! n #Wuu"KSj275:y?]081v Iג*\~("D Um4$ԃ&my\^"t6(%C,rXCQb&AHq)nE ;>)ەv&*C&q~= VݺPAJy{pF]9UbC:s˶L 3\%7|S9٘zkYc;Wzdb/ߋfs%4s4c}9r-IUi\%2P "K/iʌ#K$ ln ăKԜ I0b uF]X#ui[0'  ^p9]%TEF+8Jf=j8t]y#hR ʟ4.;M=jcCv\>F$"ly<+^3|5PPBX̧ Q(bl ]h艜(.:{7_2&AyEH1JPU:PazUANeO$M( ɍ->K !^oq+2qIIϗxGhMy.Ie:}E?n+%2P=")"ɺ?s3p,8a`P$cm~۴Oo٪ȓ=K,XaO"&661J(vt(z5w$tl.dk R( vB`f yIIaB!3_}+S؎U DiVzͣr@p`рWD$8>ڮ\F 7 ǎd*2e 92ۅ {A FA~s| ^'dxb(\4e[2za,ld)4S&f+uwĝ7e8mz'IHe;.eխuCJNlO[O: €xY84lDTrF2,剹88Qᥦˌ*[8a'PboI;QҤɰ+=9(c/ h$]QfU8B9uXN-mߣ++mD ~5$AGKKԡ.ss97J5"!e3A6-[#9(4q T4 /̆xSX$.k0 Ly\b+c4uy7=(J(6~zb%v|qtgo ޯ ߫|c75:Q˴iH9urj4kh'qvtvUqS(p.IE*.ƳPVFEgQjl%aVNt(aA &0C=z #2D;yWд~fHZr.צvpy8-L$FxZ[RA4 *2ؑ*p*CJҡp"qzE$,_N;xq21nmM, J%xZZ |9zw$v P AR]NBk1D6a[ cHjZ6s8₪a6%FIKQ "BedH;4iKGu84E .Ӈ8XH3<\- /hז(@Hs IPה 6#,%0 K!z=}/G;4 7ߦ܊9!,)zP| _$N^ m/~ _$)!96D=&7.7,BMaE]G._s4e1.ըL|űZ$SEz0EYvzVZ2.XyZ 7gA|3^k3kct6h3'PDq6JW~f3/ #wQ? K;8LcuҐݽQshaRerV_O>QļXwqq'ГDR cӺb g} byձ3P$vx<]moIk6idr 'PM0פ5:ؖLSg eR"BCo=HgFkj\w5iئ}_niH0d(Ģ @E"QzIl3z:NRg502?0C (L1(N^ h4?HR .].A7۔&(ɣΜo=\)De-LK:"D dwEKpo(g=4,AIg_1#OI  5B LNPOuiP] C܄{6p5lA`pȊ#)K{`3 2`cbQXe(a&%3Г> 5ţ~^~ A8gOl9rɵ+w@Gpԩ0CC?V뤼!G蒤p4 &2@SWf3_ ]1y'ϛ 1V'E9e\fSm{9xd7D?aljh8Fbt9fZM:'ͅLy:<4 %opͣ\+cp=9TXi=^o?Y Yd) N,Y1^R:kiksO[K84g}knJ̧$; vO1QӒ%:u`MxQh'2YYdܕɕ*l@k¤IC"JXIʘ([1BaoIctwXLrkR%TIˬ]^l*ZWJBaa$a%sp|}"$G;=f #,8<6֛.,`> YDxw E/Y3%n8z4%rF6V&&!22U;2b: +&Xx&YraaE,de>&OsR%`kH,Pnn&m V?60M2i20Y Q6zزa; 95\I,;^|ϫ=EQwa#U o\VdQiXɓ&E 6yRdcRbOc!I8Dc*C_u@UkypüNc(z!JyG ELJ0(ba_ >ChbvUS+iiѷvWcU]\yaey,@FY.W1S@޲~lZ},}h-L r䈑dGnG,dc_0P&EEI# K8{x~umd.Y@DZ-5U7 >Cr`@XtYzE[Eɧ8I(b$M>zHQN<qL3S(a^fS E 48ֲ+þMY"I ,a •|=dIY~i}Sd_p[Zٶ\|.i-kCsQ)bbEL01ɐ ,Y ~FeEH n[2BWVS %>o#@#G"jKg@_k*55[CsC+k-r @,İV:1 ؒSXcϰ衇<(&peka$+jq-!Ipy⤹FJЋZylޏ('J/=ȓLlQ-GĵLQܦ11q/CZWv>Oq7+Ξl6|8;^XnYU !u@qrHU~%O/) İ0IcQIïdXipdds4YHNDMz"Ay89"̰|n H)",IH.L^E ơAeT?+F0D6/D`2r.7)5#X ܇bY!TiUc/bId1u4 "GIԷ ,(#}3ybqɮ-iXuY< 2eؘؤED$}J3DɓTkxLEH IIӋbtH5zI[/mЃĤ(^$ȹ!O`\~6E[/QG{|1VD[7Lf3j ;W힉e)"@CIgIT$AwoEα([:k(%E^I Nna|fr#G^,%ֶ)%QmjCҒQ)xddX &)luqMez6}EY;Z *:;E N,!2ց p>?O$P.-'Rx ؒ5Y$zYMؗ#n/3<γKl!/Q$G/yrIcxRzrA,Xth)(g(P"FQ6/q: 9cJ/5I#I>2(Na2ܫH1؎B"d(:>,U+R@Q86C=oHWgkI=_ؒ9d0)0,$"wq#NXNfe ,Ib;%N_ Cd7u=@b$ȓ' {Ɂma~Ɂٔ[B1 l>|ky.?AaR"M)VU]pa#[ʲ>]`:ow :Q5I5ә,(ZcAxgy[8 ER,y,Y1D gGH#I %:L6;q<ƭ|Cʞ|y&6 )% 9'BRh.cipYRfJH2YېvvZtӗ_؅ŕiN* QpZy\~w).[ҕb`hߵmJo&w%K_]LW<9$JĈd)h ԲKғݑL>10?L%5O261HIa|%[C"K-Gh$ow8c8xיUq(YrH&}GUVH˯բMe9LuZy7 @ E.ڎCB|?PS&/˔Kτ^;r yDaCGMʑ!! j++'As 1PY~6Dؔ: JzdyLF<@w)%1myyb.:~< 2'8H)(>ֻkSXäW[6_m]s Ȣd(ي89s9_N>&-_@acSvỌERr /7uÖA[$(bZ&']* 3yG?BJ y2BIJS&08;~O@ )/`51QGS<VY8ʼiI0^ $# rH1Z#El?ckf5L—#N."sso7Y$IC/QiX0E-%q 'C^dCgH9GdD %ȋ@9r/ә%[Gjގn4ux1gxA:EIK #2%n΢>8>hQ/7AqnUέ|c87tsJ1P ĠH u)*Mb(l,fPLl Œ^I$ҤHOE9 C(~9ْF$Hke|"AFsl͢d0(a 6qıIk%S~, %Il#h3W(RX$40%)S¦" d؂8Gsġ0ÛcιLe"ibDH"&e=gfdbFm +<pߚ# Պ )s8"A@3)}-0oBMRQźQ#4Ĥ`U\rȞ(VlYdQ(ҕcu^': Al[52]rF9RˁzNbW6~pD[gH8M>2HdcQRtyMavDOEUF_Is$G؀8[xt!tu#W7*q:Q"&s4Rbe(Vª?u'YU]Nʡ$2"DPT$DL$AEY+b@F *DAED  C0ݕ߳fh~/0]uk KxӠc2|G˞F4h}Ԣ)@à},q+[hs:[`& j;aȬ4wcQ$Mx+/huԤb>!&XVu]h& ۧhӸ7S*AgK{WI/88=ٞMY F =#׏!g-ÿ(@i>?yB^v'p-0s<AV"Omlڝ}o‘|smI)۴У!EzaHjH!κ|i7hq:u5ʓtБ}Quőe@#~jIl y-7q3M*QOOsXb9Ȓ@ysb[t:Cؼ});˥z"kEc1n2;|Cx[!#ړ;M}!ҕH6EbK-QHL<%nZ* lCJyFQ Cl$')OӰWu؏3ItwbL7{d(C6 gc]9,eo\u0=%|nJ8#}Ms?r粐6gpq=~%f=mZjCӮIGNZu%ҌW!~eg,EME%TN0 X+R%AyAh/J4 j}?/[KN&y۸s"d[&,\SDL$Oe2 (mYlO49b!E49#!gX|$1ـ\Ju޶-V| Dk>3r5+rgj}gH@dͻ8uIs-BW1bx9Cy#Ȑ AV cc}|% E_0CN;Nv=th3 ,(ƐLJ"Z+UG_.!GY_˺걔6(`؂}e߅BZF1FcLvM\SlGEnl C<)*1!5ZCLVE0;2(D! Ĵ+8Lɪғa.kmNNkhN2 4EjTGiY"[bNqu. o))i9'J(QRl!Ӻl,۸@_Z1Vm9ٛ$Es#KB|dHSaW.`LF0MJ,LS-&E ˽HS_S66(6`.M*\r5 QȐp #ǟa vMB}IQ0Ɓ qJ1J! g db(RJ\)"Jd4@mq3'b)״'FA-Dtɗ99xY扬ᑢJ:<7e9YIm[L")1 R>$09s>`zRr]-f1l􁥮YVizN t{3,.d*H)dZY y$ISd i` _vZ-{`ɀ?/4+Z$1('cJCR J,!`\^xmLrR$I OT1HSƣFۖޯl-n~w[oɷmEq3,m1deMu'`0Lf/lB$o^]y];tyyjCv?cN2mqQS.}52ì@>77+|ӥ\.mƝ}pne>Q 2ŎQ%Gf!$MƵF vuZ" =TcrJ8O`E5jBӸP$*ɑ`ai=VƘ< )K|QrOaS kI.<::حq'k,ڎ\{̓/^y,%~g-v$ gBwoVRTW@ք{:1m#k&ۣ,J(P0QT1 ## EJudnL`3TJPe;#/E\1ܩڤׯirk&]'u`G %H9XVww ؍OM.7kK8S9X _?.Vsn e|2$ّJx/[*~Bm1BL:K9HRŰ3Dԟ϶^9~g$I!b  [ Hd7q;#Is%iҗfx-"'|x#ȓsbPfkvG`{MԝWTD?o-dL)Ĩ8  J |mQ( w Q2IQO,#eD޷3G7p=Ƶ'M㖎]^I"EHPUZLx(ky~ ,֬^dsڐV@b<FN~q" xVcV 1-邏cHDlГk8 Â)L򩐠(%D4 [Եg\;S:3Y>u1ҢָY#C~SMS\8X")x/6$wMq2[]*$_u ?Xm.Y+>@W}89].&Ja2dIS!/鲾ɋT"YzvpH 6N$eqZ].HNjhKv0 3Da{dZd@)`6K2rϫt!&wi'OV-< d!. N#ƐbՖ/ߐIO }q j׈ֲ.zoQ^Gb1e6\(&ͦg)74dnu[%H sHFOHF2cDC!9 ~`rF.w$*E# %6 r[2XyeՖ0'W TPq7HJmv-4Ӿa4elR[+A6I!/+_R 7cEOHG7-ڢ/w1NS [c)ʲ?[0ᶽ=-d'½jW,mDL06/{_ޮ(u ]v~-Hȼ'INY o^idb"2DݟQwÑ/KZ(pHKǮ n:{y;Q#|Mб7F x{yzؿ75qt8VhmƐՑ[vpX%[FZ?Ԝ|C >=[IP7M֌ ,-CQKQ])?+P'o'ΝtX SF ij]ԩӠxjȐɫ DE<$I3 -u/dabr_ѤMQ8 ˢX}vY(ښABqS[ۘng?  N8Sgs<' p)L:yUɮiu#4FR  ,{PQ M|܏wDmadghgT eh|mivpЇ%QnIܤ"Sa9^xj+ xܪCk1$0x\,sF>6U93ʐ*́vK1"E"e;r`X&?1ԈGF. )CP-.\V ބN`Ȓ>0 jN QgvU C]Nu )%x;8ę ˸̔(w5Y K|Y<mImBή+ox0rK%Y*yN|?jH;bG0ksxtFClߵgXj9|r 8@D 5AxgQ3A:Lj%pr+`x~ޱ7H?$b DKK}aUW=˜自Æ[91ĩPJRۖhL/uғdD?NI~9Q0G4_|nɁʚB"'!reǰңϳdag`= t9]ٙp,?29.i}gן̷& q~,q\Ȫ6rYy0H0:"\xsdW`OGk|fZ68zƮ& fN1';`w_cw}+YNK2 #%[bZߩ\\Jo;BL- FZ"FQ0<* cHp4`ڕ DVp{) 莌g7Ibh}R8s&οglE9gqcHʢ6G2y}1GHfJ H&A^әPt]|Ū@ELqӞhN'GSW@6!."/OOg;4qŘiogDLQ<\Y4C4 n.]~@ q2Tž2;@<ᶚ0d6Z޿R$L&<#|Y1Γ8V|y% dɝ1W!E<(U:HiODȋ dkGСR^V)0.E@M^G=8&q;-\!t 5 _|)#@q 45B3B6V |wf]bNN())`:C*L]w_73j_׈p,`GP"">p2E 7R3dLa< gV$,3F-'Ýnh'w Q(Me{#A %Mq^HmX 6jS\=6'9$ PǧL7ȁv6 $lQxJ )|j('GxAg~ :)Z E,Ismb&XJK{A08kY%wcQ.}LjՈ&1H0y;g ά$9䉰5񸩉(QY"fn57dbV@0EW$%1\s8scthАzGX uߴ6+ԿϔB2yMU!#|ב&@pϵMeIޜicDYr"qǐM~j̫M#B5#B 0\,Iۢ]2O wV@Sx},y|S:- =ؚ(YNp'MS;З:&BYYh K1``𘧌 > cx/h_@hxk9JB9RHSdaܡ ǜd̿ -B뷙7$ `[ 0$ZM8E7@O`+$7KB?6pn]/)SHl- c~j2m$!Qq U g^`6#s!C-°}]-w| Ѷ7N) ʊΐY/;-1T)(E*Y2 O=aHa#5`u6빌3"auECANe- |]>r ' ~%\ʯ)g]޼y'q(T~ǣ3$8e{-5ގ#N R:<-;/ af0-<V_bie>Vt5r>>KωQ&%כo%\)2Q9IJ{Qk%G -,P9_;Ƶ9< V@0>C.E|8g1`c.R"ǀ1Tɸ0C8Wzsb)֘ǧJ4 b.p=@Zlmmw9.dck9p"E79_Wnaa)uZ4x3!|yiso2I|$]ƙǗՖ6Q.QTY8VgXK$$rO!i ȍkE kI`osզHiP#0C䨒pf~9a(z|iҐ7zk [;q\ށ8-5(¸p_ABEd1$4)&Ky0lN8dW2xUStmUI}P&@smqz܋ljjC޸wo!aL4)6%|""2\" Y$u~G؊y;md6{=}T}{[Ww)8S',՜qd%Ok\^U"ɔ~_BzuM,f1ܩӉ:zX<]'Z+A%m:ܵ\I<IWupOOLy080rKiǩȸ!+qZrUd$zC{7)8ؑťDL݁GJV1va:~YFl6:cZ C2W G!s;f@W5W]}j-g{4ɥ!bT E*2%N*dTl8̷HB,eJĹIl s.#Xt(JT CMw@ &dHG~; jlý-1܆G,%rW&-qjԅْ REPc9X2iJ 'ʮ\>6%i!okc o(K ˧3˟):l!OUTC^[rM[(siQ!RvNzL#mCes~D9*I9M}eB(/LȗǑ{}gBC2GwQcώyIkaxh%*4YWr/#ƊoyZR*%ۆ$9f@kdVS 6c&\I,HsGR416#C 6Lm+ 7f'&C뤲 Cٱ=da>%2]ruu e 30-Q f5 * R"ugBf-}`ce t)ǚkG#=og7v>>U0JK\\ }c0( mJ徨D,>i eZH-RNԛ*5jWg ~`Q[=KaJ̡ FI^\I" e3ӓO")1' u4צ@ҁR3ӳ)L8S{"9K7?QR`EFDF͵hq_ r*jUT#Et tfȅwq0y 1vPqgɒ'GOB66>MD\N0GMZ0#l`ɼ8"4x02 sMSPvhӇr'/_^_޵9r2.ϐ GyuN'03֧rƲbyʢìȢ8(˝.g,m=CMϲĶ`g@0iE3t ;Ő"J).g:I1۝O$%ĴR&@1A{!ne@U xSc]~Θۡ4Y$hl.U b3wH|;<6Bmy }l޾npEZt~]u/mRx$'yiiAs3uMv'KYJ>iYm]RJ&G8gt0_OP!EQic?LL8_#禫:}gwj c7cX_4sV/`;$.}H:ZMm-ܿqty9$0D9MĀ v"A1"|z*0u=}H&}Y 䑧HMradYUMDQap= 'K*I2Lhޠ3-^.dCs;V)K, gv[Q&\u=-Gb ChR0Kg$|DNxihhQC"l3Z5sqJTS!>] ֌4G #p.Ӽ(,i r[#DVF>ȑƣJaz *@7}E1b~:䉑d '-<+#KLRb'k)} AzW8.AXբ|Cdp!]:la;M^-;,ek )9vK_e1];ڞQP`HS$IxB{؉ [ &,l< tR.CYwx-Qx5’&݃L7`$GȐ¥zCVO-C,PuPcm^śyG% 50c#ӁgO Ô(9';iPL)Kce7؂*9%z 4 u&#Rb 3!7Ijv8|jD۶u. M+h!*N,S k@.P OUʌ`8IEnƹBu4)<*}X`0]!A(;$2ۜyy-Zkْ8qx`z  na]WК)o/+ TIJ>qSWeLpC:9P/2YNudaR$:#C"T]d8b^3H_[]y;8͕Zs09A6Bd[12l!MI1D W z) 0B xVYOGmFRlbͦs[w-CɁ: nf8tM&!YEZs;dI6J2D5VȑJwA%wH}8vTu=݁Ұ,qǖ Y;,"kI~$pзKCT#gMA6)ή CO(5JٌK`>In󼁈6e%"V-Gr)^`/"$Y+ưƅ>ڴaI u:,$~e*aQ-~6%J-xVm=~|Jm)PcEjv&&s$%|"|KMLC 5ew qMHMQ"c&5T%4-`x w S ZSAFgC{Նne>,.5;1Z&h=Z[6P291.Ҡ-@"ԓt*lX)w&B 9*TI0 ݟKػm/P6"If͙Sz;RPXgJ6OyE'Ђ'J\"aŋ&=$npl߬r}S;1|d~Dx xQ=R: jN\jcLFHuyY[ѿeYO!"IF^P~ɒ&sy|G>)f:¬̫L5-)s WYB6YID~uU}mT,q[%cҡNOp>fq$3{âGi2LYag!-`ѧkQSf3.bG ̪@D8u1"Yf(Qhi8Iŭ8Of g5Ֆ0Ga(#%Ak;HpV@-X1ZZCR!CM+I>OXOv˄tK4ֺb>q#)w 5ʑq qBkŵ iWq6"GE`!pc G!+(nedbϏ:q?=8G`W7`M"}ƹS؅Ibd(* sF|TQ%!F8?*IL>;ׯҼH2ⰻ. wd`Bw-!Ű:[+Re- ]?&#)פ͓'ƶܯGfHUmRde|Ę^ܓp(,\lwUQ?ēY$F eJ= ٴƘ+["ӕ|EEr8!F!x IΪYw.{BNJ$Vw G@ah'f#bqŢrT&YecHg$wľ?V&tSA."k(:jE{;~[;yDR͜.fj8M< = =[*[G9ņ֣93ϓє!WL\hV9F$kt5KY휝i= 3[+$g) O¡mzZ&!AEeP A kI,'#6i )θ .$S?}.'R,R/Mny;hR\ W nd*W93i'XYao"em`M~M}Wm,aD5KC`5}9Za 3sas1$\ҧ*9ԞդRux1T8Y.-y0Sun3e?Zӈ{}SԆ@Q<:X!FBao9*.gʨG>>,p[N J 51K s講K Ɂ6+d-4VZk鸐CX! v]V!C49y ") Nr$WEO7SS/iƁ1TdrхQ. a0dOt(8M2$9?g}l%QKMĈ/KvXLXLB6,g ȏHS%0C4H o;{p%uD2OFY QVܣLD("-uWh!?\ 6n3mۤ&>]045Ոe"cYy,"dt i ` uB&?Pi//j5 qjig{{܆؉3QkMpiHЉkX2s0式؍3iХv Am[q(X=|]O(Ȋ/+c(vW&}SH NN5`.z>g!S1d*Sz!e$Qa2D)jz*`ldĮk ӑ^[uTELm Ȇ)HΛ'sh3}F(J H3n@SL!rc ba[U[Г-Ln 퇥CEhj " y8؝M!GDsAi}YE3NQfpxYiJ= TQ.! Kc2wdUOUnŮ$'  (PLE,YtEWȚTp AD$*yBu繧kf^e鮺=>q lős4E"QSa{JL(߮t *:qg_O}?'8+#F;,[tTY(1*G蔒sYDwFG(&'h][%^ȹ$ 6pG^Y/&}͜O0 z:0rqdJ.!׳ r_ LVטL[76)s.@rx|݅Ut鱂PPcW+:2wQZ|=e{,e{^[9{npН322.QvIMq6mي Rn]'Kf2"%塟kxw|12 ȐBO;s46{_95u ӳ.""U">qr PJqR2oVM!΍޾3n3H;V%ſw9Y*x 2<^Ңۈ"Ou&=:|H:>%+g0 %*b \Lrnyl كgq4-Ӝٜ|m嫜42`_`U*ĉCJʋ Knxew;p{nd[;/|+Pk1D@8/wI݁9ܣm|"ƩӲ. ޞ+8$N2p-+o$FI\v/cݘG亄R{S/'a]=BV|YӦ4;;vmG,Hڞ;S̨HB&E"^$1JW+V-zsHN4낳).:5$ٗRE\HT%b+tqub?G:cKs.&FITOokXz)UVG㻊s}~$fPDlG @@]uV6rHS' klE)jf jaY;c{Ͼʻ6Eƨc< ,` dk31m,A9Di1۽+0.cgnW5%cj[H^ÛE(Oǰ#S д][H DEƩ!:Dj;h9y7+7B@Ea#yyAr)n7 -`kxGe8OIa>.ޘ&<" [o.{&g@~^ Hƚ/HXhf׈X4dD +/\hЕ>˱“ b;DQWu<ps(9Rڙ?U$Gt:'8EK}. S9}9rT0ѡzj99uӬE9^% f$y/{O [*>mT\kWcާ31o; ѧCȃjwbm,AEO֕>*ȒÐc,Mr9QMIeJ% @*ES"#=xe"c[n1?t+K)Df9f]"g8Lâ&ikH^ p _&EJIc SIva]xr3ٍ'y4K1yO Kcg_$pTbWR}| m[S$ UZ;tKLmf/ 'UD7{~8bV';w͖HөP#KR5v]˔a1O|ⲣ4-6GL46mC& g ?6]ܴsD"udhX[Uo QU͜"Y{J-,Ż0XL<D==R8exJQN4kov&y Ez~3,rgmghIG.\@=YMȃ\XJFMxO._ejxp,C>'<6e'0"M@J,[s,_wt-wiiw/MwfD@aDWc³?Rg06fWy+R?QJ4i# E ,n'DDo]ȪQJ h:%QXEa HSBf j3@"狼E˷Q˼axckӡsDv~V'#lFyCԨWyG'[ udIaېH4* %=K'EHPa|KU4hu"pabf7I;sڇ6MڲFNKt&Ϗ8=#%U<59WRrr &}">$$ (f{UY N.(uXb5ZTm-qƨS8W9;tY?Ay@$KId (l3Td' ըHewZO;χ}Ve6'!yK{r؂88_pybMrΗpwwmrPu}\vTS߶N1jo_7Yg1qmf)jos[P.>BVK2uU# u(QSO8wIʱnBZ4UxSl(^X;︺y&EO%|RכE$PQ=dt2ܑ;8iIvV [Δsxx8(mRn.2:`@dsOѭk{o);˞Aq#nWyPkuWhRRk@,'l~V>vL^މJФH/ %G`UPίVJ"Us^hek{u$BFn4UFiG.cNm:kGo0+)AL, bx ЙC4e2,U!–3Cŭ*1zfXĀ k3g1 %d=N$U`K9ã>7UUoWS d1ƨQ!KKOiӯGFRy?qWw?w!f}VC?S&>fLrnoR&/w] &5X8{T̆KH1:*fɁ2ٝ9H@>͒ձ4$xR5_FCEx$'P_>g"VW,e$8뀿 Yƴ@͒JNJEKG6 +>fDOlXm/sRdt3uivz. غ>sKKt @r-q~߿6AN!i#KU?ѡ^=p4ۣHw֯[2[_af6kY*@e]2M!OEĉXOTHr)89K2~elQ!*#5% T˖a4rx box4bEI >s&DQ10H}5zbE7uA#漘N&;Obݢvp!yr2ά2lgs7H5(d-l.| [悛5N8l1"86ٰ7"7esmc(&r۶ɍxdI_:@+5hҢ[SIaoRgz$y )+ODK23kH PU y~\_5֜"&/ebs%BW{ITvQ~W{=bmrJPD8gmHi|q[8= 0:N.khKgY')? ]Pd9hX O]AOI/-pHZP̫\m `x))2ΝbO**5b,6)鼳)qsrB#2`}ox-ɒr-d_^-~SS@)k6"wL/ (Z070WEcWb|ex~7s䞗wey>3d7-1wȁ{ۤ0T3֣6HsbDT.#G*  kXWPo Jt>Q=AZV#A㸞i&-WffPg[ ޗ5r]DG2=`GEB̈́<>1dkbp ,'][Nah4mY u]!ʏm d(d4|ܹԔ,~@:9jYs-L3)á+q ɈYd uMrrkͦD,|A3aÚ)|C94b|B:?2u)y̓re;Pm, ;R,ۀQy!YL$: %E_:)!fI,H9 NL\ < V00loǃbb-Wǃ4iq#]k X..?0G, PPZ9(!X%Qwo+v&nXio(q7p2P;θ]ME]tO,/<zE2ZeR&ԓ9Yi쟵-R&E<T(7:Q>r,2Iɲ)O[)-S3_wsE 1G?(qzIQԏcau?/lc\~mSg2Cv \$>wPӜ GOn5I9IR%q1HIztcy黴t\iy"55{Rt(t_utRRLK5Lt…帶5RAVΈLCtPP<ڭj={y}yXXZp'H_!=(;NEd Qg~m@BQCBVĜd8^*i-7vD@vYrUTI`Hbȱ /\̈́ʌzL N~8YnsRݵHvBN#OJTHu4-L˝lHv- `ō{AL|g u!mWKL9'Şd8c UrT(;r8Br7lKRnS( a\[frRD ؽOs$9r#,iJs"0? ];_u)!M21x]XhHȱ H2e p u?tOD21* 8pv>!M%tX?ga(ᑡOs۱挖t% c95RQ$3I}͏o; F9o;| 5Z=c`W1TkR㚡=U cXE ST22tnds)Jdg?&,'gw r /P!N)e,!-)XeaT9J;ӣO@Z(Ku&@Zkk kdHcS.O iE u:|E}*%WH'>'$!&r_9el!sXۯFםmW-юg#+Da ȰGG1Z=thr2+R1!gs <7I(1T5y'Ѫ(zƟQH(QD]J 5J-9o"yTQO"|.b8|=l$ 9GAUGȿ3aX쒖%9%V0x':K`||E[7@NRր{$H,v}:Yetz)cS c_.CqCσ L~O!]np eS"M#lJǭ ڐ%5[ݓ KHR19I6Y ,s4\~X}'/'ôkūlO72gRQbHpHJU>/&?+"qr )0a >qr?:{#HO"2,c#ȹcK]xfyxFyȒ#YiLᓥL5rÉQ02 Gc\-tso @6w OF%x*>4h0颛>)ߠ3ap |LcuIL5IYrB'K1 dw29lƤR"yM>ts>֤44&tW2 h:~lt 6Eȱbp+7<&uJngG+ee0^rfT,L,xla3#=ݘ4g1%'x o#@<)~_ rҔɺ 1b|B9ZǤ3{>L(0b fS|=SsIr#iϯ;ngW#EeҤNα =TiW^XrJ mEIS0|FO}:7`DvY\@@1Rx)f,N0ׂ3Gɮ]Qhw0kSBM7x $&nX@,mYB<5iKB,U 0\$~+J$e(KΉ'לd7RRU9SXp6}22bRvl!96 b*/ +q"EFWȝn>B R<ꊒ§H: [?i r)щ9;{K3%ovljܕ|K_sȓf bTb("x1bDL4EuX@,6J錈eʃIPD]WA jILӯxV^=Gk Uْڵ9 Z"p~2BŴ-|RX3kkߎ \%ih~ PQ(`^2Uaywӗ1בkI)4!ذG%4ѷ\S!$ɩ.>cَYq zk.PBi ГJz{,~i H5̡(\fOyʈlOcTUXc*IZkqs>!Sn?f+tm&>y%C9B)b"G{x@RHQ׋8\Ԅ5mcuQ^*Y<'6e1 !I9U@ieGU$ra]wh`Mo]-R%E؈8?P]tMK dUbҽAoFSޠU7`ޔ=@(\%'p@uO2-64] \w.q'c@]9 =֤'K<>I/MN[%||Ei AV@éj}7L%io y4As_AqwP&MErkS&Y- Gǁ3#SipkBhJC2dHیaz_uϨ3GEdxx"c/b.rm u !F,u2 HSiyWW/N IʊT)ht);*q*!ti0*J.UHYu1RTH~!ɓe5eU5uY;#÷^TȎH?9iIW˫1IR5Ve8 '(Ku٧xdT$M.ai>Ɣqz]5}mLF#{~lʈO(m8W! PQttKiWƢ;Q`'L9^K_4ܥr*i|ĩ2N YJ$#q$?sG~6oCN u` rIu!zRXSJyXU!hx5: 22,w,LWN$XV$9C6$}>4L p+핊QuEۂߋ⡾ڎ3eJ$y;b0N d+Rʶq炭(CHbTH?BCxZcX8y6նrH!!+NU*Ry0Klk H^B1*dyJAp<) wL|d"Ps!mE9I-CNKDԩ݄*7'u^">DCC)~ˡb1U rΨ}5}ZCMH"5blHRUd2 fbhM? ۖ'S>s9 ^F)<(?b/%KF_ks5=GSw\a,Whk$5A0Q GóD/]Yv'02&͜+Yq%eȪ ԃX88l ՖALs6 l&߮uvGTж{<4E0 Ѥ%J:vPFZYIyH⩺.PİY}BU=a#P&-Kɟ#+5l ;؉Z4m]D> &5(w0FNpmaoSv[K F4h85~G؟0ۜnƩ(H@"p:T-"t',ێq8m)&sۓ$N0[.]Τ@89Q$Nw>1B|[eE^Bġ=_[.hZ×cIe]>z̨)T1d0ٌʻ"{%zL6dZγH eÞlK5\v1ͮrؖ. =4&ȫ}#wbMMαxIbHQ6 #+kcUi-B+ȒPHˤVmthkץGK'$!7pc002!S 6Őge$9?n&j G&f,*O|sN bo蹆A CՑFW`BeTcCd֏s)ۺ [kCUi, G3r _nU6#jr/q$egE̱Kق?y͸aNRg3 vڒyGP$1\D躈{o^2Hb82Bo,!@<0HCl)1hI. 9JzQQ ږ[8i!Ư;p*/+t @^G-SIRLVh烻AmSftq.I7Q*%Nqr8@,qbItlY<Ώ*p*%(`Hs$MSMG=os.Ts8/R+spoit=vÐ7ö&V}͔r)a Ge /zcyՀIOkXE 73ﱚF𪺇,dY(UdH !Igc^ٰp3-Nwbdj3sfU}͠Fizisd5ti4"ܽiML˔ 9{#khQL C?*BǨ~k̰8y< I囎%daH֥uM$R0$y3w z- ےG} %Sc8  ?^ chJY"J(=|1K931a Bb\|q@rcӔٍjF>&KJ42͔j)MP)Սاg~ʙ1έ1{+| Zk%9}>Nrfv"6}OfQ}.HrHaB~HG-GŴky19k>28%~$j]E7\QȳH%.c0D=jK;p(l m]崶TN#@d/$M~(8ĵ*/&I%$4嵞s.WKى}9r$/*i<.<)Oe{viAQ8}ٙ ;0rӪ4ɺ/įѩwEig: cFgp*d n2ZorS F9^@QC;k9 |SPW>{dr묍HR[o%OU\\ծR"AN }2' C1s"S廲*b 56"E49jǣ@8e<GL&!E %R)QUoRH&p䭘"K^:も'+Š yxx˾<PJq\ͤή. iq>Mri2OsN6mI5'*) y^;lf-ǐSwE>)|~qRElŪ%7]]&UE7ex_AfnYS!OV4y+'C@cd% 4L%%^%3Ru<9<;Ef)j1 rOJ|Mƀ8 ^5NV:&=.d0TRQqwe 'Å_q,H$ȐBqcPX"h;OOumKX bia#OM)YݴjMjF}NOOט'@s}BY:IJ孮ޗccd=\ԉa6_m}ٌy;NgEWoNjm=l#Bc'p<kYn{+v-bi.PtEiz*[B"O coa$DS"uסk\41:qg52tڦ<'\}+L CIRlWXLzvd$1GJ9z y#ʽZPrWadDCȞ1]:E؎:>I 1Rڹ\EuEʮ0JVa!Ѱ6'`P-*Ώ=AIl3x=ĄS #*f:3kI S$fiጆtcHI!$ޜ-\tC~Oň9\ROwa[cd9Ys [6$xh荞v þ K=H0dECmU}qϙDms==T( 4<װ џ_ض,$ uRXOs6mlv{N8SYI_E!'򼍻)}EL"cIP@]˼V}*݊~j+rSGG'l!@^\4||jTwidKrSM6#Q˥l"Ps7k8=،2yndޓ$I&C,\Σț9?*Jzdɐ"劤oHaH8؅}x o4ķ--4 L3fĶ=LY C2q іbccG푏!|zǚi8$Ia(vr)w6Rx )! paPK$bq 5@7"-ϿH;1ͤszqLp/7r1?|.^ϋ9؝]؞ٔq*Ng#AZ+2cl2eGv(^p:C.ZngXN+:nr tvw bX\RmMWr%Sy0TyGj,S ?81 PPydpF dWgf?uMSN?I3 Wz }(ΣqFvۃ3IשY/`%q'r 7p-Wq.Bwu.2ZnfnNaetaeMsR.#3p^+3`s}(+eiwiv$AJĕ1v3]!ϤhC<$P'MpnyXvwر!SU4kpmHބ'@J's?{B;u%JGA#R~}~[j+fMӳ~3Ao2NP@@khTw:"NC]c-:?e(;Ϧ_prŮAr#!͸"K4)°cH~1wrCsyfYuHאd1˸7gluxוR]wD'JQL|X[Oݶ9`3pWu2 Zg$ėD]4.E1boߒ'n) gf^'"K8e 6 愵)"3絝 |Q*9.8qJޢNrgG&;vAs {`H$e3ܫsc8p3A˫wCZ)I6N{d@N1¡} }^D<1ZƣHt)s/c~o˸˹+?r Ws .2~\U377~f Vp77q%<x1tvMϸEK6; :=YH>'I,)ݺ0W̴{-')X>Z/Bz''u(wEkq F^YW QC? 12) {kNۏ8'Q f)g_\>+/Zd %b$Er7$vMYI=<ĉ=IFlk,8@Dl!78H㴔ci`"92Ƨuk}(PkjDs2ahgEEE$/ORp se n^@3D>|da؁*+AdF`}'9^ǫx)G\@`0HᅼWZI1WOqq'nFnO\͍ p!w-Ȍ7jh 9 W]ɩ/HًӹGr["ױ\Nb,Ւ=0h dCQl"5TL<2'ap0uiFtI=;g?㤤O܊qS]u'%RxlkvJ]jn)!b 9j)@R:t@wDkp2M0 Lp`N2^8@zQR,L2y3W9j"D /}Ʉ{7y^Ffғ_:t#H6HGCJU#uw yz6|n\k~3/^; K6 ![aC DHC'*nT]uUEVA`$@t_uzM#!oI>iԯ=RJv/0E2z, F)~  Bqx 7'2 }t#KExJoW mprX:pSn4jĴD˕b-?)lGN_e7\.N'8ɈE"zՒҠ$L~ez|0#2Zں˗ 8V@dQhβ q^55z53EtCynb~JShG4 i:ϣ1YD M_׼|ޥi2W0Mo!Xz~/+49 2O&g8[Yi7Um]moC XVY. %,8V@X˶z0A|PT%2x,fE^PYn,9UHFoӿZ M=Yi#!WKz[2E\3v1=]y6g3RD &FI &,h ٳ}| PDpɉgU^9X(fXmٕ-8rqN ZRg$$Kzqnnd(l:)CaCs)R).6~:k~4ژOfu4eqZV5?CϷ"beWƑ#9[XuAU^zf HBewNIhU+N$yh<'Ѕ4Q,rH: iWE7&vd(ao6/Sxчqeϗɢ."(R x^QɡIOT]ػ@}*J;JT&> 5L%c maٓ<$s)c&r?XT!B$قy<-aO#5Q!p6QXmZ'0D]dyS^0qy<ZՔs,U~ϯ|}نqIPb]v\2ScjfC\"ӌ ßUV(0 ˪Nz#p ˔*F.HM"!TdkhnE˼ē<#r5q>qnLbsF6aNِI,\xMLg6y;^t3&幽X־}CS ^CuM$.YDȈK[a aש|[ b*^/?v3 j o3j_yư-Ә\G\]<#<Tyud)H\[PDّ 8V@oohBq(q"!M6lJwA*#O4U=\,@ KEL(<<'=1Tr@Q6DJ[94w$3^OzMM jmާ$`ywe(DIXi 9HA' T&/|aVVBAׯeDI3P'F|n573CZVe\ \zX“ͥ|LS03xE$m3[r"^H]orQ\1+ <@Eev(BCm g8iq dspϱ,k^,BoQ MDEƸ-Ro@&uxgxyT6'/v 8%"zd~WdyS9/4 %qp0Bg`#ǀHHst!?Ƈ7U%1kPe0&#/d]< Y!*5觇wx~y翘Lb=,(B$b a6gp 9z[!EM?|TꏲBZ$*aifIuMǧ/(ȢsO٫R]:| ySQHj[":|MAuؐ͘ȶ>ϾϗWT ٔ1tᐐ vHB8e 09/'xBjz\=䏢WV)"j 2p{E(yc!b t9(b#dv*·em(%$q*<5\M;; X֥(/3#q$HcS`6`<[ ;2,q:p%kY*Shל|Ui[ƝiJn|Sut s0.8tb$),"$ȣ0$Ctx9WiZ6pJL}kb Y,U^, 6+j4o^%>*Uqjp?Qh!?<UͰޡxo`A.idg-C (ҙ~)?-)Dr`%VJW5Z)HB,S:*G =}j H J|-ʪ^-|M>AI |\2X bgp %#HbViQW L pʧ7[瑯[! :vT06Y$(B1\6@HJ8 YݧVTkHɣRFD29ټˁw9̈́ߩdЉ 8:@PcF﹢qdw#WXSfOLI8фI%+~UisǚkH%I1eokfS$JjRƤ[`YI'C\T.qbrǚ|&E}Xh;Wti7/qs.gn!^M\SNQBMQ Q$ Yk@PAy\)Dk ;W:?rA$QdaghbqXLHEpO@`1pF9E_fH"#28IbS%E   8*c-x4r(:Z`n㪆fDWm WBYc\AlBɉ 2-ppVj#s*G=cgv2qhq@qDe;W[biMjmm~W!==' Qȓ!%C.9\2ihi=/ɥy&c mIa %K И{!F cAk+ӣC^<^ y }`-$H !E y\RDHK $b8XdG \{]y:51yɇansɅOr6;GE, K t Dɐ4 ŶR6Y:1@' \lc_2mY:K2:m݋(('. EyBE (2rX:0;GN$K f;>.[ JŎ<.'F?}29%¦=v}eF$QDq(y7ʑGiZwXrr&BM*p9#(!-Gd g\OoX[mSF^bb b(Ҕ)m86y\,$q(҉KJtaRd{5& (ҲIJQ(IRiFcrlRng¦X;#UibmwF:6ȳ{r2WX o.g ,)8dI.ٛwqw\$uY[~Wۮ:BF )ף~n /lۚ{<år :P(bdppȒ 0l,9#3zϑ&i%i lž ( @kg.9dcQ$MY"(F5a1%٠OVuU,!|E{,gEge ZKyM~m/4sXγ\dWF1"ķ0#[no4Y8$H!MHdew @>CQ KipI"M0\v$ɲiK`r+Xx؃+IE+֨/IxőG<$IcxA(Xdȑ&I0af/P|]0y:%&{Y&c38y%z`XE@bEC(MXy8c !-%D&;rQl 0S);ǘd:&Hf=75/OF9'Ymќ<Ӽ)it=6Yk<#%f#^ E49rIzGaft.q!B؀8du}7E%G\\,ly ]KR[v Ld<͉Xlx2WaH&E y:媔aIv50C8f2G[~@Jb<:-SpH#F,9\K:\„j"LzeQ.>?\İ)'E\oaɌEÒEhS$q%*+!+g+ڑ+^ZMdH߲rm!k33Hc$9 0 @>qPE]L@?aZM> g>wBdu r$Yсv0l f]Ȯ8RHg502H#Ax33|x#oT]2.LaX Z>PtǒMuKoĖEj<2ᗣ=*I rZ(29M Mu*_dcl[H`Y? =xZdY}I< b51׀Ԛ.c>{2uէ5 ̛Z,dIJ)d|]85 uuLfc!E$ R QXY b> S @L21eĔ)S @L21eʔ)S L2ebʔ)S L2ebʔ)S @L21eĔ)S @L21eĔ5 e1mwIENDB`sprockets-3.7.2/test/fixtures/default/vendor/000077500000000000000000000000001331222022000212745ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/vendor/gems/000077500000000000000000000000001331222022000222275ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/vendor/gems/jquery-1-9/000077500000000000000000000000001331222022000240525ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/vendor/gems/jquery-1-9/jquery.js000066400000000000000000000000141331222022000257220ustar00rootroot00000000000000var jQuery; sprockets-3.7.2/test/fixtures/default/vendor/gems/jquery-2-0/000077500000000000000000000000001331222022000240425ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/vendor/gems/jquery-2-0/jquery.js000066400000000000000000000000141331222022000257120ustar00rootroot00000000000000var jQuery; sprockets-3.7.2/test/fixtures/default/vendor/jquery.js000066400000000000000000000000101331222022000231400ustar00rootroot00000000000000jQuery; sprockets-3.7.2/test/fixtures/default/with_data_uri.css.erb000066400000000000000000000001171331222022000241020ustar00rootroot00000000000000body { background-image: url(<%= asset_data_uri 'blank.gif' %>) no-repeat; } sprockets-3.7.2/test/fixtures/default/zeroclipboard/000077500000000000000000000000001331222022000226365ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/zeroclipboard/FILEFILE000066400000000000000000000000001331222022000237260ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/zeroclipboard/bower.json000066400000000000000000000001471331222022000246510ustar00rootroot00000000000000{ "name": "zeroclipboard", "main": ["./missing.js", "./mimetype.unknown", "./FILEFILE", "zc.js"] } sprockets-3.7.2/test/fixtures/default/zeroclipboard/mimetype.unknown000066400000000000000000000000001331222022000260760ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/default/zeroclipboard/zc.js000066400000000000000000000000231331222022000236030ustar00rootroot00000000000000var ZeroClipboard; sprockets-3.7.2/test/fixtures/directives/000077500000000000000000000000001331222022000205145ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/directives/code_before_comment000066400000000000000000000001011331222022000244050ustar00rootroot00000000000000<% VERSION = "1.0" %> // comment var VERSION = "<%= VERSION %>"; sprockets-3.7.2/test/fixtures/directives/comment_without_directives000066400000000000000000000000471331222022000261060ustar00rootroot00000000000000/* * Comment */ (function() { })(); sprockets-3.7.2/test/fixtures/directives/directive_word_splitting000066400000000000000000000001631331222022000255450ustar00rootroot00000000000000// =require // =require "two" // =require two three // =require "two three" // ="require" five // =require 'seven' sprockets-3.7.2/test/fixtures/directives/directives_after_header000066400000000000000000000002141331222022000252660ustar00rootroot00000000000000/* * Header *= require a */ // =require b // =require c /*= require d */ /* Not a directive */ (function() { })(); /*= require e */ sprockets-3.7.2/test/fixtures/directives/documentation000066400000000000000000000001271331222022000233100ustar00rootroot00000000000000//= require project // // = Foo // // == Examples // // Foo.bar() // => "baz" var Foo; sprockets-3.7.2/test/fixtures/directives/double_slash000066400000000000000000000001251331222022000231010ustar00rootroot00000000000000// Header // // =require "a" // =require "b" // // =require "c" (function() { })(); sprockets-3.7.2/test/fixtures/directives/hash000066400000000000000000000001021331222022000213530ustar00rootroot00000000000000# Header # # =require "a" # =require "b" # # =require "c" (->)() sprockets-3.7.2/test/fixtures/directives/no_header000066400000000000000000000000241331222022000223570ustar00rootroot00000000000000(function() { })(); sprockets-3.7.2/test/fixtures/directives/slash_star000066400000000000000000000001311331222022000225750ustar00rootroot00000000000000/* Header * * =require "a" * =require "b" * * =require "c" */ (function() { })(); sprockets-3.7.2/test/fixtures/directives/slash_star_single000066400000000000000000000000501331222022000241360ustar00rootroot00000000000000/*= require "a" */ (function() { })(); sprockets-3.7.2/test/fixtures/directives/space_between_directive_word000066400000000000000000000000331331222022000263300ustar00rootroot00000000000000//= require "foo" var foo; sprockets-3.7.2/test/fixtures/directives/triple_hash000066400000000000000000000001001331222022000227300ustar00rootroot00000000000000### Header =require "a" =require "b" =require "c" ### (->)() sprockets-3.7.2/test/fixtures/encoding/000077500000000000000000000000001331222022000201415ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/encoding/ascii.js000066400000000000000000000000211331222022000215600ustar00rootroot00000000000000var foo = "bar"; sprockets-3.7.2/test/fixtures/encoding/ascii_utf8.js000066400000000000000000000000431331222022000225320ustar00rootroot00000000000000//= require ascii //= require utf8 sprockets-3.7.2/test/fixtures/encoding/binary.png000066400000000000000000001236451331222022000221460ustar00rootroot00000000000000PNG  IHDR,K9tEXtSoftwareAdobe ImageReadyqe<fiTXtXML:com.adobe.xmp pmPLTEjjjlll ޼pppzzy}}}uuuܹddcى􁁁+++[[[SSSKKKBBB333<<<$$$rrr뤤렠nnnԘ ǀ||{xxwppnnnl___rrptttlljggfOOOWWWHHG777///(((g-IIDATx콋[X>@IQ0Y5QT6rDDZѢ>ޟyj=_>vi:3׬^{kmuM/#_/Rͯj~巖_oef~=jK7#(sK7՜EEEMj" K'DUEZTt$A<'j4:pɊ(x~G~ 3y;m :~W\RA7t{ ÐYT0*zV aTiNFw wHoF%ڭ.u^P]P3ڳa TA7Tc5#"x&ͿپKLST>² T=T,ҽ*i hF&>ͯl$+2'_k¦Pdx&)e ,5Z-20$uQ8,!L|tg+~U#0_A{IDނdl]uvFk2߽?(jʜzT_nײمE'uK5烘L&߷eK?FBO"fW0[[Cd .X4 bɐKG-!c3'dN>׫bMS,1י7^:)aYSPS}TC^Qc*tuZyrA e{xEm2„#F.0Sa穊ȵ]5! hॲxej2,i"V{xj&Y^ga@pUm , b,f٣op'p7:_k(xnk|X"0e>Jj9+30ґ׾^f.=s[YsIT{><1Xͨt6ܻ}:'.&Go:fSci80b/( |`Օᘷ!V$U^i>3vڕw&߶gbkS9#OU | jՠSuz66hß6_w) W媩HZDX0$IUv2 GdC'=6F9Fe zxpVbLJ Q8um>8pvNk؂-skͪ돈,"oƘ Jeq|d߲ {F9Z{T=Ea] ' UiNM.O_xY*6C(ӄj"~b>UᙵTUc0=! 2\or>geP*(ź (kk)7)(`6:cWodqb7'ۦEmܝP/d/V͖@qoC;W 2T,Trļ ZK=A ?b|=Lfnb č|x!ف|ܰ ߣ!)·l^'Cn_7 Ѓ ? s?[C@^V:®nX\f؆;>(}U $o|-Fz#FpGی4›։BS[og!؆86?|H9w z5&MxVU`G8$]sUЄЯv[ HG{1;WdR`j"WR8,坦@oz8s x@RT,ZX)˲^BQESTb86|'hM?OmcWOsUѝkwlogq` %8!DQ*# C @0!R V T0 ژ @w}3];\\arsUӬB;{pNp`G]o)1w my[~{=ҹ`Bܶ=C|sw:蝋udٺڝRtYˮ݅iZnơ-by̐Vhz0vfp}uU="WY߀ޒij2uגiWX'C zk孾>oy;O/3@;.ț o7t$ CZRS'\@|3+y瀧gTO>vZ~Z}Li/23 "E4›G o: ?0K`oHc*k鱚r,=Bi*6R+9 D\*$eD1W]m঻XbY t|OyG/Vv u|%3<e![7/Lu sA8bne6Ab0ͲaD4gYjy xsȲ3U?2۟p@B/a"ץj v̈́Pg># :g7г<9&B[LO ?t>;zwEH& ӑ-3]# |D `HT$]Hj 'fQ8m [mli9}+t݉kJ' Y[>gl"q o/fX' (vmض6;ml~ۮS*sk<#X$MBL xEXm'wQTښ1{.#shl9:B7*cӴ{v-g̟Lx-m@hۀ́0aŸ1έ-tfvvFIF8i6Ge4^X3:kb51?Y5do5HU3<3 V3ƖE1`t<'@ Ba|0S&$Vba0=.]>/\tu)V\OKׅF%ݛ|pmaR4V]Iš!Mŋ T=MbqLlwŰpfQgcv&ۼ!&0%¥e4${ՠE W.i[Dhg!1G;Jw ^%El ,oj(&*Ĺ!imwv47 f›%:z6%`;6yJۯޯ>`uW%tPhLFph<^|FIpDROUTtI\/Q h٤TOhb=nZ6aؑ f`*Ithq:Fs~$D[~{e$J&OwW*og:)6pחs}(_XGܗD0qosڶP9%w_ vsN8gݞ[ߒ϶F]3K}3s 1ITVWDPq syݞz ۠pن@zpǁl$p;뺳U[;|Slr%ݼuIp`MF8 @xFh\O`Tmr_=t/[ {D`{FzJ}cʯ%gV_[a:Ge߀LoVWQ`0Iϱ~/T6zI@ 89acGwwΤgEz=p̾A}P?2Xz6k'Fvj|8*sO}%xKa mD>*2l8nx|h[zȷ{x픧fY~m^ϱ{;A(=p x6Z@ۡB-<*h=SU HST9{l\*PEƯo1n/cE0Ÿ"r~]Ax;vmB[+x!xt7k{Å¥m`!W(E(vglmwbvuwk i8?o?`jA'1"v77]_?{7CH |v ZUfܹ϶yOϗ! *qhg4mWw[/8Ȅʇa }ݴai/H,xnXf_ٸ %Ɩ-loApwvmK=[?g "" Lr[REҨ2u=^FVxde]4B9hG!77}G ]uv*kM|(Y^Eވ*MFnr06i#b@o,g=sø{/ 7~ܠAck6ModHAD$U:4MߊĞU, 0\P9u ťer0x̲, ozXvZ#n?._6aX>ZN/Ev?HWi?$;75uxvvX6Cc=pv{)ve=se}=hTE7RUHD:6Cu_CJ!w5zRgx&=cA=!7}~|uٳ~R!UE$֢6&]f `ai:֜_I߇mvέpMD3[Eo)Daw`400[N7B]U8a ^0,D57j l~[Yݮr|9!Bs&3cL@n6VAehnBRa4xk<ڙ@HϻԄ i#?Qiz q{<Ʊ~a^F aBE'{U&ZjֹBƘ"8xj of@=nu'̄tIUb+oSOQqYlb:J8}!h)"HkDCJv0Z%a/U @5ׄ7yu~ o^vK$qQ􄢉 TCMXVz  M(dR7Gq)kTf-fvJcR= ]mv?b)agb8c@'ԊM9Eoe:-g˾A7O|ecvq`*]3OnSWܰ\G! >mGbw(=lF흧۴-z꽟{Q(e%,Ih-*Q XO#93䂌"t56 _x@`!|vx|w'omm葥jIxqZdQsxd4M x=;WڼL܆D/ƳмwIfUx ekHxyfT6AO~'b!ȫۄ2,@+2zь͞A/M(F&|W?hosaQaMx3f H}NMgs@x3eDxs1]z 9<({,}Y {WE-0Ҹ;m#a R; ͆Fгio66m4/-[ 0MaO $aj:0Ȱ GS\pT5j -J [\'+1&6(P?{]qZ .tUE͌zL*ãSa[_}}FrVQ@ v (l&2H6&4 Ꮻ<'U y6Z 1m숻SĒIMKd):j+$!K0hƅyޜ B(VnNQ8Q5NSJ7ϞĪ0^"jQ T&J*@Hsf$NLȏ7Kd #'.jRĒ7L,eMx3H73Ɛ>ah 3(wT^ &h:$ Ah" g 8(j и o~@*g KuRb/?M8 b,2x( `U3!ܟ9|7K@wY3)9 gMTj x YuGPc#RZMVPh(&4ȿ,h//7D>߼@on7m`n1lm]gtN;ڌĶ{s4:r>M`ݦn8BBX;]kz 9YՑsƉ4i@fD/qB#D ?A5q~2J?hC֗Oӊpqt-a; ,4ÒA r 4f|hװN:@͜CxOo3]%FO O5FǛ+s3W"5f/B=l4sUtИ;A/0HO AhB[p4AEgeD;sP97Tn#(+oTx JS'qHvGص(?6iP]KQg8cJ+1jb[5N"eCpҕu*x,UT?JMvov}!zP}*v(|Ç+34`8##=bU0Ûb^5/&T2XV 8LQ QA8µ}x60Xm|?en% Wr5$Ti\?(9~P5tRp(s|}#)pBh8Ni;onhV._.`jpƘzӤ8lll.TΓǏyoL%dj, EB`iEx8}7(ik|ѵh{ݶ#~&㏲naOS}={y6xK"xEZTi>[&3&X*G wtf9 _$fF1h07!;u u2A|WSjo n›{%JIX/oKƽ-] ؍;[ێBg4Bn `;:[VVϷ熆:SSD-9lxi6Bf)ā=#@،1DY#Gs尭=ok裂$pXRWNM ѳ]{sp>%aN%P!FہM Y ۴9s~ar RR$P'+Ffmޠ;5Y t k;Zp₩!2(,@PT]W^2gVA@V-p"D'R۔ȑzi"T3/D^K"StWE"|A r㷓|nR VQ$o9;23C2;TRfd)!qn J&&Ʒx Paq.K3)/[o`[xYSq\U QV#4qԿ$Cs,~&|J£OKQS/.``)jf¹; xXYֻFQ!E1Yj#&eadȔȧɬxv潭-˂9߯z'p!J*9 v\ʶ.t9#6EJq{uGclИL4|.ʽu(L%;"Ř ,p:رjr2]KTqhs"3WpzLL? !pQhogXԩ#_#зP.OωT֪|O#ޜJ}zcOyj8׍}T{uA%xXj1t za|yIAl8'AY+Dt֞_|NRzbU%Y/Sk5»~MbkTx7ڞijqD,KT'amk%9b8Mn}Ѱ146gr@9YfagނR_Aߢ48amL$|}Xu8m,<.negfAp(rKدՉ'2s3@ުˁ̂HvԁU v4[XEGdIR9}P{ ö}k)u۳agล=q'i-Mz.ސD5#!iಆ/2(3uB՜M .OosOw!:os|xo#B =q~Xc/ DHN??Gk"f %#kWx#+)=kyWRmF3#X'mܺl76Aw]S*fl@Q 9.1ubHj%8dNgsniw+?i$~{KPEzM/tpN׌9CcNOw/'{gݲSIH\jyDg!z=dLco}˅8X*׈h8>CzLZLQ1ɝhLoooI o4XWVsJb\ 6\o)|}j%<?y1ȸ_37/P=IsߝBlԂqp櫟GTlvg]ࠫ~0_Ϳԫv#DDF /+NbŊ 'M[ŕ L5H~_Eu}9j$bv=e>琰i_cm@xs/#0ß7~3+Ҩds $qu=L\EՈ Z/ʅAwrϦ;Nm›#|}v.$T'-42oˏa\iLT=+2- Ͽ,,9S_}j`udRu}asw8ѴG2j96ڴhpCLvMfCU2KlNdj£R BX37Y?b›%_Є7@p}7]w7e<MU+ a4֪'~D&)C0k2!&n+sVZeտW^%skgoANM7MQN]cl>kqx4dj$gNQ1(ϾxIs`Mn9 xHC^cg-`›k;(OapcQ@f9h[B1]K.j_s kT=':Y]yhzXv2nFtcDy{d9%ivDǜt]tG^ޅF hxTExzY8?S  i>׏N46 z[T]@vlfBDE -jRЂ/@[WI,BKž8wh|\LwcSTu"u14bO47e23pcuA$5D2+otQ"X>T{Z](#y/dBw֊]N ]M`,u 6&___kaVLTLdq[u(X)εBNWߋR1ڗUd}B_Ӕ~N쾨+U!UUTؤͦJVFm8w` LΓ5+b9BtF곰ə'dq##UHldEL .KjV4V\Pȸ鮷@nQm5){8ji\\SULNg\~CI ;sNfO6|G̢-k#[Z|ypfT&SiG.2>9asI@I:ܐLfiEΕC0&fjQeE&wͺ ̩YbYwG NN1+{z q~ LYژj_|i vU3KXHt'%TL;;26#2",WXA@bN 9AXg*m3Tc\ O@yGvT˲XbaR#Z5xy kG̋_fʇ,]`/9o`ݓb'1kOca^>$n,ʻ䡈c^Y-ObV+J&z)y;`dOQ7y_CXVjYF*554QѸ-Vo^|5, rݤ5' nH.}C B !14Q k ;s̞Evp=\p@FyuZCR"kM{eKd7]m)&^dDF)*r˨/7F@dZ"S(hƠ ^c UwBzf=e: RcluZPrF,0"!?f[cK"C 15RGg 59xJ03` I_;"C a%v |Pg"Ef.vVly?ԓ`ޗ9J&W[HYDUƁL5{`gtYXxITcs6)ޤR3O=a4T6"fᡃVWOz#<*>0W:C"DQ8AMT׺Yod~;VfU.x}Yąz(.W4K?O59'4 :]88.9! 5ikx,RcK!!?bѓm، $_>\4`I]zk,>ۦpfV/+SR}WlB@g堏=ZtnjEY0Lw5nFkp Lg`!/"ZM5ē w }KaJ7Gotk2-޴s^|}l!j%^GԕG>X ,Y*24W_cOس).ezV ܼZ}S) q\-kl1|TUƞ]x\XUR0-rX S 岌'v;/ Ւ9Xa/ 6y(ijbu] T3٭C{Heq2)j'9i2 jH>xU -su&l cA+fdDhAI0 ly1iac`I=mgQh'ʭw"%.H:^.3n@P;zWͣɛH70w],۝^E<|sזᶨHsY1ų'hŗ?ϒU NPB->Ym A /7<5s:x5-[u Nxfg2l `{ęsނ 2S ,"' ,2w[u}=|o䬅f>"/Ջ3 [0r][OsUC '[ "+Dkŀ QL3|д¿Q"ZJaոY iÄjU[qX5vGFh82>dϋ+A}}ԻYrLG*|]8Gٕ +%O z!Hu_9t[d= T,hn?Iab_nɝ8>ZDNQ[1դ&u r'psW}%~}"z35:W1UCBE%y<3$mӤeXZ!džjBDMޒ ֑::xpSV,A('@N>iYLwdQT M>~]+aןV ?MIЄvwxk3ɲ H6hh C'vpbA<}U;B&^ہ~JJ:QMIG܊ ۞M?S3 S 9㑏et 9uI3hҟUM71 `y {mC70EMU)yȪyBOj߈$>0vsykHo<>7w`4m22UN4u߮Zs[:$< 7[Z膰W-82 !W,^I98WdCl>=º{v=o|C[.ྷ8}I9̈k4XdTSV[xT@\0jEaI,]`hq#w0E+}t AzpO^[:[FcDe:oQT#c! ӱX,QzPZxfmquv*Qoh$4"}}~Ot 9a:^$: X~ؾtLIVǔi: e,Z?_MtPDdg9FjtvZc?Jf qRoV'}l[gS2ͮө 'cidF$Tb^LYOgP_FHF5_;;~홗o|XS)x ߜ֍8>G~h g& ~)pRE蚠0;S 2D*YdD.y3_~Y|]?,\lg.fËo̖8Y 6PMCz*Z՛W/za Mdh̾k] 0hR.L۲Ju4<%Sy|R&kn=8^X ( jk;pk'rEV&ao87岄D l~InةgG!A e^:"W$5"N]w\3Ul\ĩZ`4uGl:_Q5 UPT6-2}>_tjA*Շ&'p{ RY,(|äCx!tfG-k5bO>bi~.(g$fFcki Ɂ$ Д̀2.XxzC͇|X!;4WBΐ1V.W/)b ]7hAkkxs'/2wlmxHyEfZi:W6=r:\b]}-p/K|PGt/x02 -k[TXlDM3fSA"@|``p(*zPIJm]})Y+vi{Szo9ѸFT9 䎅bec{Ƭ~M38]"*)ԵD0LrK( -G9_0͐_s&Q5fVc*\۾٠U*Uf䧻Yjl*fxjcWI5vr ,,z)-dz,'+Ps(mYd$6=Ȳ;,p/6$ZmԧT:/r wF7TMjDj/[L cuK+K2yx`@: ! <EL, yƲ8,zٛmAm++hOyX7 KEE]i̹*,ΰh;r<BÖAHwHqaUhK}_kvom ؠ+5,J"'_wm0&{猿93ڮ~ߪzުd@ I@}'ԇ %f,hiP'q&k䝋}41s6 /LyscV u73y4Dd<]ͪ^ut45_$ob^ lzQ@K/Dwj5||G˜Kh,Fa:%gJ-@Zn"ʻ4-]!x3гPrޢ߇Z)rHo{07w9[2oXWoYt?dBk^kl&Jy~ .~>+8e]q Q6>ۭwbYLfؗ\Q4ɕH61Mk7u9phsޡMUC5M#EB %Z+ĩ 3*l\pq8.&)TࡅC K#%"(lAQHrda6MisΆ- s_rㅸRJ,',_E34 \X'[4M}&o[^Z+ei& ×I? $WmͧtH9}1Qh72qK%=*9c[.P,O|\9 b!W MCI|TXګĿnd,XcF %<Θi⣏t@L 84+nhY*FS vw ؅Yo  ̳1SvXXӐ|n'lJ-~&nӳ)Xs z sU!'> 6ՂE#NW#v 6]q7M @SFIȕeگWCˍ&d4F3wi&wXn| /=§J4M}Jh|TS_=y` \EWNPm:BvRu=#|V2zY K2g~u_")adc=OIC6H,gq>bW-2Y=OyYa`AXB.`y r3`{X5W_͎f%8c'`!u+] e 囕T;>@Z]tznIx'IiQWEbPN;QzO0$1]_52:ſe&Az)kfCo6y>)7Jh˨xoӛE*~ؐZ/ei19Nq%Lwfx|9fx1h((ZEn9uBВgw?s()?cuiꒈ.KKv3HmRS4ЭjeIRgdH5KA-lrwYCz3~DkҒIK=s~LRһ )d7<Vtv20dztK~qB$*pNWEJ fL Φ& -/S*9} X):>TPQ*6F䎺nI^lH61iY!@_x%fC k\uoU|xh4 uߗIjql ?6MH:rx3LJΉNJP Xyo: gD=v,RP`N_m`P[jjUk3|yi[ﳩաWXMCA~Q;i_2np 6I ? <$〶= ~JXkGV tn (?mςh\3i40,z3fЛo|Ebry wN1r41KXrY^s& :NQϲ%GY>("v,km MC+%й՚fͰІct+C"y=+j: qǁpޤl_ЛICEpے\p`ޡ7 I&L"P*퀛fd4o#rJ؜DXz_*I4LƻyBiQ@Nw ϰB)vNX嗹6gi;%Fo\X,FFo+6UkS|^$[HS+]>GZ֡#Qn<.}U#1 յ,XwBkY:R*zZVEF ykfJ\qǺ42k?~4ZEׂ6k%T! 6oM4frTzqqמ*kiB@0FNZZ8r$CvSoR?nIj3ed:xdDV 9o%*T]^F͡(=~49k)[=#~Çs>fNGJi7l/j9Sx?p_!5,_q@&㱉FWub<&:-jY!Yhms;$wk!FKs7GirpónirXҮRE< fb[72W>Uo>hDzKEٰzsF]%;RRow!ab.{]E4Yq@uKjbIA\bciu"iN5H<<;b~`vDK'pE.`I&81lyQm!޽ DoSiZB̑"lÕﻦFR^t:d=.ǗD8Pt[865ih7P^d!PQcV3ڗ^4;WA媊&IKi_|m)>(?+?Ж64D\@BY"ы]SYF\QWkKH󔼯 L3ÍM=pF@vhQ_]!B#m oY&'?'_m[ov8~׶wG=q-ҟ,}4V$f^lim8a$7MjeIӰNI$%iI+<&3S8%xJi Z[rR\8`WB?C|o5~DhUZMf$AvLM{&߈48YWgX3-[j"H$u-c h{83@l)%daM9sxlƊ#De(|V`#G̸[ $r Tl8lxܘw~ ĠlW`Ko#m ygQ@!Hq"x&%Qcy/(?cٍ^9x8>7gՇ,b=ˆjn\3ATJ>|f#wH놜PԢn4oB QD?Mz=2o.>TKw{UM$XiFOԆpG '`+ɤDpIhXx_D }#kD%r(HhiɖhS1%Ngj,4ײd4uJ>Л76FL[ <83Wӂ& ^ =J. q&WVrP/dՐbauCaPXQ]_(_!Z r" As #~-c:B ^ӳ՞$!1{(fMA@=t Z⹩Q|3#7z5h 9n[٫c+sju,[WmOcEܪ .TYˤhkp"ug$uX#çٔX.iKwVG2RsРgHE7׎kP]UơZF"[67HEʓiRGDiR 5Id4ul)+B#{͉ةa|2 pN!yNo0KX`]IQOb*iAU C~5G&߽\8Ms6ۭ&Z`[;4g5{?$cN7zhb~bncb7u 񑦵LyIMQ԰wBDZzE b.y]* 0,#bEJĮG WJ$j;{ML~G$啵g:J$i ĹstXPh:kEśv8xewl{l;Ht^JȮ1ҫPO&n lx(R@9رa>9 uX=ƭUJ:!Y&GMJ({ zvYgG.i"+_mev@vcymmYVILowkӗdȫ% 7_ / ט& dӬ҃꾀n7c^Gz33~xhMD=AYg#$+oU6Ud4uzu[4TZڬ|PWYY$?ջ$FŸ2XT )27/Vh aaяe!F0—GxPE)ɝJ ;!dF57}5WҏDEfGpRi Üb€7\2\ZZe;]'-8\e2Iz9NfGz/L{2Et!NߘI:oKL3eD$.[|smn V:)v~E< Q֞=6H\|״x]4:8^`ch,G3%\4 II#oc\֘OOtjj?~OwZϯ5۱AiC#,%l5/d&&CWkRI3 '}m{oѳ7S4<_s WvBʴ?yڿXc6D^3zshaW-!`~hMwΕ-쇷hvtG%?ʻ1o'&XPo>74juCVU__8=kMU_􏲊R5ͻ}+'8i F <ݳk""BQ\e`*lh=h` ;[s`s&,iJ跸t璷e'GY,18֘ >8z$`ҹ/j s3\FC'9 8A#$3y_>`m&Ϫֶb&foeި0gy 4r&]57UZG; .{مwUXY *n5zy(H" ]d+]_Ci=]$9rCQu$bsKEuNf޹~O?ec9ЛtO&m<`t_-{/y OETOIA zA혧|f#D(]hc&zp/}^b{ s\C_sAMfŗdJgioZ+Cj 3ZAr*8]-A$_}ez)_/Bt"Evlħ=Ch';󷅼hW쯛q)?˫y}L; X7zuE]oZ*a>Rl$Y>KŖ^pvc}h.G1Qs1K<Kn` |ٸD<"6'P50So+Y~bci95_#v`sX`.Ȫk&|mx4X']&uTsx1"]o's C_yӒL\QߎQq_7 F͒ AHn)Vwe <r3vʏ!@y6tXXQ1N`4fC1enm`'[T OC Phš(ٗW##WA {> 3(˲EzӪ}WIM?Hnb' !p9yݍ⾧zQWپPHS& |$EۗVB87}Z;/QMs@c3҈髋nk0UlVV6#۞ƚz;^%ie>揅GMyo5 hc̺k: /2796 ZSkLcia+g>^8=;m3!O)i=5e.8 udn}y.'e7ڠLF] p+h 5Lcȝb өRI!:Ib[zyUJrﯚ&C4{y-M1qMlF3hDz8ٖs p l~pf)ϑgN;9-jc&9L08ۃ ^h-ka?}YC>@QNuCӱE액1r@EuZ85ڬz.`VmVv1񘋺h0z3`suZ!\y$+:g=һ[4ޙu^Az:tCݾr+1YzпWLDvo RjHr UAa[ æ\gbm*d&4`:n'Vi<.2BD3h1Z6>I5lhYЛs(=rܫe33A悅k۲–z*\V7Ul 5'0C]2qv nd_q-C Ov4F$ʼn_0u'n&A9 nvj .}$ {ЛMB1y &E!NuMMVTʙF ;x~+^ 80`CoNi^47q.0\9 Iz@\\eaWߵt 83:g6(;%6!-yBkpXH*Gސߠ"F2o>Gm'zݓRy4 yd(綰ZUd4YE,]$3;$>k0:Y*cWA@q_`1wOxG˜O#Pa=1 \m#p͛-̝ᛁr٨qojp~ӖS~M]/f7'|"Xm 6~6$|9crK7UZK-Iaͬc);U!ԡ7MH7 YAz37vDMBoZ`CoFS ꔾ%[ U+J_޹4FfGf IeI׽zϢ=se^`P F~vOrU3;u+}~ߝ&~W;9Rݞz"_ύ/>;j4SJvC?gMvyrܨ鶚>psG0 ڜWݕfml{AVI7#7cGۃA}pͱhfncM> lo6czcs;>pLxn"H|6,Fܪi.3Fyn x;u3[j_#LM伾X̺'& _sF%FB3X3^N}D͘#L8A9VSG.x49}| 5Zw8:\Ӕnx6Jڭi|QC*=`T r]7ymz3ڡ7( Ku"|tT[/ xjHoXhT[!f!nH@ ^rw=j7; " tIPTuiIa>c'Lw[6ARU-ٛyCEnwP,jzJڛmsEVe& ;rj\3gGgA?r7uif WMfsFU_qFZ3:4T]_Qq[3[Ztc9u{ș5:=cfh,k&X@u{uVUmӢc0|w]8MD'"hiK {ҍٰIӦ)< RvhgMk9v́` V30䞰 fmh$, @٦7y qHoބdf4]NIg6f`K k> ̥3 \~)Ѵ^l-` ؑ뼄 \"hA,B6*)- nA&1A U\RExr)%K I𝩨S~4uVƕ ٛ2|Gِi .>g16uf Xt` HH7پ#}>qic.OuD6ty! f=?0PLTͩ, #ۡ3~+g.^EVt"aܺ1+A BvD7#5n-謤i%˫貾 Fc{~y9\>\>"ɁxVd2 >1Cϭix=1|uJ+gGg|xrZZ^\xVi4Wdi?w CHh& `psgǹpLJsF%.0llC!7ِKP ܐ>zqJHpBnP񗋡^u;S +7![e fPE`t^K_C:p/vߐ[ѫ:~EP 3m%TO{nENzS%镝LA"V/k=y.u5 ` I1خ%?9 QԚyV󉚥pmL\6̫M*aTs [1Z\vÃñ9SP`}FflҎBd'UOࣵ/ 1R;AuS+H``/{JU2 psaq:ׄDIVy0Z5͖@2Y~,*amʃD#%<,Žm+*% 3L(_`}낡(f3e8KQFhHPRAk P Q8bu@a\@mQ3ru /=RU8e{ak奤DVX>ij,lak/[ƭbއ%ILZA3tµ-C2a쬐ꄦB> ~rJi S7i +v/ßoT44$f3#;Ja4 2dK5,` ;Lfb1_Z0OJTQ>)9LC~i LB11|< Uؔ(" :D칄Cm[ =Ic˖P4#RC됫%]MdM#nцEt#idmB;<3R@}K{C[5@f"`tw:6u#(~ u,ۿccnl`onh:#;VLm7$29c(*;v?)X${;c0"ѝ*so,"bN 2}H_1'IОWϟ44V$Q[)%i+=,/K$R'O Fd ILqM{B:W6Z .'vyӆJԥ/l*J^-2Ο6Dk]z^]ʉ ߏڽ:SՍԪ~nWtF7Q&sW|Wpwm7SCop}3R9 pM,ax˰wؠj0uju^MUoI'= e SsLUrRnU_$?Y__@ E'MɧK[Vrmv~X&ӏjöT<Ф. xj10`k..1MdTbd5h8!m4pe婰as3R]5r+T]AiiZzfTFʰH Cƫ>BMܰ3W(se;f"Z(E@D׻0N7u{d@-= kCCnTT]ֳ}3rV7eZ*EֆTvy,jqϻ]l 2}b(~.&)BK0izIsP5DR1%?4=]oHȢŦ i-W8^.ԁ9NMwKQS  QgR3OPq,׽k] j1[97L-fy&^a|TQF8NAk<dT=5c= pf ejY,bxʐ=`z)3$(qOӶVuzfO '/_2QMglXQ{)69eil{xm3JfNEk)'6 >rv6O |SN犨(I5%k sA&/OhYoWB:=T-nZꭾRd7y ҏL\ki`» Х6bLYtgpqҏ{l3A٪ 3j?`#:lG7/=|x]`.>\|_ێ^Z~YulO1-f W9燫̬ǜ9̼2`m8L|T+mO\I&pצ\%ӨC?mϮFx9Au蔢CR`W*yL׼8!+m`iMELݪo(mUe Wz^*m?ffw6j(7LPύ }nTc,ъh* 4JH/g$~4? kL$j5=:F`֥W7Cf HĕAkJ_8y;'m65Ngżq94[)7}l`=H[1;QHbHjj%jN,jav^5fsnhkKS%ZBH-o^Q?[Wz˿i664Jr֩.famz#EQQd4 ޜ'`jO2"֖nFoRSh+\_י!f4>7]p P&/+I-WB۾C߬/iX٣4F+XcMoDFz&CFqф[f4gh0RT-r:Fhv7!͟ ١7hh|(?EyjЛ:'9XFoNFЛ|r4ÈfI^]' Fxp_7.^{:U1"ڏl*CG27Fvw-< {9/"WrE}ĨccS޷ћŜwŘO -ŰCq'b E 7BEWjq xT%epoi6-КJA9rE]nfG6pA]%fS6M$\gԅeOܶF|:qkR:z>H(hQXUo9v2zX,.u{tlZ75F:δ$69IzPxY.5zSc420.қA'z 6 7gQr<#y 6omzGQp뜧a4w6"ʤdى;g _ o\5g4z&\A ίO߰uTY{k{nh C $y7t+BoR` ^\s /焖V|\ɴi,87W?ӛ FfP@ǜ%$G+eM9ɷMh2%2MH|?UdGraqWf'#z62yvŝcHż>uIb٬INU=^z+~O,7{k]x8N$( K53kUXuWG7\ۙ8kqƼGgJOC1cTA2q" @*htu5tGMoFMxf&7lI4MNWQz=Y֕hh;bŠ'zϪ5q 1Qab]b)'қoDsT4 y[TZE B;i%\JoJϨ >O ~Oz5`^Pg*u^u$)E"1,&13f ϲJ FP6 ?qdiTlҤKw2}fϩ\ћ<Ģs߁5q*X4${~Ko`3zSc4hcZ0 ?t8?\g5zseiMg;j7ۀ ,5v>\]47 12̐Ǵ_{ eIPk?kIg)~e{# ;9 &CزO緝i ' cu͘Q-}$Uʥ~i)y+7C.]FF_CrkwX%/=U|yEelmբia>~f.e@Z0}mkl4^ ϳ@M/bf/8dcu{YYIh˫]>B3:eFjD9r83ѽ>>oQFUz9\Z5z*Ju" ^&p t4s1;[ICi]cxڱ_G}.kRQ.D"dX<+h6;1xj2bԚpIsSM#N"HijD{'X+DO9^qglw|>^Yf2b<5F.7 r2A5vq+3?[1F3E|lfۿBi0͞^jʦ8 8x#y'o!qnRk@JS&{%8fkIJ &eiA:6Cn@rƶ~X]{P[~޻.{y6(}FTQ!30yfZg޹=7G7kφXγ5^3?V>o~N4(kX,N1%(rWgyHެ.ZJ$, sfnU?'`5_*튁a'ds]x6zV˶Kgk;u?pJ;Gp4L'{Y4U Mkve;P5%8lG`es&7a؏΅ {e|kŹİ ..| f |~G%&pMl4 j@g/y"H̚Dɕƥ-4Ꮝqp0Z_M(phRh[2(t'ij gcU$dnYnkX_]=2%E4k:{NId9&</p>sprockets-3.7.2/test/fixtures/encoding/utf16be.js000066400000000000000000000000461331222022000217530ustar00rootroot00000000000000var snowman = "&";sprockets-3.7.2/test/fixtures/encoding/utf16le-bom-charset.css000066400000000000000000000001241331222022000243400ustar00rootroot00000000000000@charset "utf-16le"; h1 { color: red; } sprockets-3.7.2/test/fixtures/encoding/utf16le-charset.css000066400000000000000000000001221331222022000235630ustar00rootroot00000000000000@charset "utf-16le"; h1 { color: red; } sprockets-3.7.2/test/fixtures/encoding/utf16le.html000066400000000000000000000000221331222022000223070ustar00rootroot00000000000000<p>&</p>sprockets-3.7.2/test/fixtures/encoding/utf16le.js000066400000000000000000000000461331222022000217650ustar00rootroot00000000000000var snowman = "&";sprockets-3.7.2/test/fixtures/encoding/utf32be.html000066400000000000000000000000441331222022000222770ustar00rootroot00000000000000<p>&</p>sprockets-3.7.2/test/fixtures/encoding/utf32be.js000066400000000000000000000001141331222022000217450ustar00rootroot00000000000000var snowman = "&";sprockets-3.7.2/test/fixtures/encoding/utf32le.html000066400000000000000000000000441331222022000223110ustar00rootroot00000000000000<p>&</p>sprockets-3.7.2/test/fixtures/encoding/utf32le.js000066400000000000000000000001141331222022000217570ustar00rootroot00000000000000var snowman = "&";sprockets-3.7.2/test/fixtures/encoding/utf8-charset.css000066400000000000000000000000461331222022000231700ustar00rootroot00000000000000@charset "utf-8"; h1 { color: red; } sprockets-3.7.2/test/fixtures/encoding/utf8-charset.html000066400000000000000000000000121331222022000233350ustar00rootroot00000000000000

sprockets-3.7.2/test/fixtures/encoding/utf8.js000066400000000000000000000000241331222022000213610ustar00rootroot00000000000000var snowman = "☃";sprockets-3.7.2/test/fixtures/encoding/utf8_bom.html000066400000000000000000000000151331222022000225460ustar00rootroot00000000000000

sprockets-3.7.2/test/fixtures/encoding/utf8_bom.js000066400000000000000000000000271331222022000222210ustar00rootroot00000000000000var snowman = "☃";sprockets-3.7.2/test/fixtures/engines/000077500000000000000000000000001331222022000200035ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/engines/hello.alert000066400000000000000000000000151331222022000221330ustar00rootroot00000000000000Hello world! sprockets-3.7.2/test/fixtures/engines/moo.js000066400000000000000000000000451331222022000211320ustar00rootroot00000000000000console.log("Moo, #{RUBY_VERSION}"); sprockets-3.7.2/test/fixtures/errors/000077500000000000000000000000001331222022000176675ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/errors/symlink000077700000000000000000000000001331222022000236662missing_fileustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/manifest_utils/000077500000000000000000000000001331222022000214015ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/manifest_utils/default/000077500000000000000000000000001331222022000230255ustar00rootroot00000000000000.sprockets-manifest-f4bf345974645583d284686ddfb7625e.json000066400000000000000000000000001331222022000337230ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/manifest_utils/defaultsprockets-3.7.2/test/fixtures/manifest_utils/legacy/000077500000000000000000000000001331222022000226455ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/manifest_utils/legacy/manifest-02f33520c330d408567423cefa7a03ba.json000066400000000000000000000000001331222022000315170ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/manifest_utils/legacy2/000077500000000000000000000000001331222022000227275ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/manifest_utils/legacy2/manifest.json000066400000000000000000000000001331222022000254160ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/octicons/000077500000000000000000000000001331222022000201745ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/octicons/octicons.eot000066400000000000000000000000001331222022000225140ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/octicons/octicons.scss000066400000000000000000000004701331222022000227130ustar00rootroot00000000000000@font-face { font-family: 'octicons'; src: font-url('octicons.eot?#iefix') format('embedded-opentype'), font-url('octicons.woff') format('woff'), font-url('octicons.ttf') format('truetype'), font-url('octicons.svg#octicons') format('svg'); font-weight: normal; font-style: normal; } sprockets-3.7.2/test/fixtures/octicons/octicons.svg000066400000000000000000000000001331222022000225240ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/octicons/octicons.ttf000066400000000000000000000000001331222022000225220ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/octicons/octicons.woff000066400000000000000000000000001331222022000226660ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/000077500000000000000000000000001331222022000174725ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/all.coffee/000077500000000000000000000000001331222022000214705ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/all.coffee/hot.coffee000066400000000000000000000000001331222022000234210ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/all.coffee/index.coffee000066400000000000000000000000001331222022000237360ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/all.coffee/plain.js000066400000000000000000000000001331222022000231170ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/application.coffee000066400000000000000000000000001331222022000231340ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/application.css000066400000000000000000000000001331222022000224750ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/application.css.scss000066400000000000000000000000001331222022000234470ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/application.js000066400000000000000000000000001331222022000223210ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/application.js.coffee000066400000000000000000000000001331222022000235470ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/application.js.erb000066400000000000000000000000001331222022000230700ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/application.scss000066400000000000000000000000001331222022000226600ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/bar-ng.ngt.haml000066400000000000000000000000001331222022000222600ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/baz-ng.js.ngt000066400000000000000000000000001331222022000217630ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/bower/000077500000000000000000000000001331222022000206105ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/bower/bower.json000066400000000000000000000000001331222022000226070ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/bower/main.js000066400000000000000000000000001331222022000220600ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/coffee/000077500000000000000000000000001331222022000207215ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/coffee/foo.coffee000066400000000000000000000000001331222022000226430ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/coffee/index.js000066400000000000000000000000001331222022000223540ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/default/000077500000000000000000000000001331222022000211165ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/default/bower/000077500000000000000000000000001331222022000222345ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/default/bower/main.js000066400000000000000000000000001331222022000235040ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/empty000066400000000000000000000000001331222022000205410ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/files.erb000066400000000000000000000000001331222022000212540ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/foo-ng.ngt000066400000000000000000000000001331222022000213570ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/hello.jst.ejs000066400000000000000000000000001331222022000220650ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/jquery-coffee.min.coffee000066400000000000000000000000001331222022000241570ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/jquery-custom.min.js.erb000066400000000000000000000000001331222022000241760ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/jquery.csv.js000066400000000000000000000000001331222022000221270ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/jquery.csv.min.js000066400000000000000000000000001331222022000227110ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/jquery.ext/000077500000000000000000000000001331222022000216105ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/jquery.ext/form.js000066400000000000000000000000001331222022000230770ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/jquery.ext/index.js000066400000000000000000000000001331222022000232430ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/jquery.foo.min.js000066400000000000000000000000001331222022000227010ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/jquery.js000066400000000000000000000000001331222022000213350ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/jquery.js.min000066400000000000000000000000001331222022000221170ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/jquery.min.js000066400000000000000000000000001331222022000221170ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/jquery.tmpl.js000066400000000000000000000000001331222022000223100ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/jquery.tmpl.min.js000066400000000000000000000000001331222022000230720ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/project.js.coffee.erb000066400000000000000000000000001331222022000234610ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/sprite.css.embed000066400000000000000000000000001331222022000225530ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/store.css.erb000066400000000000000000000000001331222022000220750ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/store.foo000066400000000000000000000000001331222022000213210ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/traceur.es6000066400000000000000000000000001331222022000215440ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/paths/traceur.js.es6000066400000000000000000000000001331222022000221570ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/public/000077500000000000000000000000001331222022000176315ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/public/compiled-digest-0aa2105d29558f3eb790d411d7d8fb66.js000066400000000000000000000000521331222022000275320ustar00rootroot00000000000000(function() { application.boot(); })(); sprockets-3.7.2/test/fixtures/public/compiled-digest-1c41eb0cf934a0c76babe875f982f9d1.js000066400000000000000000000000231331222022000277550ustar00rootroot00000000000000(function() {})(); sprockets-3.7.2/test/fixtures/resolve/000077500000000000000000000000001331222022000200325ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/resolve/javascripts/000077500000000000000000000000001331222022000223635ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/resolve/javascripts/bar.css000066400000000000000000000000001331222022000236270ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/resolve/javascripts/bar.js000066400000000000000000000000001331222022000234530ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/resolve/javascripts/foo.js000066400000000000000000000000001331222022000234720ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/resolve/stylesheets/000077500000000000000000000000001331222022000224065ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/resolve/stylesheets/foo.css000066400000000000000000000000001331222022000236710ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/sass/000077500000000000000000000000001331222022000173245ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/sass/_colors.scss000066400000000000000000000000371331222022000216610ustar00rootroot00000000000000$link: "red"; $header: 'blue'; sprockets-3.7.2/test/fixtures/sass/_header.scss000066400000000000000000000000361331222022000216070ustar00rootroot00000000000000#header { color: $header; } sprockets-3.7.2/test/fixtures/sass/_rounded.scss000066400000000000000000000002371331222022000220220ustar00rootroot00000000000000@mixin rounded($side, $radius: 10px) { border-#{$side}-radius: $radius; -moz-border-radius-#{$side}: $radius; -webkit-border-#{$side}-radius: $radius; } sprockets-3.7.2/test/fixtures/sass/data_url.scss000066400000000000000000000000611331222022000220110ustar00rootroot00000000000000div { url: asset-data-url('asset/blue.png'); } sprockets-3.7.2/test/fixtures/sass/error.sass000066400000000000000000000000451331222022000213470ustar00rootroot00000000000000.foo color: green .bar invalid/ sprockets-3.7.2/test/fixtures/sass/import_load_path.scss000066400000000000000000000000231331222022000235410ustar00rootroot00000000000000@import "compass"; sprockets-3.7.2/test/fixtures/sass/import_nonpartial.scss000066400000000000000000000000251331222022000237570ustar00rootroot00000000000000@import "variables"; sprockets-3.7.2/test/fixtures/sass/import_partial.sass000066400000000000000000000002041331222022000232410ustar00rootroot00000000000000@import "rounded" #navbar li @include rounded(top) #footer @include rounded(top, 5px) #sidebar @include rounded(left, 8px) sprockets-3.7.2/test/fixtures/sass/import_partial.scss000066400000000000000000000002141331222022000232440ustar00rootroot00000000000000@import "rounded"; #navbar li { @include rounded(top); } #footer { @include rounded(top, 5px); } #sidebar { @include rounded(left, 8px); } sprockets-3.7.2/test/fixtures/sass/links.scss000066400000000000000000000000561331222022000213420ustar00rootroot00000000000000@import "colors"; a:link { color: $link; } sprockets-3.7.2/test/fixtures/sass/main.scss000066400000000000000000000000431331222022000211420ustar00rootroot00000000000000$header: 'blue'; @import "header"; sprockets-3.7.2/test/fixtures/sass/nesting.scss000066400000000000000000000002171331222022000216700ustar00rootroot00000000000000table.hl { margin: 2em 0; td.ln { text-align: right; } } li { font: { family: serif; weight: bold; size: 1.2em; } } sprockets-3.7.2/test/fixtures/sass/paths.scss000066400000000000000000000004141331222022000213370ustar00rootroot00000000000000div { url: url(asset-path("foo.svg")); url: url(image-path("foo.png")); url: url(video-path("foo.mov")); url: url(audio-path("foo.mp3")); url: url(font-path("foo.woff")); url: url(javascript-path("foo.js")); url: url(stylesheet-path("foo.css")); }sprockets-3.7.2/test/fixtures/sass/relative.scss000066400000000000000000000000701331222022000220310ustar00rootroot00000000000000@import "shared/colors"; body { background: $grey; } sprockets-3.7.2/test/fixtures/sass/reset.css000066400000000000000000000001561331222022000211620ustar00rootroot00000000000000article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; } sprockets-3.7.2/test/fixtures/sass/shared/000077500000000000000000000000001331222022000205725ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/sass/shared/colors.sass000066400000000000000000000000171331222022000227640ustar00rootroot00000000000000$grey: #666666 sprockets-3.7.2/test/fixtures/sass/shared/relative.scss000066400000000000000000000002171331222022000233020ustar00rootroot00000000000000@import "../rounded"; #navbar li { @include rounded(top); } #footer { @include rounded(top, 5px); } #sidebar { @include rounded(left, 8px); } sprockets-3.7.2/test/fixtures/sass/urls.scss000066400000000000000000000003421331222022000212050ustar00rootroot00000000000000div { url: asset-url("foo.svg"); url: image-url("foo.png"); url: video-url("foo.mov"); url: audio-url("foo.mp3"); url: font-url("foo.woff"); url: javascript-url("foo.js"); url: stylesheet-url("foo.css"); }sprockets-3.7.2/test/fixtures/sass/variables.sass000066400000000000000000000002571331222022000221730ustar00rootroot00000000000000$blue: #3bbfce $margin: 16px .content-navigation border-color: $blue color: darken($blue, 9%) .border padding: $margin / 2 margin: $margin / 2 border-color: $blue sprockets-3.7.2/test/fixtures/server/000077500000000000000000000000001331222022000176615ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/server/app/000077500000000000000000000000001331222022000204415ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/server/app/images/000077500000000000000000000000001331222022000217065ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/server/app/images/logo.png000066400000000000000000001236451331222022000233670ustar00rootroot00000000000000PNG  IHDR,K9tEXtSoftwareAdobe ImageReadyqe<fiTXtXML:com.adobe.xmp pmPLTEjjjlll ޼pppzzy}}}uuuܹddcى􁁁+++[[[SSSKKKBBB333<<<$$$rrr뤤렠nnnԘ ǀ||{xxwppnnnl___rrptttlljggfOOOWWWHHG777///(((g-IIDATx콋[X>@IQ0Y5QT6rDDZѢ>ޟyj=_>vi:3׬^{kmuM/#_/Rͯj~巖_oef~=jK7#(sK7՜EEEMj" K'DUEZTt$A<'j4:pɊ(x~G~ 3y;m :~W\RA7t{ ÐYT0*zV aTiNFw wHoF%ڭ.u^P]P3ڳa TA7Tc5#"x&ͿپKLST>² T=T,ҽ*i hF&>ͯl$+2'_k¦Pdx&)e ,5Z-20$uQ8,!L|tg+~U#0_A{IDނdl]uvFk2߽?(jʜzT_nײمE'uK5烘L&߷eK?FBO"fW0[[Cd .X4 bɐKG-!c3'dN>׫bMS,1י7^:)aYSPS}TC^Qc*tuZyrA e{xEm2„#F.0Sa穊ȵ]5! hॲxej2,i"V{xj&Y^ga@pUm , b,f٣op'p7:_k(xnk|X"0e>Jj9+30ґ׾^f.=s[YsIT{><1Xͨt6ܻ}:'.&Go:fSci80b/( |`Օᘷ!V$U^i>3vڕw&߶gbkS9#OU | jՠSuz66hß6_w) W媩HZDX0$IUv2 GdC'=6F9Fe zxpVbLJ Q8um>8pvNk؂-skͪ돈,"oƘ Jeq|d߲ {F9Z{T=Ea] ' UiNM.O_xY*6C(ӄj"~b>UᙵTUc0=! 2\or>geP*(ź (kk)7)(`6:cWodqb7'ۦEmܝP/d/V͖@qoC;W 2T,Trļ ZK=A ?b|=Lfnb č|x!ف|ܰ ߣ!)·l^'Cn_7 Ѓ ? s?[C@^V:®nX\f؆;>(}U $o|-Fz#FpGی4›։BS[og!؆86?|H9w z5&MxVU`G8$]sUЄЯv[ HG{1;WdR`j"WR8,坦@oz8s x@RT,ZX)˲^BQESTb86|'hM?OmcWOsUѝkwlogq` %8!DQ*# C @0!R V T0 ژ @w}3];\\arsUӬB;{pNp`G]o)1w my[~{=ҹ`Bܶ=C|sw:蝋udٺڝRtYˮ݅iZnơ-by̐Vhz0vfp}uU="WY߀ޒij2uגiWX'C zk孾>oy;O/3@;.ț o7t$ CZRS'\@|3+y瀧gTO>vZ~Z}Li/23 "E4›G o: ?0K`oHc*k鱚r,=Bi*6R+9 D\*$eD1W]m঻XbY t|OyG/Vv u|%3<e![7/Lu sA8bne6Ab0ͲaD4gYjy xsȲ3U?2۟p@B/a"ץj v̈́Pg># :g7г<9&B[LO ?t>;zwEH& ӑ-3]# |D `HT$]Hj 'fQ8m [mli9}+t݉kJ' Y[>gl"q o/fX' (vmض6;ml~ۮS*sk<#X$MBL xEXm'wQTښ1{.#shl9:B7*cӴ{v-g̟Lx-m@hۀ́0aŸ1έ-tfvvFIF8i6Ge4^X3:kb51?Y5do5HU3<3 V3ƖE1`t<'@ Ba|0S&$Vba0=.]>/\tu)V\OKׅF%ݛ|pmaR4V]Iš!Mŋ T=MbqLlwŰpfQgcv&ۼ!&0%¥e4${ՠE W.i[Dhg!1G;Jw ^%El ,oj(&*Ĺ!imwv47 f›%:z6%`;6yJۯޯ>`uW%tPhLFph<^|FIpDROUTtI\/Q h٤TOhb=nZ6aؑ f`*Ithq:Fs~$D[~{e$J&OwW*og:)6pחs}(_XGܗD0qosڶP9%w_ vsN8gݞ[ߒ϶F]3K}3s 1ITVWDPq syݞz ۠pن@zpǁl$p;뺳U[;|Slr%ݼuIp`MF8 @xFh\O`Tmr_=t/[ {D`{FzJ}cʯ%gV_[a:Ge߀LoVWQ`0Iϱ~/T6zI@ 89acGwwΤgEz=p̾A}P?2Xz6k'Fvj|8*sO}%xKa mD>*2l8nx|h[zȷ{x픧fY~m^ϱ{;A(=p x6Z@ۡB-<*h=SU HST9{l\*PEƯo1n/cE0Ÿ"r~]Ax;vmB[+x!xt7k{Å¥m`!W(E(vglmwbvuwk i8?o?`jA'1"v77]_?{7CH |v ZUfܹ϶yOϗ! *qhg4mWw[/8Ȅʇa }ݴai/H,xnXf_ٸ %Ɩ-loApwvmK=[?g "" Lr[REҨ2u=^FVxde]4B9hG!77}G ]uv*kM|(Y^Eވ*MFnr06i#b@o,g=sø{/ 7~ܠAck6ModHAD$U:4MߊĞU, 0\P9u ťer0x̲, ozXvZ#n?._6aX>ZN/Ev?HWi?$;75uxvvX6Cc=pv{)ve=se}=hTE7RUHD:6Cu_CJ!w5zRgx&=cA=!7}~|uٳ~R!UE$֢6&]f `ai:֜_I߇mvέpMD3[Eo)Daw`400[N7B]U8a ^0,D57j l~[Yݮr|9!Bs&3cL@n6VAehnBRa4xk<ڙ@HϻԄ i#?Qiz q{<Ʊ~a^F aBE'{U&ZjֹBƘ"8xj of@=nu'̄tIUb+oSOQqYlb:J8}!h)"HkDCJv0Z%a/U @5ׄ7yu~ o^vK$qQ􄢉 TCMXVz  M(dR7Gq)kTf-fvJcR= ]mv?b)agb8c@'ԊM9Eoe:-g˾A7O|ecvq`*]3OnSWܰ\G! >mGbw(=lF흧۴-z꽟{Q(e%,Ih-*Q XO#93䂌"t56 _x@`!|vx|w'omm葥jIxqZdQsxd4M x=;WڼL܆D/ƳмwIfUx ekHxyfT6AO~'b!ȫۄ2,@+2zь͞A/M(F&|W?hosaQaMx3f H}NMgs@x3eDxs1]z 9<({,}Y {WE-0Ҹ;m#a R; ͆Fгio66m4/-[ 0MaO $aj:0Ȱ GS\pT5j -J [\'+1&6(P?{]qZ .tUE͌zL*ãSa[_}}FrVQ@ v (l&2H6&4 Ꮻ<'U y6Z 1m숻SĒIMKd):j+$!K0hƅyޜ B(VnNQ8Q5NSJ7ϞĪ0^"jQ T&J*@Hsf$NLȏ7Kd #'.jRĒ7L,eMx3H73Ɛ>ah 3(wT^ &h:$ Ah" g 8(j и o~@*g KuRb/?M8 b,2x( `U3!ܟ9|7K@wY3)9 gMTj x YuGPc#RZMVPh(&4ȿ,h//7D>߼@on7m`n1lm]gtN;ڌĶ{s4:r>M`ݦn8BBX;]kz 9YՑsƉ4i@fD/qB#D ?A5q~2J?hC֗Oӊpqt-a; ,4ÒA r 4f|hװN:@͜CxOo3]%FO O5FǛ+s3W"5f/B=l4sUtИ;A/0HO AhB[p4AEgeD;sP97Tn#(+oTx JS'qHvGص(?6iP]KQg8cJ+1jb[5N"eCpҕu*x,UT?JMvov}!zP}*v(|Ç+34`8##=bU0Ûb^5/&T2XV 8LQ QA8µ}x60Xm|?en% Wr5$Ti\?(9~P5tRp(s|}#)pBh8Ni;onhV._.`jpƘzӤ8lll.TΓǏyoL%dj, EB`iEx8}7(ik|ѵh{ݶ#~&㏲naOS}={y6xK"xEZTi>[&3&X*G wtf9 _$fF1h07!;u u2A|WSjo n›{%JIX/oKƽ-] ؍;[ێBg4Bn `;:[VVϷ熆:SSD-9lxi6Bf)ā=#@،1DY#Gs尭=ok裂$pXRWNM ѳ]{sp>%aN%P!FہM Y ۴9s~ar RR$P'+Ffmޠ;5Y t k;Zp₩!2(,@PT]W^2gVA@V-p"D'R۔ȑzi"T3/D^K"StWE"|A r㷓|nR VQ$o9;23C2;TRfd)!qn J&&Ʒx Paq.K3)/[o`[xYSq\U QV#4qԿ$Cs,~&|J£OKQS/.``)jf¹; xXYֻFQ!E1Yj#&eadȔȧɬxv潭-˂9߯z'p!J*9 v\ʶ.t9#6EJq{uGclИL4|.ʽu(L%;"Ř ,p:رjr2]KTqhs"3WpzLL? !pQhogXԩ#_#зP.OωT֪|O#ޜJ}zcOyj8׍}T{uA%xXj1t za|yIAl8'AY+Dt֞_|NRzbU%Y/Sk5»~MbkTx7ڞijqD,KT'amk%9b8Mn}Ѱ146gr@9YfagނR_Aߢ48amL$|}Xu8m,<.negfAp(rKدՉ'2s3@ުˁ̂HvԁU v4[XEGdIR9}P{ ö}k)u۳agล=q'i-Mz.ސD5#!iಆ/2(3uB՜M .OosOw!:os|xo#B =q~Xc/ DHN??Gk"f %#kWx#+)=kyWRmF3#X'mܺl76Aw]S*fl@Q 9.1ubHj%8dNgsniw+?i$~{KPEzM/tpN׌9CcNOw/'{gݲSIH\jyDg!z=dLco}˅8X*׈h8>CzLZLQ1ɝhLoooI o4XWVsJb\ 6\o)|}j%<?y1ȸ_37/P=IsߝBlԂqp櫟GTlvg]ࠫ~0_Ϳԫv#DDF /+NbŊ 'M[ŕ L5H~_Eu}9j$bv=e>琰i_cm@xs/#0ß7~3+Ҩds $qu=L\EՈ Z/ʅAwrϦ;Nm›#|}v.$T'-42oˏa\iLT=+2- Ͽ,,9S_}j`udRu}asw8ѴG2j96ڴhpCLvMfCU2KlNdj£R BX37Y?b›%_Є7@p}7]w7e<MU+ a4֪'~D&)C0k2!&n+sVZeտW^%skgoANM7MQN]cl>kqx4dj$gNQ1(ϾxIs`Mn9 xHC^cg-`›k;(OapcQ@f9h[B1]K.j_s kT=':Y]yhzXv2nFtcDy{d9%ivDǜt]tG^ޅF hxTExzY8?S  i>׏N46 z[T]@vlfBDE -jRЂ/@[WI,BKž8wh|\LwcSTu"u14bO47e23pcuA$5D2+otQ"X>T{Z](#y/dBw֊]N ]M`,u 6&___kaVLTLdq[u(X)εBNWߋR1ڗUd}B_Ӕ~N쾨+U!UUTؤͦJVFm8w` LΓ5+b9BtF곰ə'dq##UHldEL .KjV4V\Pȸ鮷@nQm5){8ji\\SULNg\~CI ;sNfO6|G̢-k#[Z|ypfT&SiG.2>9asI@I:ܐLfiEΕC0&fjQeE&wͺ ̩YbYwG NN1+{z q~ LYژj_|i vU3KXHt'%TL;;26#2",WXA@bN 9AXg*m3Tc\ O@yGvT˲XbaR#Z5xy kG̋_fʇ,]`/9o`ݓb'1kOca^>$n,ʻ䡈c^Y-ObV+J&z)y;`dOQ7y_CXVjYF*554QѸ-Vo^|5, rݤ5' nH.}C B !14Q k ;s̞Evp=\p@FyuZCR"kM{eKd7]m)&^dDF)*r˨/7F@dZ"S(hƠ ^c UwBzf=e: RcluZPrF,0"!?f[cK"C 15RGg 59xJ03` I_;"C a%v |Pg"Ef.vVly?ԓ`ޗ9J&W[HYDUƁL5{`gtYXxITcs6)ޤR3O=a4T6"fᡃVWOz#<*>0W:C"DQ8AMT׺Yod~;VfU.x}Yąz(.W4K?O59'4 :]88.9! 5ikx,RcK!!?bѓm، $_>\4`I]zk,>ۦpfV/+SR}WlB@g堏=ZtnjEY0Lw5nFkp Lg`!/"ZM5ē w }KaJ7Gotk2-޴s^|}l!j%^GԕG>X ,Y*24W_cOس).ezV ܼZ}S) q\-kl1|TUƞ]x\XUR0-rX S 岌'v;/ Ւ9Xa/ 6y(ijbu] T3٭C{Heq2)j'9i2 jH>xU -su&l cA+fdDhAI0 ly1iac`I=mgQh'ʭw"%.H:^.3n@P;zWͣɛH70w],۝^E<|sזᶨHsY1ų'hŗ?ϒU NPB->Ym A /7<5s:x5-[u Nxfg2l `{ęsނ 2S ,"' ,2w[u}=|o䬅f>"/Ջ3 [0r][OsUC '[ "+Dkŀ QL3|д¿Q"ZJaոY iÄjU[qX5vGFh82>dϋ+A}}ԻYrLG*|]8Gٕ +%O z!Hu_9t[d= T,hn?Iab_nɝ8>ZDNQ[1դ&u r'psW}%~}"z35:W1UCBE%y<3$mӤeXZ!džjBDMޒ ֑::xpSV,A('@N>iYLwdQT M>~]+aןV ?MIЄvwxk3ɲ H6hh C'vpbA<}U;B&^ہ~JJ:QMIG܊ ۞M?S3 S 9㑏et 9uI3hҟUM71 `y {mC70EMU)yȪyBOj߈$>0vsykHo<>7w`4m22UN4u߮Zs[:$< 7[Z膰W-82 !W,^I98WdCl>=º{v=o|C[.ྷ8}I9̈k4XdTSV[xT@\0jEaI,]`hq#w0E+}t AzpO^[:[FcDe:oQT#c! ӱX,QzPZxfmquv*Qoh$4"}}~Ot 9a:^$: X~ؾtLIVǔi: e,Z?_MtPDdg9FjtvZc?Jf qRoV'}l[gS2ͮө 'cidF$Tb^LYOgP_FHF5_;;~홗o|XS)x ߜ֍8>G~h g& ~)pRE蚠0;S 2D*YdD.y3_~Y|]?,\lg.fËo̖8Y 6PMCz*Z՛W/za Mdh̾k] 0hR.L۲Ju4<%Sy|R&kn=8^X ( jk;pk'rEV&ao87岄D l~InةgG!A e^:"W$5"N]w\3Ul\ĩZ`4uGl:_Q5 UPT6-2}>_tjA*Շ&'p{ RY,(|äCx!tfG-k5bO>bi~.(g$fFcki Ɂ$ Д̀2.XxzC͇|X!;4WBΐ1V.W/)b ]7hAkkxs'/2wlmxHyEfZi:W6=r:\b]}-p/K|PGt/x02 -k[TXlDM3fSA"@|``p(*zPIJm]})Y+vi{Szo9ѸFT9 䎅bec{Ƭ~M38]"*)ԵD0LrK( -G9_0͐_s&Q5fVc*\۾٠U*Uf䧻Yjl*fxjcWI5vr ,,z)-dz,'+Ps(mYd$6=Ȳ;,p/6$ZmԧT:/r wF7TMjDj/[L cuK+K2yx`@: ! <EL, yƲ8,zٛmAm++hOyX7 KEE]i̹*,ΰh;r<BÖAHwHqaUhK}_kvom ؠ+5,J"'_wm0&{猿93ڮ~ߪzުd@ I@}'ԇ %f,hiP'q&k䝋}41s6 /LyscV u73y4Dd<]ͪ^ut45_$ob^ lzQ@K/Dwj5||G˜Kh,Fa:%gJ-@Zn"ʻ4-]!x3гPrޢ߇Z)rHo{07w9[2oXWoYt?dBk^kl&Jy~ .~>+8e]q Q6>ۭwbYLfؗ\Q4ɕH61Mk7u9phsޡMUC5M#EB %Z+ĩ 3*l\pq8.&)TࡅC K#%"(lAQHrda6MisΆ- s_rㅸRJ,',_E34 \X'[4M}&o[^Z+ei& ×I? $WmͧtH9}1Qh72qK%=*9c[.P,O|\9 b!W MCI|TXګĿnd,XcF %<Θi⣏t@L 84+nhY*FS vw ؅Yo  ̳1SvXXӐ|n'lJ-~&nӳ)Xs z sU!'> 6ՂE#NW#v 6]q7M @SFIȕeگWCˍ&d4F3wi&wXn| /=§J4M}Jh|TS_=y` \EWNPm:BvRu=#|V2zY K2g~u_")adc=OIC6H,gq>bW-2Y=OyYa`AXB.`y r3`{X5W_͎f%8c'`!u+] e 囕T;>@Z]tznIx'IiQWEbPN;QzO0$1]_52:ſe&Az)kfCo6y>)7Jh˨xoӛE*~ؐZ/ei19Nq%Lwfx|9fx1h((ZEn9uBВgw?s()?cuiꒈ.KKv3HmRS4ЭjeIRgdH5KA-lrwYCz3~DkҒIK=s~LRһ )d7<Vtv20dztK~qB$*pNWEJ fL Φ& -/S*9} X):>TPQ*6F䎺nI^lH61iY!@_x%fC k\uoU|xh4 uߗIjql ?6MH:rx3LJΉNJP Xyo: gD=v,RP`N_m`P[jjUk3|yi[ﳩաWXMCA~Q;i_2np 6I ? <$〶= ~JXkGV tn (?mςh\3i40,z3fЛo|Ebry wN1r41KXrY^s& :NQϲ%GY>("v,km MC+%й՚fͰІct+C"y=+j: qǁpޤl_ЛICEpے\p`ޡ7 I&L"P*퀛fd4o#rJ؜DXz_*I4LƻyBiQ@Nw ϰB)vNX嗹6gi;%Fo\X,FFo+6UkS|^$[HS+]>GZ֡#Qn<.}U#1 յ,XwBkY:R*zZVEF ykfJ\qǺ42k?~4ZEׂ6k%T! 6oM4frTzqqמ*kiB@0FNZZ8r$CvSoR?nIj3ed:xdDV 9o%*T]^F͡(=~49k)[=#~Çs>fNGJi7l/j9Sx?p_!5,_q@&㱉FWub<&:-jY!Yhms;$wk!FKs7GirpónirXҮRE< fb[72W>Uo>hDzKEٰzsF]%;RRow!ab.{]E4Yq@uKjbIA\bciu"iN5H<<;b~`vDK'pE.`I&81lyQm!޽ DoSiZB̑"lÕﻦFR^t:d=.ǗD8Pt[865ih7P^d!PQcV3ڗ^4;WA媊&IKi_|m)>(?+?Ж64D\@BY"ы]SYF\QWkKH󔼯 L3ÍM=pF@vhQ_]!B#m oY&'?'_m[ov8~׶wG=q-ҟ,}4V$f^lim8a$7MjeIӰNI$%iI+<&3S8%xJi Z[rR\8`WB?C|o5~DhUZMf$AvLM{&߈48YWgX3-[j"H$u-c h{83@l)%daM9sxlƊ#De(|V`#G̸[ $r Tl8lxܘw~ ĠlW`Ko#m ygQ@!Hq"x&%Qcy/(?cٍ^9x8>7gՇ,b=ˆjn\3ATJ>|f#wH놜PԢn4oB QD?Mz=2o.>TKw{UM$XiFOԆpG '`+ɤDpIhXx_D }#kD%r(HhiɖhS1%Ngj,4ײd4uJ>Л76FL[ <83Wӂ& ^ =J. q&WVrP/dՐbauCaPXQ]_(_!Z r" As #~-c:B ^ӳ՞$!1{(fMA@=t Z⹩Q|3#7z5h 9n[٫c+sju,[WmOcEܪ .TYˤhkp"ug$uX#çٔX.iKwVG2RsРgHE7׎kP]UơZF"[67HEʓiRGDiR 5Id4ul)+B#{͉ةa|2 pN!yNo0KX`]IQOb*iAU C~5G&߽\8Ms6ۭ&Z`[;4g5{?$cN7zhb~bncb7u 񑦵LyIMQ԰wBDZzE b.y]* 0,#bEJĮG WJ$j;{ML~G$啵g:J$i ĹstXPh:kEśv8xewl{l;Ht^JȮ1ҫPO&n lx(R@9رa>9 uX=ƭUJ:!Y&GMJ({ zvYgG.i"+_mev@vcymmYVILowkӗdȫ% 7_ / ט& dӬ҃꾀n7c^Gz33~xhMD=AYg#$+oU6Ud4uzu[4TZڬ|PWYY$?ջ$FŸ2XT )27/Vh aaяe!F0—GxPE)ɝJ ;!dF57}5WҏDEfGpRi Üb€7\2\ZZe;]'-8\e2Iz9NfGz/L{2Et!NߘI:oKL3eD$.[|smn V:)v~E< Q֞=6H\|״x]4:8^`ch,G3%\4 II#oc\֘OOtjj?~OwZϯ5۱AiC#,%l5/d&&CWkRI3 '}m{oѳ7S4<_s WvBʴ?yڿXc6D^3zshaW-!`~hMwΕ-쇷hvtG%?ʻ1o'&XPo>74juCVU__8=kMU_􏲊R5ͻ}+'8i F <ݳk""BQ\e`*lh=h` ;[s`s&,iJ跸t璷e'GY,18֘ >8z$`ҹ/j s3\FC'9 8A#$3y_>`m&Ϫֶb&foeި0gy 4r&]57UZG; .{مwUXY *n5zy(H" ]d+]_Ci=]$9rCQu$bsKEuNf޹~O?ec9ЛtO&m<`t_-{/y OETOIA zA혧|f#D(]hc&zp/}^b{ s\C_sAMfŗdJgioZ+Cj 3ZAr*8]-A$_}ez)_/Bt"Evlħ=Ch';󷅼hW쯛q)?˫y}L; X7zuE]oZ*a>Rl$Y>KŖ^pvc}h.G1Qs1K<Kn` |ٸD<"6'P50So+Y~bci95_#v`sX`.Ȫk&|mx4X']&uTsx1"]o's C_yӒL\QߎQq_7 F͒ AHn)Vwe <r3vʏ!@y6tXXQ1N`4fC1enm`'[T OC Phš(ٗW##WA {> 3(˲EzӪ}WIM?Hnb' !p9yݍ⾧zQWپPHS& |$EۗVB87}Z;/QMs@c3҈髋nk0UlVV6#۞ƚz;^%ie>揅GMyo5 hc̺k: /2796 ZSkLcia+g>^8=;m3!O)i=5e.8 udn}y.'e7ڠLF] p+h 5Lcȝb өRI!:Ib[zyUJrﯚ&C4{y-M1qMlF3hDz8ٖs p l~pf)ϑgN;9-jc&9L08ۃ ^h-ka?}YC>@QNuCӱE액1r@EuZ85ڬz.`VmVv1񘋺h0z3`suZ!\y$+:g=һ[4ޙu^Az:tCݾr+1YzпWLDvo RjHr UAa[ æ\gbm*d&4`:n'Vi<.2BD3h1Z6>I5lhYЛs(=rܫe33A悅k۲–z*\V7Ul 5'0C]2qv nd_q-C Ov4F$ʼn_0u'n&A9 nvj .}$ {ЛMB1y &E!NuMMVTʙF ;x~+^ 80`CoNi^47q.0\9 Iz@\\eaWߵt 83:g6(;%6!-yBkpXH*Gސߠ"F2o>Gm'zݓRy4 yd(綰ZUd4YE,]$3;$>k0:Y*cWA@q_`1wOxG˜O#Pa=1 \m#p͛-̝ᛁr٨qojp~ӖS~M]/f7'|"Xm 6~6$|9crK7UZK-Iaͬc);U!ԡ7MH7 YAz37vDMBoZ`CoFS ꔾ%[ U+J_޹4FfGf IeI׽zϢ=se^`P F~vOrU3;u+}~ߝ&~W;9Rݞz"_ύ/>;j4SJvC?gMvyrܨ鶚>psG0 ڜWݕfml{AVI7#7cGۃA}pͱhfncM> lo6czcs;>pLxn"H|6,Fܪi.3Fyn x;u3[j_#LM伾X̺'& _sF%FB3X3^N}D͘#L8A9VSG.x49}| 5Zw8:\Ӕnx6Jڭi|QC*=`T r]7ymz3ڡ7( Ku"|tT[/ xjHoXhT[!f!nH@ ^rw=j7; " tIPTuiIa>c'Lw[6ARU-ٛyCEnwP,jzJڛmsEVe& ;rj\3gGgA?r7uif WMfsFU_qFZ3:4T]_Qq[3[Ztc9u{ș5:=cfh,k&X@u{uVUmӢc0|w]8MD'"hiK {ҍٰIӦ)< RvhgMk9v́` V30䞰 fmh$, @٦7y qHoބdf4]NIg6f`K k> ̥3 \~)Ѵ^l-` ؑ뼄 \"hA,B6*)- nA&1A U\RExr)%K I𝩨S~4uVƕ ٛ2|Gِi .>g16uf Xt` HH7پ#}>qic.OuD6ty! f=?0PLTͩ, #ۡ3~+g.^EVt"aܺ1+A BvD7#5n-謤i%˫貾 Fc{~y9\>\>"ɁxVd2 >1Cϭix=1|uJ+gGg|xrZZ^\xVi4Wdi?w CHh& `psgǹpLJsF%.0llC!7ِKP ܐ>zqJHpBnP񗋡^u;S +7![e fPE`t^K_C:p/vߐ[ѫ:~EP 3m%TO{nENzS%镝LA"V/k=y.u5 ` I1خ%?9 QԚyV󉚥pmL\6̫M*aTs [1Z\vÃñ9SP`}FflҎBd'UOࣵ/ 1R;AuS+H``/{JU2 psaq:ׄDIVy0Z5͖@2Y~,*amʃD#%<,Žm+*% 3L(_`}낡(f3e8KQFhHPRAk P Q8bu@a\@mQ3ru /=RU8e{ak奤DVX>ij,lak/[ƭbއ%ILZA3tµ-C2a쬐ꄦB> ~rJi S7i +v/ßoT44$f3#;Ja4 2dK5,` ;Lfb1_Z0OJTQ>)9LC~i LB11|< Uؔ(" :D칄Cm[ =Ic˖P4#RC됫%]MdM#nцEt#idmB;<3R@}K{C[5@f"`tw:6u#(~ u,ۿccnl`onh:#;VLm7$29c(*;v?)X${;c0"ѝ*so,"bN 2}H_1'IОWϟ44V$Q[)%i+=,/K$R'O Fd ILqM{B:W6Z .'vyӆJԥ/l*J^-2Ο6Dk]z^]ʉ ߏڽ:SՍԪ~nWtF7Q&sW|Wpwm7SCop}3R9 pM,ax˰wؠj0uju^MUoI'= e SsLUrRnU_$?Y__@ E'MɧK[Vrmv~X&ӏjöT<Ф. xj10`k..1MdTbd5h8!m4pe婰as3R]5r+T]AiiZzfTFʰH Cƫ>BMܰ3W(se;f"Z(E@D׻0N7u{d@-= kCCnTT]ֳ}3rV7eZ*EֆTvy,jqϻ]l 2}b(~.&)BK0izIsP5DR1%?4=]oHȢŦ i-W8^.ԁ9NMwKQS  QgR3OPq,׽k] j1[97L-fy&^a|TQF8NAk<dT=5c= pf ejY,bxʐ=`z)3$(qOӶVuzfO '/_2QMglXQ{)69eil{xm3JfNEk)'6 >rv6O |SN犨(I5%k sA&/OhYoWB:=T-nZꭾRd7y ҏL\ki`» Х6bLYtgpqҏ{l3A٪ 3j?`#:lG7/=|x]`.>\|_ێ^Z~YulO1-f W9燫̬ǜ9̼2`m8L|T+mO\I&pצ\%ӨC?mϮFx9Au蔢CR`W*yL׼8!+m`iMELݪo(mUe Wz^*m?ffw6j(7LPύ }nTc,ъh* 4JH/g$~4? kL$j5=:F`֥W7Cf HĕAkJ_8y;'m65Ngżq94[)7}l`=H[1;QHbHjj%jN,jav^5fsnhkKS%ZBH-o^Q?[Wz˿i664Jr֩.famz#EQQd4 ޜ'`jO2"֖nFoRSh+\_י!f4>7]p P&/+I-WB۾C߬/iX٣4F+XcMoDFz&CFqф[f4gh0RT-r:Fhv7!͟ ١7hh|(?EyjЛ:'9XFoNFЛ|r4ÈfI^]' Fxp_7.^{:U1"ڏl*CG27Fvw-< {9/"WrE}ĨccS޷ћŜwŘO -ŰCq'b E 7BEWjq xT%epoi6-КJA9rE]nfG6pA]%fS6M$\gԅeOܶF|:qkR:z>H(hQXUo9v2zX,.u{tlZ75F:δ$69IzPxY.5zSc420.қA'z 6 7gQr<#y 6omzGQp뜧a4w6"ʤdى;g _ o\5g4z&\A ίO߰uTY{k{nh C $y7t+BoR` ^\s /焖V|\ɴi,87W?ӛ FfP@ǜ%$G+eM9ɷMh2%2MH|?UdGraqWf'#z62yvŝcHż>uIb٬INU=^z+~O,7{k]x8N$( K53kUXuWG7\ۙ8kqƼGgJOC1cTA2q" @*htu5tGMoFMxf&7lI4MNWQz=Y֕hh;bŠ'zϪ5q 1Qab]b)'қoDsT4 y[TZE B;i%\JoJϨ >O ~Oz5`^Pg*u^u$)E"1,&13f ϲJ FP6 ?qdiTlҤKw2}fϩ\ћ<Ģs߁5q*X4${~Ko`3zSc4hcZ0 ?t8?\g5zseiMg;j7ۀ ,5v>\]47 12̐Ǵ_{ eIPk?kIg)~e{# ;9 &CزO緝i ' cu͘Q-}$Uʥ~i)y+7C.]FF_CrkwX%/=U|yEelmբia>~f.e@Z0}mkl4^ ϳ@M/bf/8dcu{YYIh˫]>B3:eFjD9r83ѽ>>oQFUz9\Z5z*Ju" ^&p t4s1;[ICi]cxڱ_G}.kRQ.D"dX<+h6;1xj2bԚpIsSM#N"HijD{'X+DO9^qglw|>^Yf2b<5F.7 r2A5vq+3?[1F3E|lfۿBi0͞^jʦ8 8x#y'o!qnRk@JS&{%8fkIJ &eiA:6Cn@rƶ~X]{P[~޻.{y6(}FTQ!30yfZg޹=7G7kφXγ5^3?V>o~N4(kX,N1%(rWgyHެ.ZJ$, sfnU?'`5_*튁a'ds]x6zV˶Kgk;u?pJ;Gp4L'{Y4U Mkve;P5%8lG`es&7a؏΅ {e|kŹİ ..| f |~G%&pMl4 j@g/y"H̚Dɕƥ-4Ꮝqp0Z_M(phRh[2(t'ij gcU$dnYnkX_]=2%E4k:{NId9 x * x # Arrays: list = [1, 2, 3, 4, 5] # Objects: math = root: Math.sqrt square: square cube: (x) -> x * square x # Splats: race = (winner, runners...) -> print winner, runners # Existence: alert "I knew it!" if elvis? # Array comprehensions: cubes = (math.cube num for num in list) sprockets-3.7.2/test/fixtures/source-maps/coffee/precompiled/000077500000000000000000000000001331222022000243435ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/source-maps/coffee/precompiled/main.coffee000066400000000000000000000006361331222022000264450ustar00rootroot00000000000000# Assignment: number = 42 opposite = true # Conditions: number = -42 if opposite # Functions: square = (x) -> x * x # Arrays: list = [1, 2, 3, 4, 5] # Objects: math = root: Math.sqrt square: square cube: (x) -> x * square x # Splats: race = (winner, runners...) -> print winner, runners # Existence: alert "I knew it!" if elvis? # Array comprehensions: cubes = (math.cube num for num in list) sprockets-3.7.2/test/fixtures/source-maps/coffee/precompiled/main.js000066400000000000000000000016601331222022000256300ustar00rootroot00000000000000// Generated by CoffeeScript 1.8.0 (function() { var cubes, list, math, num, number, opposite, race, square, __slice = [].slice; number = 42; opposite = true; if (opposite) { number = -42; } square = function(x) { return x * x; }; list = [1, 2, 3, 4, 5]; math = { root: Math.sqrt, square: square, cube: function(x) { return x * square(x); } }; race = function() { var runners, winner; winner = arguments[0], runners = 2 <= arguments.length ? __slice.call(arguments, 1) : []; return print(winner, runners); }; if (typeof elvis !== "undefined" && elvis !== null) { alert("I knew it!"); } cubes = (function() { var _i, _len, _results; _results = []; for (_i = 0, _len = list.length; _i < _len; _i++) { num = list[_i]; _results.push(math.cube(num)); } return _results; })(); }).call(this); //# sourceMappingURL=main.js.map sprockets-3.7.2/test/fixtures/source-maps/coffee/precompiled/main.js.map000066400000000000000000000016151331222022000264040ustar00rootroot00000000000000{ "version": 3, "file": "main.js", "sourceRoot": "", "sources": [ "main.coffee" ], "names": [], "mappings": ";AACA;AAAA,MAAA,sDAAA;IAAA,kBAAA;;AAAA,EAAA,MAAA,GAAW,EAAX,CAAA;;AAAA,EACA,QAAA,GAAW,IADX,CAAA;;AAIA,EAAA,IAAgB,QAAhB;AAAA,IAAA,MAAA,GAAS,CAAA,EAAT,CAAA;GAJA;;AAAA,EAOA,MAAA,GAAS,SAAC,CAAD,GAAA;WAAO,CAAA,GAAI,EAAX;EAAA,CAPT,CAAA;;AAAA,EAUA,IAAA,GAAO,CAAC,CAAD,EAAI,CAAJ,EAAO,CAAP,EAAU,CAAV,EAAa,CAAb,CAVP,CAAA;;AAAA,EAaA,IAAA,GACE;AAAA,IAAA,IAAA,EAAQ,IAAI,CAAC,IAAb;AAAA,IACA,MAAA,EAAQ,MADR;AAAA,IAEA,IAAA,EAAQ,SAAC,CAAD,GAAA;aAAO,CAAA,GAAI,MAAA,CAAO,CAAP,EAAX;IAAA,CAFR;GAdF,CAAA;;AAAA,EAmBA,IAAA,GAAO,SAAA,GAAA;AACL,QAAA,eAAA;AAAA,IADM,uBAAQ,iEACd,CAAA;WAAA,KAAA,CAAM,MAAN,EAAc,OAAd,EADK;EAAA,CAnBP,CAAA;;AAuBA,EAAA,IAAsB,8CAAtB;AAAA,IAAA,KAAA,CAAM,YAAN,CAAA,CAAA;GAvBA;;AAAA,EA0BA,KAAA;;AAAS;SAAA,2CAAA;qBAAA;AAAA,oBAAA,IAAI,CAAC,IAAL,CAAU,GAAV,EAAA,CAAA;AAAA;;MA1BT,CAAA;AAAA" }sprockets-3.7.2/test/fixtures/source-maps/sass/000077500000000000000000000000001331222022000215625ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/source-maps/sass/main.scss000066400000000000000000000002721331222022000234040ustar00rootroot00000000000000nav { ul { margin: 0; padding: 0; list-style: none; } li { display: inline-block; } a { display: block; padding: 6px 12px; text-decoration: none; } } sprockets-3.7.2/test/fixtures/source-maps/sass/precompiled/000077500000000000000000000000001331222022000240655ustar00rootroot00000000000000sprockets-3.7.2/test/fixtures/source-maps/sass/precompiled/main.css000066400000000000000000000003161331222022000255230ustar00rootroot00000000000000nav ul { margin: 0; padding: 0; list-style: none; } nav li { display: inline-block; } nav a { display: block; padding: 6px 12px; text-decoration: none; } /*# sourceMappingURL=main.css.map */ sprockets-3.7.2/test/fixtures/source-maps/sass/precompiled/main.css.map000066400000000000000000000005301331222022000262750ustar00rootroot00000000000000{ "version": 3, "mappings": "AACE,MAAG;EACD,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,CAAC;EACV,UAAU,EAAE,IAAI;AAGlB,MAAG;EAAE,OAAO,EAAE,YAAY;AAE1B,KAAE;EACA,OAAO,EAAE,KAAK;EACd,OAAO,EAAE,QAAQ;EACjB,eAAe,EAAE,IAAI", "sources": ["file:///Users/josh/Projects/sprockets/test/fixtures/source-maps/sass/precompiled/main.scss"], "names": [], "file": "main.css" }sprockets-3.7.2/test/fixtures/source-maps/sass/precompiled/main.scss000066400000000000000000000002721331222022000257070ustar00rootroot00000000000000nav { ul { margin: 0; padding: 0; list-style: none; } li { display: inline-block; } a { display: block; padding: 6px 12px; text-decoration: none; } } sprockets-3.7.2/test/fixtures/symlink000077700000000000000000000000001331222022000213262defaultustar00rootroot00000000000000sprockets-3.7.2/test/sprockets_test.rb000066400000000000000000000137441331222022000201140ustar00rootroot00000000000000require "minitest/autorun" require "sprockets" require "sprockets/environment" require "fileutils" old_verbose, $VERBOSE = $VERBOSE, false Encoding.default_external = 'UTF-8' Encoding.default_internal = 'UTF-8' $VERBOSE = old_verbose def silence_warnings old_verbose, $VERBOSE = $VERBOSE, false yield ensure $VERBOSE = old_verbose end # Popular extensions for testing but not part of Sprockets core Sprockets.register_dependency_resolver "rand" do rand(2**100) end NoopProcessor = proc { |input| input[:data] } # Sprockets.register_mime_type 'text/haml', extensions: ['.haml'] Sprockets.register_engine '.haml', NoopProcessor, mime_type: 'text/html', silence_deprecation: true # Sprockets.register_mime_type 'text/ng-template', extensions: ['.ngt'] AngularProcessor = proc { |input| <<-EOS $app.run(function($templateCache) { $templateCache.put('#{input[:name]}.html', #{input[:data].chomp.inspect}); }); EOS } Sprockets.register_engine '.ngt', AngularProcessor, mime_type: 'application/javascript', silence_deprecation: true # Sprockets.register_mime_type 'text/mustache', extensions: ['.mustache'] Sprockets.register_engine '.mustache', NoopProcessor, mime_type: 'application/javascript', silence_deprecation: true # Sprockets.register_mime_type 'text/x-handlebars-template', extensions: ['.handlebars'] Sprockets.register_engine '.handlebars', NoopProcessor, mime_type: 'application/javascript', silence_deprecation: true # Sprockets.register_mime_type 'application/javascript-module', extensions: ['.es6'] Sprockets.register_engine '.es6', NoopProcessor, mime_type: 'application/javascript', silence_deprecation: true # Sprockets.register_mime_type 'application/dart', extensions: ['.dart'] Sprockets.register_engine '.dart', NoopProcessor, mime_type: 'application/javascript', silence_deprecation: true require 'nokogiri' HtmlBuilderProcessor = proc { |input| instance_eval <<-EOS builder = Nokogiri::HTML::Builder.new do |doc| #{input[:data]} end builder.to_html EOS } Sprockets.register_mime_type 'application/html+builder', extensions: ['.html.builder'] Sprockets.register_transformer 'application/html+builder', 'text/html', HtmlBuilderProcessor XmlBuilderProcessor = proc { |input| instance_eval <<-EOS builder = Nokogiri::XML::Builder.new do |xml| #{input[:data]} end builder.to_xml EOS } Sprockets.register_mime_type 'application/xml+builder', extensions: ['.xml.builder'] Sprockets.register_transformer 'application/xml+builder', 'application/xml', XmlBuilderProcessor require 'sprockets/jst_processor' Sprockets.register_engine '.jst2', Sprockets::JstProcessor.new(namespace: 'this.JST2'), mime_type: 'application/javascript', silence_deprecation: true SVG2PNG = proc { |input| "\x89\x50\x4e\x47\xd\xa\x1a\xa#{input[:data]}" } Sprockets.register_transformer 'image/svg+xml', 'image/png', SVG2PNG PNG2GIF = proc { |input| "\x47\x49\x46\x38\x37\61#{input[:data]}" } Sprockets.register_transformer 'image/png', 'image/gif', PNG2GIF CSS2HTMLIMPORT = proc { |input| "" } Sprockets.register_transformer 'text/css', 'text/html', CSS2HTMLIMPORT JS2HTMLIMPORT = proc { |input| "" } Sprockets.register_transformer 'application/javascript', 'text/html', JS2HTMLIMPORT Sprockets.register_bundle_metadata_reducer 'text/css', :selector_count, :+ Sprockets.register_postprocessor 'text/css', proc { |input| { selector_count: input[:data].scan(/\{/).size } } SourceMapTransformer = proc { |input| accept = case input[:content_type] when "application/js-sourcemap+json" accept = "application/javascript" when "application/css-sourcemap+json" accept = "text/css" else fail input[:content_type] end uri, _ = input[:environment].resolve!(input[:filename], accept: accept) asset = input[:environment].load(uri) JSON.generate({ "version" => 3, "file" => asset.logical_path, "mappings" => ";123" }) } Sprockets.register_mime_type 'application/js-sourcemap+json', extensions: ['.js.map'] Sprockets.register_mime_type 'application/css-sourcemap+json', extensions: ['.css.map'] Sprockets.register_transformer 'application/javascript', 'application/js-sourcemap+json', SourceMapTransformer Sprockets.register_transformer 'text/css', 'application/css-sourcemap+json', SourceMapTransformer class Sprockets::TestCase < MiniTest::Test FIXTURE_ROOT = File.expand_path(File.join(File.dirname(__FILE__), "fixtures")) def self.test(name, &block) define_method("test_#{name.inspect}", &block) end def fixture(path) IO.read(fixture_path(path)) end def fixture_path(path) if path.match(FIXTURE_ROOT) path else File.join(FIXTURE_ROOT, path) end end def fixture_path_for_uri(path) uri_path(fixture_path(path).to_s) end def uri_path(path) path = '/' + path if path[1] == ':' # Windows path / drive letter path end def sandbox(*paths) backup_paths = paths.select { |path| File.exist?(path) } remove_paths = paths.select { |path| !File.exist?(path) } begin backup_paths.each do |path| FileUtils.cp(path, "#{path}.orig") end yield ensure backup_paths.each do |path| if File.exist?("#{path}.orig") FileUtils.mv("#{path}.orig", path) end assert !File.exist?("#{path}.orig") end remove_paths.each do |path| if File.exist?(path) FileUtils.rm_rf(path) end assert !File.exist?(path) end end end def write(filename, contents, mtime = nil) if File.exist?(filename) mtime ||= [Time.now.to_i, File.stat(filename).mtime.to_i].max + 1 File.open(filename, 'w') do |f| f.write(contents) end File.utime(mtime, mtime, filename) else File.open(filename, 'w') do |f| f.write(contents) end File.utime(mtime, mtime, filename) if mtime end end end module Sprockets module SilenceDeprecation def self.silence(&block) Deprecation.silence(&block) end end end sprockets-3.7.2/test/test_asset.rb000066400000000000000000001261071331222022000172140ustar00rootroot00000000000000require "sprockets_test" module AssetTests def self.test(name, &block) define_method("test_#{name.inspect}", &block) end test "id is a SHA256 String" do assert_kind_of String, @asset.id assert_match(/^[0-9a-f]{64}$/, @asset.id) end test "uri can find itself" do # assert_kind_of URI, @asset.uri assert_equal @asset, @env.load(@asset.uri) end test "pathname is a Pathname that exists" do assert_kind_of Pathname, @asset.pathname assert @asset.pathname.exist? end test "logical path can find itself" do assert_equal @asset, @env[@asset.logical_path] end test "mtime" do assert @asset.mtime end test "length is source length" do assert_equal @asset.to_s.length, @asset.length end test "bytesize is source bytesize" do assert_equal @asset.to_s.bytesize, @asset.bytesize end test "links are a Set" do assert_kind_of Set, @asset.links end test "dependencies are an Array" do assert_kind_of Array, @asset.dependencies end test "splat asset" do assert_kind_of Array, @asset.to_a end test "to_a body parts equals to_s" do source = "" @asset.to_a.each do |asset| source << asset.to_s end assert_equal @asset.to_s, source end test "write to file" do target = fixture_path('asset/tmp.js') begin @asset.write_to(target) assert File.exist?(target) assert_equal @asset.mtime, File.mtime(target) ensure FileUtils.rm(target) if File.exist?(target) assert !File.exist?(target) end end test "write to gzipped file" do target = fixture_path('asset/tmp.js.gz') begin @asset.write_to(target) assert File.exist?(target) assert_equal @asset.mtime, File.mtime(target) ensure FileUtils.rm(target) if File.exist?(target) assert !File.exist?(target) end end def normalize_uri(uri) uri.sub(/id=\w+/, 'id=xxx') end def normalize_uris(uris) uris.to_a.map { |uri| normalize_uri(uri) }.sort end end module FreshnessTests def self.test(name, &block) define_method("test_#{name.inspect}", &block) end test "modify asset contents" do filename = fixture_path('asset/test.js') sandbox filename do write(filename, "a;") asset = asset('test.js') old_digest = asset.hexdigest old_uri = asset.uri assert_equal "a;\n", asset.to_s write(filename, "b;") asset = asset('test.js') refute_equal old_digest, asset.hexdigest refute_equal old_uri, asset.uri assert_equal "b;\n", asset.to_s end end test "remove asset" do filename = fixture_path('asset/test.js') sandbox filename do write(filename, "a;") asset = asset('test.js') File.unlink(filename) refute asset('test.js') end end test "remove asset's dependency file" do main = fixture_path('asset/test-main.js') dep = fixture_path('asset/test-dep.js') sandbox main, dep do write(main, "//= depend_on test-dep\n") write(dep, "a;") asset = asset('test-main.js') File.unlink(dep) assert_raises(Sprockets::FileNotFound) do asset('test-main.js') end end end end class TextStaticAssetTest < Sprockets::TestCase def setup @env = Sprockets::Environment.new @env.append_path(fixture_path('asset')) @env.cache = {} @asset = @env['log.txt'] end include AssetTests test "uri" do assert_equal "file://#{fixture_path_for_uri('asset/log.txt')}?type=text/plain&id=xxx", normalize_uri(@asset.uri) end test "logical path" do assert_equal "log.txt", @asset.logical_path end test "digest path" do assert_equal "log-66a045b452102c59d840ec097d59d9467e13a3f34f6494e539ffd32c1bb35f18.txt", @asset.digest_path end test "content type" do assert_equal "text/plain", @asset.content_type end test "charset is UTF-8" do assert_equal 'utf-8', @asset.charset end test "length" do assert_equal 6, @asset.length end test "bytesize" do assert_equal 6, @asset.bytesize end end class BinaryStaticAssetTest < Sprockets::TestCase def setup @env = Sprockets::Environment.new @env.append_path(fixture_path('asset')) @env.cache = {} @asset = @env['POW.png'] end include AssetTests test "uri" do assert_equal "file://#{fixture_path_for_uri('asset/POW.png')}?type=image/png&id=xxx", normalize_uri(@asset.uri) end test "logical path" do assert_equal "POW.png", @asset.logical_path end test "digest path" do assert_equal "POW-1da2e59df75d33d8b74c3d71feede698f203f136512cbaab20c68a5bdebd5800.png", @asset.digest_path end test "content type" do assert_equal "image/png", @asset.content_type end test "charset is nil" do assert_equal nil, @asset.charset end test "length" do assert_equal 42917, @asset.length end test "bytesize" do assert_equal 42917, @asset.bytesize end test "source digest" do # DEPRECATED: Will be byte digest in 4.x assert_equal "1da2e59df75d33d8b74c3d71feede698f203f136512cbaab20c68a5bdebd5800", @asset.digest end test "source hexdigest" do assert_equal "1da2e59df75d33d8b74c3d71feede698f203f136512cbaab20c68a5bdebd5800", @asset.hexdigest end test "source base64digest" do assert_equal "HaLlnfddM9i3TD1x/u3mmPID8TZRLLqrIMaKW969WAA=", @asset.base64digest end test "integrity" do assert_equal "sha256-HaLlnfddM9i3TD1x/u3mmPID8TZRLLqrIMaKW969WAA=", @asset.integrity end test "splat" do assert_equal [@asset], @asset.to_a end test "dependencies" do assert_equal [], @asset.dependencies end test "asset is fresh if its mtime is changed but its contents is the same" do filename = fixture_path('asset/test-POW.png') sandbox filename do File.open(filename, 'w') { |f| f.write "a" } asset = @env['test-POW.png'] assert asset old_digest = asset.hexdigest old_uri = asset.uri File.open(filename, 'w') { |f| f.write "a" } mtime = Time.now + 1 File.utime(mtime, mtime, filename) assert_equal old_digest, @env['test-POW.png'].hexdigest assert_equal old_uri, @env['test-POW.png'].uri end end test "asset is stale when its contents has changed" do filename = fixture_path('asset/POW.png') sandbox filename do File.open(filename, 'w') { |f| f.write "a" } asset = @env['POW.png'] assert asset old_digest = asset.hexdigest old_uri = asset.uri File.open(filename, 'w') { |f| f.write "b" } mtime = Time.now + 1 File.utime(mtime, mtime, filename) refute_equal old_digest, @env['POW.png'].hexdigest refute_equal old_uri, @env['POW.png'].uri end end test "asset is fresh if the file is removed" do filename = fixture_path('asset/POW.png') sandbox filename do File.open(filename, 'w') { |f| f.write "a" } asset = @env['POW.png'] assert asset File.unlink(filename) refute @env['POW.png'] end end end class SourceAssetTest < Sprockets::TestCase def setup @env = Sprockets::Environment.new @env.append_path(fixture_path('asset')) @env.cache = {} @pipeline = :source @asset = @env.find_asset('application.js', pipeline: :source) end include AssetTests test "uri" do assert_equal "file://#{fixture_path_for_uri('asset/application.js')}?type=application/javascript&pipeline=source&id=xxx", normalize_uri(@asset.uri) end test "logical path" do assert_equal "application.source.js", @asset.logical_path end test "digest path" do assert_equal "application.source-6ae801e02813bf209a84a89b8c5b5edf5eb770ca9e4253c56834c08a2fc5dbea.js", @asset.digest_path end test "content type" do assert_equal "application/javascript", @asset.content_type end test "length" do assert_equal 109, @asset.length end test "source digest" do # DEPRECATED: Will be byte digest in 4.x assert_equal "6ae801e02813bf209a84a89b8c5b5edf5eb770ca9e4253c56834c08a2fc5dbea", @asset.digest end test "source hexdigest" do assert_equal "6ae801e02813bf209a84a89b8c5b5edf5eb770ca9e4253c56834c08a2fc5dbea", @asset.hexdigest end test "source base64digest" do assert_equal "augB4CgTvyCahKibjFte3163cMqeQlPFaDTAii/F2+o=", @asset.base64digest end test "integrity" do assert_equal "sha256-augB4CgTvyCahKibjFte3163cMqeQlPFaDTAii/F2+o=", @asset.integrity end test "splat" do assert_equal [@asset], @asset.to_a end test "dependencies" do assert_equal [], @asset.dependencies end test "to_s" do assert_equal "// =require \"project\"\n// =require \"users\"\n\ndocument.on('dom:loaded', function() {\n $('search').focus();\n});\n", @asset.to_s end test "each" do body = "" @asset.each { |part| body << part } assert_equal "// =require \"project\"\n// =require \"users\"\n\ndocument.on('dom:loaded', function() {\n $('search').focus();\n});\n", body end test "to_a" do body = "" @asset.to_a.each do |asset| body << asset.to_s end assert_equal "\// =require \"project\"\n// =require \"users\"\n\ndocument.on('dom:loaded', function() {\n $('search').focus();\n});\n", body end def asset(logical_path, options = {}) @env.find_asset(logical_path, {:pipeline => @pipeline}.merge(options)) end end class ProcessedAssetTest < Sprockets::TestCase include FreshnessTests def setup @env = Sprockets::Environment.new @env.append_path(fixture_path('asset')) @env.cache = {} @pipeline = :self @asset = @env.find_asset('application.js', pipeline: :self) end include AssetTests test "modify asset's dependency file" do main = fixture_path('asset/test-main.js.erb') dep = fixture_path('asset/test-dep.js') sandbox main, dep do write(main, "//= depend_on test-dep\n<%= File.read('#{dep}') %>") write(dep, "a;") asset = asset('test-main.js') old_digest = asset.hexdigest old_uri = asset.uri assert_equal "a;", asset.to_s write(dep, "b;") asset = asset('test-main.js') refute_equal old_digest, asset.hexdigest refute_equal old_uri, asset.uri assert_equal "b;", asset.to_s end end test "uri" do assert_equal "file://#{fixture_path_for_uri('asset/application.js')}?type=application/javascript&pipeline=self&id=xxx", normalize_uri(@asset.uri) end test "logical path" do assert_equal "application.self.js", @asset.logical_path end test "digest path" do assert_equal "application.self-6a5fff89e8328f158e77642b53e325c24ed844a6bcd5a96ec0f9004384e9c9a5.js", @asset.digest_path end test "content type" do assert_equal "application/javascript", @asset.content_type end test "length" do assert_equal 69, @asset.length end test "source digest" do # DEPRECATED: Will be byte digest in 4.x assert_equal "6a5fff89e8328f158e77642b53e325c24ed844a6bcd5a96ec0f9004384e9c9a5", @asset.digest end test "source hexdigest" do assert_equal "6a5fff89e8328f158e77642b53e325c24ed844a6bcd5a96ec0f9004384e9c9a5", @asset.hexdigest end test "source base64digest" do assert_equal "al//iegyjxWOd2QrU+Mlwk7YRKa81aluwPkAQ4TpyaU=", @asset.base64digest end test "integrity" do assert_equal "sha256-al//iegyjxWOd2QrU+Mlwk7YRKa81aluwPkAQ4TpyaU=", @asset.integrity end test "charset is UTF-8" do assert_equal 'utf-8', @asset.charset end test "splat" do assert_equal [@asset], @asset.to_a end test "dependencies" do assert_equal [], @asset.dependencies end test "to_s" do assert_equal "\n\n\ndocument.on('dom:loaded', function() {\n $('search').focus();\n});\n", @asset.to_s end test "each" do body = "" @asset.each { |part| body << part } assert_equal "\n\n\ndocument.on('dom:loaded', function() {\n $('search').focus();\n});\n", body end test "to_a" do body = "" @asset.to_a.each do |asset| body << asset.to_s end assert_equal "\n\n\ndocument.on('dom:loaded', function() {\n $('search').focus();\n});\n", body end def asset(logical_path, options = {}) @env.find_asset(logical_path, {:pipeline => @pipeline}.merge(options)) end end class BundledAssetTest < Sprockets::TestCase include FreshnessTests def setup @env = Sprockets::Environment.new @env.append_path(fixture_path('asset')) @env.cache = {} @pipeline = nil @asset = @env['application.js'] end include AssetTests test "modify asset's dependency file" do main = fixture_path('asset/test-main.js.erb') dep = fixture_path('asset/test-dep.js') sandbox main, dep do write(main, "//= depend_on test-dep\n<%= File.read('#{dep}') %>") write(dep, "a;") asset = asset('test-main.js') old_digest = asset.hexdigest old_uri = asset.uri assert_equal "a;\n", asset.to_s write(dep, "b;") asset = asset('test-main.js') refute_equal old_digest, asset.hexdigest refute_equal old_uri, asset.uri assert_equal "b;\n", asset.to_s end end test "uri" do assert_equal "file://#{fixture_path_for_uri('asset/application.js')}?type=application/javascript&id=xxx", normalize_uri(@asset.uri) end test "logical path" do assert_equal "application.js", @asset.logical_path end test "digest path" do assert_equal "application-955b2dddd0d1449b1c617124b83b46300edadec06d561104f7f6165241b31a94.js", @asset.digest_path end test "content type" do assert_equal "application/javascript", @asset.content_type end test "length" do assert_equal 159, @asset.length end test "source digest" do # DEPRECATED: Will be byte digest in 4.x assert_equal "955b2dddd0d1449b1c617124b83b46300edadec06d561104f7f6165241b31a94", @asset.digest end test "source hexdigest" do assert_equal "955b2dddd0d1449b1c617124b83b46300edadec06d561104f7f6165241b31a94", @asset.hexdigest end test "source base64digest" do assert_equal "lVst3dDRRJscYXEkuDtGMA7a3sBtVhEE9/YWUkGzGpQ=", @asset.base64digest end test "integrity" do assert_equal "sha256-lVst3dDRRJscYXEkuDtGMA7a3sBtVhEE9/YWUkGzGpQ=", @asset.integrity end test "charset is UTF-8" do assert_equal 'utf-8', @asset.charset end test "to_s" do assert_equal "var Project = {\n find: function(id) {\n }\n};\nvar Users = {\n find: function(id) {\n }\n};\n\n\n\ndocument.on('dom:loaded', function() {\n $('search').focus();\n});\n", @asset.to_s end test "each" do body = "" @asset.each { |part| body << part } assert_equal "var Project = {\n find: function(id) {\n }\n};\nvar Users = {\n find: function(id) {\n }\n};\n\n\n\ndocument.on('dom:loaded', function() {\n $('search').focus();\n});\n", body end test "asset is stale when one of its source files is modified" do main = fixture_path('asset/test-main.js') dep = fixture_path('asset/test-dep.js') sandbox main, dep do File.open(main, 'w') { |f| f.write "//= require test-dep\n" } File.open(dep, 'w') { |f| f.write "a;" } asset = asset('test-main.js') old_digest = asset.hexdigest old_uri = asset.uri File.open(dep, 'w') { |f| f.write "b;" } mtime = Time.now + 1 File.utime(mtime, mtime, dep) refute_equal old_digest, asset('test-main.js').hexdigest refute_equal old_uri, asset('test-main.js').uri end end test "asset is stale when one of its asset dependencies is modified" do main = fixture_path('asset/test-main.js') dep = fixture_path('asset/test-dep.js') sandbox main, dep do File.open(main, 'w') { |f| f.write "//= depend_on_asset test-dep\n" } File.open(dep, 'w') { |f| f.write "a;" } asset = asset('test-main.js') old_digest = asset.hexdigest old_uri = asset.uri File.open(dep, 'w') { |f| f.write "b;" } mtime = Time.now + 1 File.utime(mtime, mtime, dep) asset = asset('test-main.js') assert_equal old_digest, asset.hexdigest refute_equal old_uri, asset.uri end end test "asset is stale when one of its source files dependencies is modified" do a = fixture_path('asset/test-a.js') b = fixture_path('asset/test-b.js') c = fixture_path('asset/test-c.js') sandbox a, b, c do File.open(a, 'w') { |f| f.write "//= require test-b\n" } File.open(b, 'w') { |f| f.write "//= require test-c\n" } File.open(c, 'w') { |f| f.write "c;" } asset_a = asset('test-a.js') asset_b = asset('test-b.js') asset_c = asset('test-c.js') old_asset_a_digest = asset_a.hexdigest old_asset_b_digest = asset_b.hexdigest old_asset_c_digest = asset_c.hexdigest old_asset_a_uri = asset_a.uri old_asset_b_uri = asset_b.uri old_asset_c_uri = asset_c.uri File.open(c, 'w') { |f| f.write "x;" } mtime = Time.now + 1 File.utime(mtime, mtime, c) refute_equal old_asset_a_digest, asset('test-a.js').hexdigest refute_equal old_asset_b_digest, asset('test-b.js').hexdigest refute_equal old_asset_c_digest, asset('test-c.js').hexdigest refute_equal old_asset_a_uri, asset('test-a.js').uri refute_equal old_asset_b_uri, asset('test-b.js').uri refute_equal old_asset_c_uri, asset('test-c.js').uri end end test "asset is stale when one of its dependency dependencies is modified" do a = fixture_path('asset/test-a.js') b = fixture_path('asset/test-b.js') c = fixture_path('asset/test-c.js') sandbox a, b, c do File.open(a, 'w') { |f| f.write "//= require test-b\n" } File.open(b, 'w') { |f| f.write "//= depend_on test-c\n" } File.open(c, 'w') { |f| f.write "c;" } asset_a = asset('test-a.js') asset_b = asset('test-b.js') asset_c = asset('test-c.js') old_asset_a_uri = asset_a.uri old_asset_b_uri = asset_b.uri old_asset_c_uri = asset_c.uri File.open(c, 'w') { |f| f.write "x;" } mtime = Time.now + 1 File.utime(mtime, mtime, c) refute_equal old_asset_a_uri, asset('test-a.js').uri refute_equal old_asset_b_uri, asset('test-b.js').uri refute_equal old_asset_c_uri, asset('test-c.js').uri end end test "asset is stale when one of its asset dependency dependencies is modified" do a = fixture_path('asset/test-a.js') b = fixture_path('asset/test-b.js') c = fixture_path('asset/test-c.js') sandbox a, b, c do File.open(a, 'w') { |f| f.write "//= depend_on_asset test-b\n" } File.open(b, 'w') { |f| f.write "//= depend_on_asset test-c\n" } File.open(c, 'w') { |f| f.write "c;" } asset_a = asset('test-a.js') asset_b = asset('test-b.js') asset_c = asset('test-c.js') old_asset_a_uri = asset_a.uri old_asset_b_uri = asset_b.uri old_asset_c_uri = asset_c.uri File.open(c, 'w') { |f| f.write "x;" } mtime = Time.now + 1 File.utime(mtime, mtime, c) refute_equal old_asset_a_uri, asset('test-a.js').uri refute_equal old_asset_b_uri, asset('test-b.js').uri refute_equal old_asset_c_uri, asset('test-c.js').uri end end test "asset is stale when one of its linked assets is modified" do a = fixture_path('asset/test-a.js') b = fixture_path('asset/test-b.js') sandbox a, b do File.open(a, 'w') { |f| f.write "//= link test-b\n" } File.open(b, 'w') { |f| f.write "b;" } asset_a = asset('test-a.js') asset_b = asset('test-b.js') old_asset_a_uri = asset_a.uri old_asset_b_uri = asset_b.uri File.open(b, 'w') { |f| f.write "x;" } mtime = Time.now + 1 File.utime(mtime, mtime, b) refute_equal old_asset_a_uri, asset('test-a.js').uri refute_equal old_asset_b_uri, asset('test-b.js').uri end end test "erb asset is stale when one of its linked assets is modified" do a = fixture_path('asset/test-a.js.erb') b = fixture_path('asset/test-b.js.erb') sandbox a, b do File.open(a, 'w') { |f| f.write "<% link_asset 'test-b' %>\n" } File.open(b, 'w') { |f| f.write "b;" } asset_a = asset('test-a.js') asset_b = asset('test-b.js') old_asset_a_uri = asset_a.uri old_asset_b_uri = asset_b.uri File.open(b, 'w') { |f| f.write "x;" } mtime = Time.now + 1 File.utime(mtime, mtime, b) refute_equal old_asset_a_uri, asset('test-a.js').uri refute_equal old_asset_b_uri, asset('test-b.js').uri end end test "asset is stale if a file is added to its require directory" do asset = asset("tree/all_with_require_directory.js") assert asset old_uri = asset.uri dirname = File.join(fixture_path("asset"), "tree/all") filename = File.join(dirname, "z.js") sandbox filename do File.open(filename, 'w') { |f| f.write "z" } mtime = Time.now + 1 File.utime(mtime, mtime, dirname) refute_equal old_uri, asset("tree/all_with_require_directory.js").uri end end test "asset is stale if a file is added to its require tree" do asset = asset("tree/all_with_require_tree.js") assert asset old_uri = asset.uri dirname = File.join(fixture_path("asset"), "tree/all/b/c") filename = File.join(dirname, "z.js") sandbox filename do File.open(filename, 'w') { |f| f.write "z" } mtime = Time.now + 1 File.utime(mtime, mtime, dirname) refute_equal old_uri, asset("tree/all_with_require_tree.js").uri end end test "asset is stale if its declared dependency changes" do sprite = fixture_path('asset/sprite.css.erb') image = fixture_path('asset/POW.png') sandbox sprite, image do asset = asset('sprite.css') assert asset old_uri = asset.uri File.open(image, 'w') { |f| f.write "(change)" } mtime = Time.now + 1 File.utime(mtime, mtime, image) refute_equal old_uri, asset('sprite.css').uri end end test "asset if stale if once of its source files is removed" do main = fixture_path('asset/test-main.js') dep = fixture_path('asset/test-dep.js') sandbox main, dep do File.open(main, 'w') { |f| f.write "//= require test-dep\n" } File.open(dep, 'w') { |f| f.write "a;" } assert asset('test-main.js') File.unlink(dep) assert_raises(Sprockets::FileNotFound) do asset('test-main.js') end end end test "asset is stale when one of its stubbed targets dependencies are modified" do frameworks = fixture_path('asset/stub-frameworks.js') app = fixture_path('asset/stub-app.js') jquery = fixture_path('asset/stub-jquery.js') sandbox frameworks, app, jquery do write(frameworks, "frameworks = {};") write(app, "//= stub stub-frameworks\n//= require stub-jquery\napp = {};") write(jquery, "jquery = {};") asset_jquery = asset('stub-jquery.js', pipeline: :self) refute asset('stub-frameworks.js').included.include?(asset_jquery.uri) assert asset('stub-app.js').included.include?(asset_jquery.uri) old_asset_frameworks_uri = asset('stub-frameworks.js').uri old_asset_app_uri = asset('stub-app.js').uri write(frameworks, "//= require stub-jquery\nframeworks = {};") # jquery never changed assert_equal asset_jquery.uri, asset('stub-jquery.js', pipeline: :self).uri # jquery moved from app to frameworks assert asset('stub-frameworks.js').included.include?(asset_jquery.uri) refute asset('stub-app.js').included.include?(asset_jquery.uri) refute_equal old_asset_frameworks_uri, asset('stub-frameworks.js').uri refute_equal old_asset_app_uri, asset('stub-app.js').uri end end test "mtime is based on required assets" do required_asset = fixture_path('asset/dependencies/b.js') sandbox required_asset do mtime = Time.now + 1 File.utime mtime, mtime, required_asset assert_equal mtime.to_i, asset('required_assets.js').mtime.to_i end end test "mtime is based on dependency paths" do asset_dependency = fixture_path('asset/dependencies/b.js') sandbox asset_dependency do mtime = Time.now + 1 File.utime mtime, mtime, asset_dependency assert_equal mtime.to_i, asset('dependency_paths.js').mtime.to_i end end test "mtime is based on absolute dependency paths" do asset_dependency = fixture_path('asset/dependencies/b.js') sandbox asset_dependency do mtime = Time.now + 1 File.utime mtime, mtime, asset_dependency assert_equal mtime.to_i, asset('absolute_dependency_paths.js').mtime.to_i end end test "requiring the same file multiple times has no effect" do assert_equal read("asset/project.js.erb")+"\n\n\n", asset("multiple.js").to_s end test "requiring a file of a different format raises an exception" do assert_raises Sprockets::FileNotFound do asset("mismatch.js") end end test "splatted asset includes itself" do assert_equal [fixture_path("asset/project.js.erb")], asset("project.js").to_a.map(&:filename) end test "splatted asset with child dependencies" do assert_equal [fixture_path("asset/project.js.erb"), fixture_path("asset/users.js.erb"), fixture_path("asset/application.js")], asset("application.js").to_a.map(&:filename) end test "asset dependencies with child dependencies" do assert_equal [fixture_path("asset/project.js.erb"), fixture_path("asset/users.js.erb")], asset("application.js").dependencies.map(&:filename) end test "bundling joins files with blank line" do assert_equal "var Project = {\n find: function(id) {\n }\n};\nvar Users = {\n find: function(id) {\n }\n};\n\n\n\ndocument.on('dom:loaded', function() {\n $('search').focus();\n});\n", asset("application.js").to_s end test "dependencies appear in the source before files that required them" do assert_match(/Project.+Users.+focus/m, asset("application.js").to_s) end test "processing a source file with no engine extensions" do assert_equal read("asset/users.js.erb"), asset("noengine.js").to_s end test "processing a source file with one engine extension" do assert_equal read("asset/users.js.erb"), asset("oneengine.js").to_s end test "processing a source file with multiple engine extensions" do assert_equal read("asset/users.js.erb"), asset("multipleengine.js").to_s end test "processing a source file with unknown extensions" do assert_equal read("asset/users.js.erb") + "var jQuery;\n\n\n", asset("unknownexts.min.js").to_s end test "requiring a file with a relative path" do assert_equal read("asset/project.js.erb") + "\n", asset("relative/require.js").to_s end test "can't require files outside the load path" do assert !@env.paths.include?(fixture_path("default")), @env.paths.inspect assert_raises Sprockets::FileNotFound do asset("relative/require_outside_path.js") end end test "can't require files in another load path" do @env.append_path(fixture_path("default")) assert @env.paths.include?(fixture_path("default")), @env.paths.inspect assert_raises Sprockets::FileNotFound do asset("relative/require_other_load_path.js") end end test "can't require absolute files outside the load path" do assert_raises Sprockets::FileOutsidePaths do asset("absolute/require_outside_path.js").to_s end end test "require_directory requires all child files in alphabetical order" do assert_equal( "ok(\"b.js.erb\");\n", asset("tree/all_with_require_directory.js").to_s ) end test "require_directory current directory includes self last" do assert_equal( "var Bar;\nvar Foo;\nvar App;\n", asset("tree/directory/application.js").to_s ) end test "require_tree requires all descendant files in alphabetical order" do assert_equal( asset("tree/all_with_require.js").to_s, asset("tree/all_with_require_tree.js").to_s + "\n\n\n\n\n\n" ) end test "require_tree without an argument defaults to the current directory" do assert_equal( "a();\nb();\n", asset("tree/without_argument/require_tree_without_argument.js").to_s ) end test "require_tree with current directory includes self last" do assert_equal( "var Bar;\nvar Foo;\nvar App;\n", asset("tree/tree/application.js").to_s ) end test "require_tree with a logical path argument raises an exception" do assert_raises(Sprockets::ArgumentError) do asset("tree/with_logical_path/require_tree_with_logical_path.js").to_s end end test "require_tree with a nonexistent path raises an exception" do assert_raises(Sprockets::ArgumentError) do asset("tree/with_logical_path/require_tree_with_nonexistent_path.js").to_s end end test "require_tree with a nonexistent absolute path raises an exception" do assert_raises(Sprockets::ArgumentError) do asset("absolute/require_nonexistent_path.js").to_s end end test "require_tree respects order of child dependencies" do assert_equal( "var c;\nvar b;\nvar a;\n\n", asset("tree/require_tree_alpha.js").to_s ) end test "require_self inserts the current file's body at the specified point" do assert_equal "/* b.css */\n\nb { display: none }\n/*\n\n\n\n */\n\n\nbody {}\n.project {}\n", asset("require_self.css").to_s end test "multiple require_self directives raises and error" do assert_raises(Sprockets::ArgumentError) do asset("require_self_twice.css") end end test "linked asset depends on target asset" do assert asset = asset("require_manifest.js") assert_equal <<-EOS, asset.to_s define("application.js", "application-955b2dddd0d1449b1c617124b83b46300edadec06d561104f7f6165241b31a94.js") define("application.css", "application-46d50149c56fc370805f53c29f79b89a52d4cc479eeebcdc8db84ab116d7ab1a.css") define("POW.png", "POW-1da2e59df75d33d8b74c3d71feede698f203f136512cbaab20c68a5bdebd5800.png") ; EOS assert_equal [ "file://#{fixture_path_for_uri("asset/POW.png")}?type=image/png&id=xxx", "file://#{fixture_path_for_uri("asset/application.css")}?type=text/css&id=xxx", "file://#{fixture_path_for_uri("asset/application.js")}?type=application/javascript&id=xxx" ], normalize_uris(asset.links) end test "directive linked asset depends on target asset" do assert asset = asset("require_manifest2.js") assert_equal <<-EOS, asset.to_s define("application.js", "application-955b2dddd0d1449b1c617124b83b46300edadec06d561104f7f6165241b31a94.js") define("application.css", "application-46d50149c56fc370805f53c29f79b89a52d4cc479eeebcdc8db84ab116d7ab1a.css") define("POW.png", "POW-1da2e59df75d33d8b74c3d71feede698f203f136512cbaab20c68a5bdebd5800.png") ; EOS assert_equal [ "file://#{fixture_path_for_uri("asset/POW.png")}?type=image/png&id=xxx", "file://#{fixture_path_for_uri("asset/application.css")}?type=text/css&id=xxx", "file://#{fixture_path_for_uri("asset/application.js")}?type=application/javascript&id=xxx" ], normalize_uris(asset.links) end test "link_directory current directory includes self last" do assert_equal [ "file://#{fixture_path_for_uri("asset/link/directory/bar.js")}?type=application/javascript&id=xxx", "file://#{fixture_path_for_uri("asset/link/directory/foo.js")}?type=application/javascript&id=xxx" ], normalize_uris(asset("link/directory/application.js").links) end test "link_tree requires all descendant files in alphabetical order" do assert_equal normalize_uris(asset("link/all_with_require.js").links), normalize_uris(asset("link/all_with_require_tree.js").links) end test "link_tree without an argument defaults to the current directory" do assert_equal [ "file://#{fixture_path_for_uri("asset/link/without_argument/a.js")}?type=application/javascript&id=xxx", "file://#{fixture_path_for_uri("asset/link/without_argument/b.js")}?type=application/javascript&id=xxx" ], normalize_uris(asset("link/without_argument/require_tree_without_argument.js").links) end test "link_tree with current directory includes self last" do assert_equal [ "file://#{fixture_path_for_uri("asset/link/tree/bar.js")}?type=application/javascript&id=xxx", "file://#{fixture_path_for_uri("asset/link/tree/foo.js")}?type=application/javascript&id=xxx" ], normalize_uris(asset("link/tree/application.js").links) end test "link_tree with a logical path argument raises an exception" do assert_raises(Sprockets::ArgumentError) do asset("link/with_logical_path/require_tree_with_logical_path.js") end end test "link_tree with a nonexistent path raises an exception" do assert_raises(Sprockets::ArgumentError) do asset("link/with_logical_path/require_tree_with_nonexistent_path.js") end end test "link_directory requires all child files in alphabetical order" do assert_equal [ "file://#{fixture_path_for_uri("asset/link/all/README.md")}?id=xxx", "file://#{fixture_path_for_uri("asset/link/all/b.css")}?type=text/css&id=xxx", "file://#{fixture_path_for_uri("asset/link/all/b.js.erb")}?type=application/javascript&id=xxx" ], normalize_uris(asset("link/all_with_require_directory.js").links) end test "link_directory as app/js requires all child files in alphabetical order" do assert_equal [ "file://#{fixture_path_for_uri("asset/link/all/b.js.erb")}?type=application/javascript&id=xxx" ], normalize_uris(asset("link/all_with_require_directory_as_js.js").links) end test "link_tree respects order of child dependencies" do assert_equal [ "file://#{fixture_path_for_uri("asset/link/alpha/a.js")}?type=application/javascript&id=xxx", "file://#{fixture_path_for_uri("asset/link/alpha/b.js")}?type=application/javascript&id=xxx", "file://#{fixture_path_for_uri("asset/link/alpha/c.js")}?type=application/javascript&id=xxx" ], normalize_uris(asset("link/require_tree_alpha.js").links) end test "link_tree as app/js respects order of child dependencies" do assert_equal [ "file://#{fixture_path_for_uri("asset/link/alpha/a.js")}?type=application/javascript&id=xxx", "file://#{fixture_path_for_uri("asset/link/alpha/b.js")}?type=application/javascript&id=xxx", "file://#{fixture_path_for_uri("asset/link/alpha/c.js")}?type=application/javascript&id=xxx" ], normalize_uris(asset("link/require_tree_alpha_as_js.js").links) end test "link_asset with uri" do assert asset = asset("link/asset_uri.css") assert_equal <<-EOS, asset.to_s .logo { background: url(POW-1da2e59df75d33d8b74c3d71feede698f203f136512cbaab20c68a5bdebd5800.png); } EOS assert_equal [ "file://#{fixture_path_for_uri("asset/POW.png")}?type=image/png&id=xxx" ], normalize_uris(asset.links) end test "stub single dependency" do assert_equal "var jQuery.UI = {};\n\n\n", asset("stub/skip_jquery").to_s end test "stub dependency tree" do assert_equal "var Foo = {};\n\n\n\n", asset("stub/application").to_s end test "resolves circular requires" do assert_equal "var A;\nvar C;\nvar B;\n", asset("circle/a.js").to_s assert_equal "var B;\nvar A;\nvar C;\n", asset("circle/b.js").to_s assert_equal "var C;\nvar B;\nvar A;\n", asset("circle/c.js").to_s end test "unknown directives are ignored" do assert_equal "var Project = {\n find: function(id) {\n }\n};\n\n//\n// = Foo\n//\n// == Examples\n//\n// Foo.bar()\n// => \"baz\"\nvar Foo;\n", asset("unknown_directives.js").to_s end test "__FILE__ is properly set in templates" do assert_equal %(var filename = "#{fixture_path("asset/filename.js.erb")}";\n), asset("filename.js").to_s end test "asset inherits the format extension and content type of the original file" do asset = asset("project.js") assert_equal "application/javascript", asset.content_type end test "asset falls back to engines default mime type" do asset = asset("default_mime_type.js") assert_equal "application/javascript", asset.content_type end test "asset is a rack response body" do body = "" asset("project.js").each { |part| body += part } assert_equal asset("project.js").to_s, body end test "asset length is source length with unicode characters" do assert_equal 8, asset("unicode.js").length end test "asset length is source bytesize with unicode characters" do assert_equal 8, asset("unicode.js").bytesize end test "asset digest" do assert asset("project.js").hexdigest end test "project digest path" do assert_equal "project-9f8d317511370805ee292b685e9bcc4227bb901f8fd6ce82157d1845651ff6da.js", asset("project.js").digest_path end test "multiple charset defintions are stripped from css bundle" do assert_equal "\n.foo {}\n\n.bar {}\n\n\n", asset("charset.css").to_s end test "appends missing semicolons" do assert_equal "var Bar\n;\n\n(function() {\n var Foo\n})\n;\n", asset("semicolons.js").to_s end test "should not fail if home is not set in environment" do begin home, ENV["HOME"] = ENV["HOME"], nil env = Sprockets::Environment.new env.append_path(fixture_path('asset')) env['application.js'] rescue Exception flunk ensure ENV["HOME"] = home end end def asset(logical_path, options = {}) @env.find_asset(logical_path, {:pipeline => @pipeline}.merge(options)) end def read(logical_path) File.read(fixture_path(logical_path)) end end class AssetLogicalPathTest < Sprockets::TestCase def setup @env = Sprockets::Environment.new @env.append_path(fixture_path('paths')) end test "logical path" do assert_equal "empty", logical_path("empty") assert_equal "application.js", logical_path("application.js") assert_equal "application.css", logical_path("application.css") assert_equal "application.js", logical_path("application.js.erb") assert_equal "application.js", logical_path("application.js.coffee") assert_equal "application.css", logical_path("application.css.scss") assert_equal "project.js", logical_path("project.js.coffee.erb") assert_equal "store.css", logical_path("store.css.erb") assert_equal "store.foo", logical_path("store.foo") assert_equal "files.txt", logical_path("files.erb") assert_equal "application.js", logical_path("application.coffee") assert_equal "application.css", logical_path("application.scss") assert_equal "hello.js", logical_path("hello.jst.ejs") assert_equal "bower/main.js", logical_path("bower/main.js") assert_equal "bower/bower.json", logical_path("bower/bower.json") assert_equal "coffee/index.js", logical_path("coffee/index.js") assert_equal "coffee/foo.js", logical_path("coffee/foo.coffee") assert_equal "jquery.js", logical_path("jquery.js") assert_equal "jquery.min.js", logical_path("jquery.min.js") assert_equal "jquery.csv.js", logical_path("jquery.csv.js") assert_equal "jquery.csv.min.js", logical_path("jquery.csv.min.js") assert_equal "jquery.foo.min.js", logical_path("jquery.foo.min.js") assert_equal "jquery.tmpl.js", logical_path("jquery.tmpl.js") assert_equal "jquery.tmpl.min.js", logical_path("jquery.tmpl.min.js") assert_equal "jquery.ext/index.js", logical_path("jquery.ext/index.js") assert_equal "jquery.ext/form.js", logical_path("jquery.ext/form.js") assert_equal "jquery-coffee.min.js", logical_path("jquery-coffee.min.coffee") assert_equal "jquery-custom.min.js", logical_path("jquery-custom.min.js.erb") assert_equal "jquery.js.min", logical_path("jquery.js.min") assert_equal "all.coffee/plain.js", logical_path("all.coffee/plain.js") assert_equal "all.coffee/hot.js", logical_path("all.coffee/hot.coffee") assert_equal "all.coffee/index.js", logical_path("all.coffee/index.coffee") assert_equal "foo-ng.js", logical_path("foo-ng.ngt") assert_equal "bar-ng.js", logical_path("bar-ng.ngt.haml") assert_equal "baz-ng.js", logical_path("baz-ng.js.ngt") assert_equal "sprite.css.embed", logical_path("sprite.css.embed") assert_equal "traceur.js", logical_path("traceur.es6") assert_equal "traceur.js", logical_path("traceur.js.es6") end def logical_path(path) filename = fixture_path("paths/#{path}") assert File.exist?(filename), "#{filename} does not exist" silence_warnings do assert asset = @env.find_asset(filename), "couldn't find asset: #{filename}" asset.logical_path end end end class AssetContentTypeTest < Sprockets::TestCase def setup @env = Sprockets::Environment.new @env.append_path(fixture_path('paths')) end test "content type" do assert_equal nil, content_type("empty") assert_equal "application/javascript", content_type("application.js") assert_equal "text/css", content_type("application.css") assert_equal "application/javascript", content_type("application.js.erb") assert_equal "application/javascript", content_type("application.js.coffee") assert_equal "text/css", content_type("application.css.scss") assert_equal "application/javascript", content_type("project.js.coffee.erb") assert_equal "text/css", content_type("store.css.erb") assert_equal "text/plain", content_type("files.erb") assert_equal nil, content_type("store.foo") assert_equal "application/javascript", content_type("application.coffee") assert_equal "text/css", content_type("application.scss") assert_equal "application/javascript", content_type("hello.jst.ejs") assert_equal "application/javascript", content_type("bower/main.js") assert_equal "application/json", content_type("bower/bower.json") assert_equal "application/javascript", content_type("coffee/index.js") assert_equal "application/javascript", content_type("coffee/foo.coffee") assert_equal "application/javascript", content_type("jquery.js") assert_equal "application/javascript", content_type("jquery.min.js") assert_equal "application/javascript", content_type("jquery.csv.js") assert_equal "application/javascript", content_type("jquery.csv.min.js") assert_equal "application/javascript", content_type("jquery.foo.min.js") assert_equal "application/javascript", content_type("jquery.tmpl.js") assert_equal "application/javascript", content_type("jquery.tmpl.min.js") assert_equal "application/javascript", content_type("jquery.ext/index.js") assert_equal "application/javascript", content_type("jquery.ext/form.js") assert_equal "application/javascript", content_type("jquery-coffee.min.coffee") assert_equal "application/javascript", content_type("jquery-custom.min.js.erb") assert_equal nil, content_type("jquery.js.min") assert_equal "application/javascript", content_type("all.coffee/plain.js") assert_equal "application/javascript", content_type("all.coffee/hot.coffee") assert_equal "application/javascript", content_type("all.coffee/index.coffee") assert_equal "application/javascript", content_type("foo-ng.ngt") assert_equal "application/javascript", content_type("bar-ng.ngt.haml") assert_equal "application/javascript", content_type("baz-ng.js.ngt") assert_equal nil, content_type("sprite.css.embed") assert_equal "application/javascript", content_type("traceur.es6") assert_equal "application/javascript", content_type("traceur.js.es6") end def content_type(path) filename = fixture_path("paths/#{path}") assert File.exist?(filename), "#{filename} does not exist" silence_warnings do assert asset = @env.find_asset(filename), "couldn't find asset: #{filename}" asset.content_type end end end sprockets-3.7.2/test/test_bundle.rb000066400000000000000000000073531331222022000173470ustar00rootroot00000000000000require 'sprockets_test' class TestStylesheetBundle < Sprockets::TestCase test "bundle single stylesheet file" do environment = Sprockets::Environment.new environment.append_path fixture_path('asset') filename = fixture_path('asset/project.css') assert File.exist?(filename) input = { environment: environment, uri: "file://#{filename}?type=text/css", filename: filename, content_type: 'text/css', metadata: {} } data = ".project {}\n" result = Sprockets::Bundle.call(input) assert_equal data, result[:data] assert_equal ["file-digest://#{uri_path(filename)}"], result[:dependencies].to_a.sort.select { |dep| dep.start_with?("file-digest:") } end test "bundle multiple stylesheet files" do environment = Sprockets::Environment.new environment.append_path fixture_path('asset') filename = fixture_path('asset/require_self.css') assert File.exist?(filename) input = { environment: environment, uri: "file://#{filename}?type=text/css", filename: filename, content_type: 'text/css', metadata: {} } data = "/* b.css */\n\nb { display: none }\n/*\n\n\n\n */\n\n\nbody {}\n.project {}\n" result = Sprockets::Bundle.call(input) assert_equal data, result[:data] assert_equal [ "file-digest://" + fixture_path_for_uri('asset'), "file-digest://" + fixture_path_for_uri('asset/project'), "file-digest://" + fixture_path_for_uri('asset/project.css'), "file-digest://" + fixture_path_for_uri('asset/require_self.css'), "file-digest://" + fixture_path_for_uri('asset/tree/all'), "file-digest://" + fixture_path_for_uri('asset/tree/all/b'), "file-digest://" + fixture_path_for_uri('asset/tree/all/b.css') ], result[:dependencies].to_a.sort.select { |dep| dep.start_with?("file-digest:") } end test "bundle single javascript file" do environment = Sprockets::Environment.new environment.append_path fixture_path('asset') filename = fixture_path('asset/project.js.erb') assert File.exist?(filename) input = { environment: environment, uri: "file://#{filename}?type=application/javascript", filename: filename, content_type: 'application/javascript', metadata: {} } data = "var Project = {\n find: function(id) {\n }\n};\n" result = Sprockets::Bundle.call(input) assert_equal data, result[:data] assert_equal ["file-digest://#{uri_path(filename)}"], result[:dependencies].to_a.sort.select { |dep| dep.start_with?("file-digest:") } end test "bundle multiple javascript files" do environment = Sprockets::Environment.new environment.append_path fixture_path('asset') filename = fixture_path('asset/application.js') assert File.exist?(filename) input = { environment: environment, uri: "file://#{filename}?type=application/javascript", filename: filename, content_type: 'application/javascript', metadata: {} } data = "var Project = {\n find: function(id) {\n }\n};\nvar Users = {\n find: function(id) {\n }\n};\n\n\n\ndocument.on('dom:loaded', function() {\n $('search').focus();\n});\n" result = Sprockets::Bundle.call(input) assert_equal data, result[:data] assert_equal [ "file-digest://" + fixture_path_for_uri('asset'), "file-digest://" + fixture_path_for_uri('asset/application.js'), "file-digest://" + fixture_path_for_uri('asset/project'), "file-digest://" + fixture_path_for_uri('asset/project.js.erb'), "file-digest://" + fixture_path_for_uri('asset/users'), "file-digest://" + fixture_path_for_uri('asset/users.js.erb') ], result[:dependencies].to_a.sort.select { |dep| dep.start_with?("file-digest:") } end end sprockets-3.7.2/test/test_cache_store.rb000066400000000000000000000103461331222022000203510ustar00rootroot00000000000000require 'minitest/autorun' require 'tmpdir' require 'fileutils' require 'sprockets/cache' require 'sprockets/cache/file_store' require 'sprockets/cache/memory_store' require 'sprockets/cache/null_store' module CacheStoreNullTests def test_read refute @store.get("foo") end def test_write result = @store.set("foo", "bar") assert_equal "bar", result end def test_write_and_read_miss @store.set("foo", "bar") refute @store.get("foo") end def test_fetch result = @store.fetch("foo") { "bar" } assert_equal "bar", result end end module CacheStoreTests def test_read_miss refute @store.get("missing") end def test_write result = @store.set("foo", "bar") assert_equal "bar", result end def test_write_and_read_hit @store.set("foo", "bar") assert_equal "bar", @store.get("foo") end def test_multiple_write_and_read_hit @store.set("foo", "1") @store.set("bar", "2") @store.set("baz", "3") assert_equal "1", @store.get("foo") assert_equal "2", @store.get("bar") assert_equal "3", @store.get("baz") end def test_large_write_and_read_hit data = ("a"..."zzz").to_a.join @store.set("foo", data) assert_equal data, @store.get("foo") end def test_delete @store.set("foo", "bar") assert_equal "bar", @store.get("foo") @store.set("foo", nil) assert_equal nil, @store.get("foo") end def test_fetch result = @store.fetch("user") { "josh" } assert_equal "josh", result end end class TestNullStore < MiniTest::Test def setup @_store = Sprockets::Cache::NullStore.new @store = Sprockets::Cache.new(Sprockets::Cache::NullStore.new) end def test_inspect assert_equal "# store=#>", @store.inspect assert_equal "#", @_store.inspect end include CacheStoreNullTests end class TestMemoryStore < MiniTest::Test def setup @_store = Sprockets::Cache::MemoryStore.new @store = Sprockets::Cache.new(@_store) end def test_inspect assert_equal "#", @_store.inspect end include CacheStoreTests def test_get_with_lru @_store.set(:a, 1) @_store.set(:b, 2) @_store.set(:c, 3) assert_equal [1, 2, 3], @_store.instance_variable_get(:@cache).values @_store.get(:a) @_store.set(:d, 4) assert_equal [2, 3, 1, 4], @_store.instance_variable_get(:@cache).values end def test_set_with_lru @_store.set(:a, 1) @_store.set(:b, 2) @_store.set(:c, 3) assert_equal [1, 2, 3], @_store.instance_variable_get(:@cache).values @_store.set(:a, 1) @_store.set(:d, 4) assert_equal [2, 3, 1, 4], @_store.instance_variable_get(:@cache).values end end class TestZeroMemoryStore < MiniTest::Test def setup @_store = Sprockets::Cache::MemoryStore.new(0) @store = Sprockets::Cache.new(@_store) end def test_inspect assert_equal "#", @_store.inspect end include CacheStoreNullTests end class TestFileStore < MiniTest::Test def setup @root = Dir::mktmpdir "sprockets-file-store" @_store = Sprockets::Cache::FileStore.new(@root) @store = Sprockets::Cache.new(@_store) end def teardown FileUtils.rm_rf(@root) end def test_inspect Dir::mktmpdir "sprockets-file-store-inspect" do |dir| store = Sprockets::Cache::FileStore.new(dir) assert_equal "#", store.inspect end end def test_corrupted_read File.write(File.join(@root, "corrupt.cache"), "w") do |f| f.write("corrupt") end refute @_store.get("corrupt") end include CacheStoreTests end class TestZeroFileStore < MiniTest::Test def setup @tmpdir = Dir::mktmpdir "sprockets-file-store-zero" @_store = Sprockets::Cache::FileStore.new(@tmpdir, 0) @store = Sprockets::Cache.new(@_store) end def teardown FileUtils.rm_rf @tmpdir end def test_inspect Dir.mktmpdir "sprockets-file-store-inspect" do |dir| store = Sprockets::Cache::FileStore.new(dir, 0) assert_equal "#", store.inspect end end include CacheStoreNullTests end sprockets-3.7.2/test/test_caching.rb000066400000000000000000000363471331222022000174770ustar00rootroot00000000000000require 'sprockets_test' class TestCaching < Sprockets::TestCase def setup reset end def reset @cache = {} @env1 = Sprockets::Environment.new(fixture_path('default')) do |env| env.append_path(".") env.cache = @cache end @env2 = Sprockets::Environment.new(fixture_path('default')) do |env| env.append_path(".") env.cache = @cache end end test "same environment instance cache objects are equal" do env = @env1 asset1 = env['gallery.js'] asset2 = env['gallery.js'] assert asset1 assert asset2 assert asset1.eql?(asset2) assert asset2.eql?(asset1) end test "same cached instance cache objects are equal" do cached = @env1.cached asset1 = cached['gallery.js'] asset2 = cached['gallery.js'] assert asset1 assert asset2 assert asset1.eql?(asset2) assert asset2.eql?(asset1) end test "same environment instance is cached at logical and expanded path" do env = @env1 asset1 = env['gallery.js'] asset2 = env[asset1.filename] assert asset1 assert asset2 assert asset1.eql?(asset2) assert asset2.eql?(asset1) end test "same cached instance is cached at logical and expanded path" do cached = @env1.cached asset1 = cached['gallery.js'] asset2 = cached[asset1.filename] assert asset1 assert asset2 assert asset1.eql?(asset2) assert asset2.eql?(asset1) end test "shared cache objects are eql" do asset1 = @env1['gallery.js'] asset2 = @env2['gallery.js'] assert asset1 assert asset2 assert asset1.eql?(asset2) assert asset2.eql?(asset1) assert !asset1.equal?(asset2) end test "keys are different if environment digest changes" do @env1['gallery.js'] old_keys = @cache.keys.sort @cache.clear @env2.version = '2.0' @env2['gallery.js'] new_keys = @cache.keys.sort refute_equal old_keys, new_keys end class MockProcessor attr_reader :cache_key def initialize(cache_key) @cache_key = cache_key end def call(input) end end test "asset ids are different if preprocessor is added" do assert asset1 = @env1['gallery.js'] @env2.register_preprocessor 'application/javascript', MockProcessor.new('1.0') assert asset2 = @env2['gallery.js'] refute_equal asset1.id, asset2.id end test "asset ids are different if postprocessor is added" do assert asset1 = @env1['gallery.js'] @env2.register_postprocessor 'application/javascript', MockProcessor.new('1.0') assert asset2 = @env2['gallery.js'] refute_equal asset1.id, asset2.id end test "asset ids are different if bundle processor is added" do assert asset1 = @env1['gallery.js'] @env2.register_bundle_processor 'application/javascript', MockProcessor.new('1.0') assert asset2 = @env2['gallery.js'] refute_equal asset1.id, asset2.id end test "asset ids are different if processor cache key changes" do @env1.register_preprocessor 'application/javascript', MockProcessor.new('1.0') assert asset1 = @env1['gallery.js'] @env2.register_preprocessor 'application/javascript', MockProcessor.new('2.0') assert asset2 = @env2['gallery.js'] refute_equal asset1.id, asset2.id end test "unknown cache keys are ignored" do @env1.register_dependency_resolver 'foo-version' do |env| 1 end @env1.depend_on 'foo-version' assert asset1 = @env1['gallery.js'] assert asset1.metadata[:dependencies].include?('foo-version') assert asset2 = @env2['gallery.js'] refute asset2.metadata[:dependencies].include?('foo-version') refute_equal asset1.id, asset2.id end test "assets from different load paths are not equal" do # Normalize test fixture mtimes mtime = File.stat(fixture_path("default/app/main.js")).mtime.to_i File.utime(mtime, mtime, fixture_path("default/vendor/gems/jquery-2-0/jquery.js")) File.utime(mtime, mtime, fixture_path("default/vendor/gems/jquery-1-9/jquery.js")) env1 = Sprockets::Environment.new(fixture_path('default')) do |env| env.append_path("app") env.append_path("vendor/gems/jquery-1-9") env.cache = @cache end env2 = Sprockets::Environment.new(fixture_path('default')) do |env| env.append_path("app") env.append_path("vendor/gems/jquery-2-0") env.cache = @cache end refute_equal env1.find_asset("main.js"), env2.find_asset("main.js") end test "stale cached asset isn't loaded if file is remove" do filename = fixture_path("default/tmp.js") sandbox filename do File.open(filename, 'w') { |f| f.write "foo;\n" } assert_equal "foo;\n", @env1["tmp.js"].to_s File.unlink(filename) assert_nil @env2["tmp.js"] end end test "stale cached asset isn't loaded if dependency is changed and removed" do foo = fixture_path("default/foo-tmp.js") bar = fixture_path("default/bar-tmp.js") sandbox foo, bar do File.open(foo, 'w') { |f| f.write "//= require bar-tmp\nfoo;\n" } File.open(bar, 'w') { |f| f.write "bar;\n" } assert_equal "bar;\nfoo;\n", @env1["foo-tmp.js"].to_s assert_equal "bar;\n", @env1["bar-tmp.js"].to_s # File.open(foo, 'w') { |f| f.write "foo;\n" } File.unlink(bar) assert_nil @env2["bar-tmp.js"] assert_raises Sprockets::FileNotFound do @env1["foo-tmp.js"].to_s end end end test "stale cached asset isn't loaded if removed from path" do env1 = Sprockets::Environment.new(fixture_path('default')) do |env| env.append_path("app") env.append_path("vendor") env.cache = @cache end env2 = Sprockets::Environment.new(fixture_path('default')) do |env| env.append_path("app") env.cache = @cache end assert_equal "jQuery;\n", env1["main.js"].to_s assert_equal "jQuery;\n", env1["jquery.js"].to_s assert_raises Sprockets::FileNotFound do env2["main.js"].to_s end end test "add/remove file to shadow vendor" do @env = Sprockets::Environment.new(fixture_path('default')) do |env| env.append_path("app") env.append_path("vendor") env.cache = @cache end patched_jquery = fixture_path('default/app/jquery.js') sandbox patched_jquery do File.utime(1421000000, 1422000000, File.dirname(patched_jquery)) asset = @env["jquery.js"] assert_equal fixture_path('default/vendor/jquery.js'), asset.filename assert_equal "jQuery;\n", asset.to_s asset = @env["main.js"] assert_equal fixture_path('default/app/main.js'), asset.filename assert_equal "jQuery;\n", asset.to_s write(patched_jquery, "jQueryFixed;\n", 1422000010) asset = @env["main.js"] assert_equal fixture_path('default/app/main.js'), asset.filename assert_equal "jQueryFixed;\n", asset.to_s asset = @env["jquery.js"] assert_equal fixture_path('default/app/jquery.js'), asset.filename assert_equal "jQueryFixed;\n", asset.to_s File.unlink(patched_jquery) File.utime(1421000020, 1422000020, File.dirname(patched_jquery)) asset = @env["jquery.js"] assert_equal fixture_path('default/vendor/jquery.js'), asset.filename assert_equal "jQuery;\n", asset.to_s asset = @env["main.js"] assert_equal fixture_path('default/app/main.js'), asset.filename assert_equal "jQuery;\n", asset.to_s end end test "add/remove index file to shadow vendor" do @env = Sprockets::Environment.new(fixture_path('default')) do |env| env.append_path("app") env.append_path("vendor") env.cache = @cache end patched_jquery = fixture_path('default/app/jquery/index.js') sandbox File.dirname(patched_jquery), patched_jquery do File.utime(1423000000, 1423000000, File.dirname(File.dirname(patched_jquery))) asset = @env["jquery.js"] assert_equal fixture_path('default/vendor/jquery.js'), asset.filename assert_equal "jQuery;\n", asset.to_s asset = @env["main.js"] assert_equal fixture_path('default/app/main.js'), asset.filename assert_equal "jQuery;\n", asset.to_s FileUtils.mkdir(File.dirname(patched_jquery)) write(patched_jquery, "jQueryFixed;\n", 1423000010) asset = @env["main.js"] assert_equal fixture_path('default/app/main.js'), asset.filename assert_equal "jQueryFixed;\n", asset.to_s asset = @env["jquery.js"] assert_equal fixture_path('default/app/jquery/index.js'), asset.filename assert_equal "jQueryFixed;\n", asset.to_s File.unlink(patched_jquery) File.utime(1423000020, 1423000020, File.dirname(patched_jquery)) asset = @env["jquery.js"] assert_equal fixture_path('default/vendor/jquery.js'), asset.filename assert_equal "jQuery;\n", asset.to_s asset = @env["main.js"] assert_equal fixture_path('default/app/main.js'), asset.filename assert_equal "jQuery;\n", asset.to_s end end test "seperate cache for dependencies under a different load path" do env1 = Sprockets::Environment.new(fixture_path('default')) do |env| env.append_path("app") env.append_path("vendor/gems/jquery-1-9") env.cache = @cache end env2 = Sprockets::Environment.new(fixture_path('default')) do |env| env.append_path("app") env.append_path("vendor/gems/jquery-2-0") env.cache = @cache end assert main = env1.find_asset("main.js") assert_equal "var jQuery;\n", main.to_s assert_equal fixture_path('default/app/main.js'), main.filename assert_equal main, env1.load(main.uri) assert_equal main, env1.find_asset("main.js") assert main = env2.find_asset("main.js") assert_equal "var jQuery;\n", main.to_s assert_equal fixture_path('default/app/main.js'), main.filename assert_equal main, env2.load(main.uri) assert_equal main, env2.find_asset("main.js") end test "environment cache resolver evaluated on load" do env = @env1 assert asset1 = env['rand.js'] assert asset2 = env['rand.js'] refute_equal asset1.id, asset2.id end test "cached environment cache resolver evaluated onced" do env = @env1.cached assert asset1 = env['rand.js'] assert asset2 = env['rand.js'] assert_equal asset1.id, asset2.id end end require 'tmpdir' class TestFileStoreCaching < Sprockets::TestCase def setup @cache_dir = File.join(Dir::tmpdir, 'sprockets') @cache = Sprockets::Cache::FileStore.new(@cache_dir) end def teardown FileUtils.remove_entry(@cache_dir) end test "shared cache objects are eql" do @env1 = Sprockets::Environment.new(fixture_path('default')) do |env| env.append_path(".") env.cache = @cache end @env2 = Sprockets::Environment.new(fixture_path('default')) do |env| env.append_path(".") env.cache = @cache end asset1 = @env1['gallery.js'] asset2 = @env2['gallery.js'] assert asset1 assert asset2 assert asset1.eql?(asset2) assert asset2.eql?(asset1) assert !asset1.equal?(asset2) end test "no absolute paths are retuned from cache using sass" do env1 = Sprockets::Environment.new(fixture_path('sass')) do |env| env.append_path(".") env.cache = @cache end asset1 = silence_warnings do env1['variables.scss'] end Dir.mktmpdir do |dir| env2 = Sprockets::Environment.new(dir) do |env| env.append_path(dir) env.cache = @cache end FileUtils.cp_r(env1.root + "/.", env2.root) asset2 = silence_warnings do env2['variables.scss'] end assert asset1.metadata[:sass_dependencies] assert asset2.metadata[:sass_dependencies] assert_equal asset1.digest_path, asset2.digest_path assert_equal asset1.source, asset2.source assert_equal asset1.hexdigest, asset2.hexdigest # Absolute paths should be different refute_equal asset1.metadata[:sass_dependencies], asset2.metadata[:sass_dependencies] end end test "history cache is not polluted" do dependency_file = File.join(fixture_path('asset'), "dependencies", "a.js") env1 = Sprockets::Environment.new(fixture_path('asset')) do |env| env.append_path(".") env.cache = @cache end env1['required_assets.js'] sandbox dependency_file do write(dependency_file, "var aa = 2;") env1['required_assets.js'] # We must use private APIs to test this behavior # https://github.com/rails/sprockets/pull/141 cache_entries = @cache.send(:find_caches).map do |file, _| key = file.gsub(/\.cache\z/, ''.freeze).split(@cache_dir).last result = @cache.get(key) if result.is_a?(Array) result if result.first.is_a?(Set) else nil end end.compact assert cache_entries.any? cache_entries.each do |sets| sets.each do |set| refute set.any? {|uri| uri.include?(env1.root) }, "Expected entry in cache to not include absolute paths but did: #{set.inspect}" end end end end test "no absolute paths are retuned from cache" do env1 = Sprockets::Environment.new(fixture_path('default')) do |env| env.append_path(".") env.cache = @cache end asset1 = env1['schneems.js'] Dir.mktmpdir do |dir| env2 = Sprockets::Environment.new(dir) do |env| env.append_path(dir) env.cache = @cache end FileUtils.cp_r(env1.root + "/.", env2.root) asset2 = env2['schneems.js'] assert asset1 assert asset2 assert_equal asset1.digest_path, asset2.digest_path assert_equal asset1.source, asset2.source assert_equal asset1.hexdigest, asset2.hexdigest # Absolute paths should be different refute_equal asset1.uri, asset2.uri refute_equal asset1.filename, asset2.filename refute_equal asset1.included, asset2.included refute_equal asset1.to_hash[:load_path], asset2.to_hash[:load_path] refute_equal asset1.metadata[:dependencies], asset2.metadata[:dependencies] refute_equal asset1.metadata[:links], asset2.metadata[:links] # The metadata[:stubbed] and metadata[:required] cannot be # observed directly, they are included in the `dependencies`. # We must use private APIs to test this behavior # https://github.com/rails/sprockets/issues/96#issuecomment-133097865 cache_entries = @cache.send(:find_caches).map do |file, _| key = file.gsub(/\.cache\z/, ''.freeze).split(@cache_dir).last result = @cache.get(key) result.is_a?(Hash) ? result : nil end.compact required = cache_entries.map do |asset| asset[:metadata][:required] if asset[:metadata] end.compact required.each do |set| refute set.any? {|uri| uri.include?(env1.root) || uri.include?(env2.root)}, "Expected 'required' entry in cache to not include absolute paths but did: #{set.inspect}" end stubbed = cache_entries.map do |asset| asset[:metadata][:stubbed] if asset[:metadata] end.compact stubbed.each do |set| refute set.any? {|uri| uri.include?(env1.root) || uri.include?(env2.root)}, "Expected 'stubbed' entry in cache to not include absolute paths but did: #{set.inspect}" end end end end sprockets-3.7.2/test/test_closure_compressor.rb000066400000000000000000000010611331222022000220140ustar00rootroot00000000000000require 'minitest/autorun' require 'sprockets/cache' require 'sprockets/closure_compressor' class TestClosureCompressor < MiniTest::Test def test_compress_javascript input = { :data => "function foo() {\n return true;\n}", :cache => Sprockets::Cache.new } output = "function foo(){return!0};\n" begin assert_equal output, Sprockets::ClosureCompressor.call(input) rescue Closure::Error skip "No Java runtime present" end end def test_cache_key assert Sprockets::ClosureCompressor.cache_key end end sprockets-3.7.2/test/test_coffee_script_processor.rb000066400000000000000000000007641331222022000230070ustar00rootroot00000000000000require 'minitest/autorun' require 'sprockets/cache' require 'sprockets/coffee_script_processor' class TestCoffeeScriptProcessor < MiniTest::Test def test_compile_coffee_script_template_to_js input = { content_type: 'application/javascript', data: "square = (n) -> n * n", cache: Sprockets::Cache.new } assert Sprockets::CoffeeScriptProcessor.call(input).match(/var square/) end def test_cache_key assert Sprockets::CoffeeScriptProcessor.cache_key end end sprockets-3.7.2/test/test_context.rb000066400000000000000000000107041331222022000175540ustar00rootroot00000000000000require 'sprockets_test' require 'yaml' class TestContext < Sprockets::TestCase def setup @env = Sprockets::Environment.new(".") @env.append_path(fixture_path('context')) end test "context environment is cached" do instances = @env["environment.js"].to_s.split("\n") assert_match "Sprockets::CachedEnvironment", instances[0] assert_equal instances[0], instances[1] end test "source file properties are exposed in context" do json = @env["properties.js"].to_s.chomp.chop assert_equal({ 'filename' => fixture_path("context/properties.js.erb"), '__FILE__' => fixture_path("context/properties.js.erb"), 'root_path' => fixture_path("context"), 'logical_path' => "properties", 'content_type' => "application/javascript" }, YAML.load(json)) end test "source file properties are exposed in context when path contains periods" do json = @env["properties.with.periods.js"].to_s.chomp.chop assert_equal({ 'filename' => fixture_path("context/properties.with.periods.js.erb"), '__FILE__' => fixture_path("context/properties.with.periods.js.erb"), 'root_path' => fixture_path("context"), 'logical_path' => "properties.with.periods", 'content_type' => "application/javascript" }, YAML.load(json)) end test "extend context" do @env.context_class.class_eval do def datauri(path) require 'base64' Base64.encode64(File.open(path, "rb") { |f| f.read }) end end assert_equal ".pow {\n background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZoAAAEsCAMAAADNS4U5AAAAGXRFWHRTb2Z0\n", @env["helpers.css"].to_s.lines.to_a[0..1].join assert_equal 58240, @env["helpers.css"].length end test "resolve with content type" do assert_equal(<<-FILE, @env["resolve_content_type.js"].to_s) #{fixture_path_for_uri("context/foo.js")}; #{fixture_path_for_uri("context/foo.js")}; #{fixture_path_for_uri("context/foo.js")}; FILE end end class TestCustomProcessor < Sprockets::TestCase def setup @env = Sprockets::Environment.new @env.append_path(fixture_path('context')) end require 'yaml' class YamlProcessor def initialize(file, &block) @data = block.call end def render(context, locals = {}) manifest = YAML.load(@data) manifest['require'].each do |logical_path| context.require_asset(logical_path) end "" end end test "custom processor using Context#require" do @env.register_engine '.yml', YamlProcessor assert_equal "var Foo = {};\n\nvar Bar = {};\n", @env['application.js'].to_s end require 'base64' class DataUriProcessor def initialize(file, &block) @data = block.call end def self.call(input) context = input[:environment].context_class.new(input) result = self.new(nil, &Proc.new { input[:data]} ).render(context) { data: result } end def render(context, locals = {}) data = @data data.gsub(/url\(\"(.+?)\"\)/) do path = context.resolve($1, compat: true) context.depend_on(path) data = Base64.encode64(File.open(path, "rb") { |f| f.read }) "url(data:image/png;base64,#{data})" end end end test "custom processor using Context#resolve and Context#depend_on" do @env.register_mime_type 'text/css+embed', extensions: ['.css.embed'] @env.register_transformer 'text/css+embed', 'text/css', DataUriProcessor assert_equal ".pow {\n background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZoAAAEsCAMAAADNS4U5AAAAGXRFWHRTb2Z0\n", @env["sprite.css"].to_s.lines.to_a[0..1].join assert_equal 58240, @env["sprite.css"].length end test "block custom processor" do require 'base64' klass = Class.new do def self.call(input) data = input[:data] result = data.gsub(/url\(\"(.+?)\"\)/) do context = input[:environment].context_class.new(input) path = context.resolve($1, compat: true) context.depend_on(path) data = Base64.encode64(File.open(path, "rb") { |f| f.read }) "url(data:image/png;base64,#{data})" end { data: result } end end @env.register_preprocessor 'text/css', klass assert_equal ".pow {\n background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZoAAAEsCAMAAADNS4U5AAAAGXRFWHRTb2Z0\n", @env["sprite2.css"].to_s.lines.to_a[0..1].join assert_equal 58240, @env["sprite2.css"].length end end sprockets-3.7.2/test/test_digest_utils.rb000066400000000000000000000106271331222022000205730ustar00rootroot00000000000000require 'minitest/autorun' require 'sprockets/digest_utils' class TestDigestUtils < MiniTest::Test include Sprockets::DigestUtils def test_detect_digest_class md5 = Digest::MD5.new.digest sha1 = Digest::SHA1.new.digest sha256 = Digest::SHA256.new.digest sha512 = Digest::SHA512.new.digest refute detect_digest_class("0000") assert_equal Digest::MD5, detect_digest_class(md5) assert_equal Digest::SHA1, detect_digest_class(sha1) assert_equal Digest::SHA256, detect_digest_class(sha256) assert_equal Digest::SHA512, detect_digest_class(sha512) end def hexdigest(obj) pack_hexdigest(digest(obj)) end def test_digest assert_equal "9bda381dac87b1c16b04f996abb623f43f1cdb89ce8be7dda3f67319dc440bc5", hexdigest(nil) assert_equal "92de503a8b413365fc38050c7dd4bacf28b0f705e744dacebcaa89f2032dcd67", hexdigest(true) assert_equal "bdfd64a7c8febcc3b0b8fb05d60c8e2a4cb6b8c081fcba20db1c9778e9beaf89", hexdigest(false) assert_equal "291e87109f89e59ad717aebe4ffc9657c700e74da45db789ecd19d6b797baee2", hexdigest(42) assert_equal "d1312b90a6258e9bda7d10e5e1ab1468d92786eca72a65b5ab077169e36bcb1e", hexdigest(2 ** 128) assert_equal "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae", hexdigest("foo") assert_equal "dea6712e86478d2ee22a35a8c5ac9627e7cbc5ce2407a7da7c645fea2434fe9b", hexdigest(:foo) assert_equal "f0cf39d0be3efbb6f86ac2404100ff7e055c17ded946a06808d66f89ca03a811", hexdigest([]) assert_equal "ed98cc300019b22ca15e7cd5934028a79e7af4c75f7eeea810f43a3a4353a04d", hexdigest(["foo"]) assert_equal "54edcfe382f4abaa9ebe93efa9977b05b786c9058496609797989b7fdf8208d4", hexdigest({"foo" => "bar"}) assert_equal "62427aa539a0b78e90fd710dc0e15f2960771ba44214b5d41d4a93a8b2940a38", hexdigest({"foo" => "baz"}) assert_equal "b6054efd9929004bdd0a1c09eb2d12961325396da749143def3e9a4050aa703e", hexdigest([[:foo, 1]]) assert_equal "79a19ffe41ecebd5dc35e95363e0b4aa79b139a22bc650384df57eb09842f099", hexdigest([{:foo => 1}]) assert_equal "94ee40cca7c2c6d2a134033d2f5a31c488cad5d3dcc61a3dbb5e2a858635874b", hexdigest("foo".force_encoding('UTF-8').encoding) assert_raises(TypeError) do digest(Object.new) end end def test_pack_hexdigest digest = Digest::SHA256.new.update("alert(1)") assert_equal "6e11c72f7cf6bc383152dd16ddd5903aba6bb1c99d6b6639a4bb0b838185fa92", digest.hexdigest assert_equal "6e11c72f7cf6bc383152dd16ddd5903aba6bb1c99d6b6639a4bb0b838185fa92", pack_hexdigest(digest.digest) end def test_unpack_hexdigest digest = Digest::SHA256.new.update("alert(1)") assert_equal digest.digest, unpack_hexdigest(digest.hexdigest) end def test_pack_base64_digest digest = Digest::SHA256.new.update("alert(1)") assert_equal "bhHHL3z2vDgxUt0W3dWQOrprscmda2Y5pLsLg4GF+pI=", digest.base64digest assert_equal "bhHHL3z2vDgxUt0W3dWQOrprscmda2Y5pLsLg4GF+pI=", pack_base64digest(digest.digest) end def test_pack_urlsafe_base64_digest digest = Digest::SHA256.new.update("alert(1)") assert_equal "bhHHL3z2vDgxUt0W3dWQOrprscmda2Y5pLsLg4GF-pI", pack_urlsafe_base64digest(digest.digest) end def test_integrity_uri sha256 = Digest::SHA256.new.update("alert(1)") sha512 = Digest::SHA512.new.update("alert(1)") assert_equal "sha256-bhHHL3z2vDgxUt0W3dWQOrprscmda2Y5pLsLg4GF+pI=", integrity_uri(sha256) assert_equal "sha256-bhHHL3z2vDgxUt0W3dWQOrprscmda2Y5pLsLg4GF+pI=", integrity_uri(sha256.digest) assert_equal "sha512-+uuYUxxe7oWIShQrWEmMn/fixz/rxDP4qcAZddXLDM3nN8/tpk1ZC2jXQk6N+mXE65jwfzNVUJL/qjA3y9KbuQ==", integrity_uri(sha512) assert_equal "sha512-+uuYUxxe7oWIShQrWEmMn/fixz/rxDP4qcAZddXLDM3nN8/tpk1ZC2jXQk6N+mXE65jwfzNVUJL/qjA3y9KbuQ==", integrity_uri(sha512.digest) # echo -n "alert('Hello, world.');" | openssl dgst -sha256 -binary | openssl enc -base64 -A sha256 = Digest::SHA256.new.update("alert('Hello, world.');") assert_equal "sha256-qznLcsROx4GACP2dm0UCKCzCG+HiZ1guq6ZZDob/Tng=", integrity_uri(sha256) end def test_hexdigest_integrity_uri sha256 = Digest::SHA256.new.update("alert(1)").hexdigest sha512 = Digest::SHA512.new.update("alert(1)").hexdigest assert_equal "sha256-bhHHL3z2vDgxUt0W3dWQOrprscmda2Y5pLsLg4GF+pI=", hexdigest_integrity_uri(sha256) assert_equal "sha512-+uuYUxxe7oWIShQrWEmMn/fixz/rxDP4qcAZddXLDM3nN8/tpk1ZC2jXQk6N+mXE65jwfzNVUJL/qjA3y9KbuQ==", hexdigest_integrity_uri(sha512) end end sprockets-3.7.2/test/test_eco_processor.rb000066400000000000000000000007171331222022000207400ustar00rootroot00000000000000require 'minitest/autorun' require 'sprockets/cache' require 'sprockets/eco_processor' class TestEcoProcessor < MiniTest::Test def test_compile_eco_template_to_js input = { content_type: 'application/javascript', data: "Hello, <%= name %>

", cache: Sprockets::Cache.new } assert Sprockets::EcoProcessor.call(input).match(/Hello, /) end def test_cache_key assert Sprockets::EcoProcessor.cache_key end end sprockets-3.7.2/test/test_ejs_processor.rb000066400000000000000000000007171331222022000207530ustar00rootroot00000000000000require 'minitest/autorun' require 'sprockets/cache' require 'sprockets/ejs_processor' class TestEjsProcessor < MiniTest::Test def test_compile_ejs_template_to_js input = { content_type: 'application/javascript', data: "Hello, <%= name %>

", cache: Sprockets::Cache.new } assert Sprockets::EjsProcessor.call(input).match(/Hello, /) end def test_cache_key assert Sprockets::EjsProcessor.cache_key end end sprockets-3.7.2/test/test_encoding.rb000066400000000000000000000045071331222022000176620ustar00rootroot00000000000000# encoding: utf-8 require "sprockets_test" class AssetEncodingTest < Sprockets::TestCase def setup @env = Sprockets::Environment.new @env.append_path(fixture_path('encoding')) end test "read ASCII asset" do data = @env['ascii.js'].to_s assert_equal "var foo = \"bar\";\n", data assert_equal Encoding::UTF_8, data.encoding end test "read UTF-8 asset" do data = @env['utf8.js'].to_s assert_equal "var snowman = \"☃\";\n", data assert_equal Encoding::UTF_8, data.encoding end test "read UTF-8 asset with BOM" do data = @env['utf8_bom.js'].to_s assert_equal "var snowman = \"☃\";\n", data assert_equal Encoding::UTF_8, data.encoding end test "read UTF-16 asset" do data = @env['utf16le.js'].to_s assert_equal "var snowman = \"☃\";\n", data assert_equal Encoding::UTF_8, data.encoding end test "read ASCII + UTF-8 concatation asset" do data = @env['ascii_utf8.js'].to_s assert_equal "var foo = \"bar\";\nvar snowman = \"\342\230\203\";\n\n\n", data assert_equal Encoding::UTF_8, data.encoding end test "read static BINARY asset" do data = @env['binary.png'].to_s assert_equal "\x89PNG\r\n\x1A\n\x00\x00\x00".force_encoding("BINARY"), data[0..10] assert_equal Encoding::BINARY, data.encoding end test "read processed BINARY asset" do klass = Class.new do def self.call(input) input[:data] end end @env.register_postprocessor('image/png', klass) data = @env['binary.png'].to_s assert_equal "\x89PNG\r\n\x1A\n\x00\x00\x00".force_encoding("BINARY"), data[0..10] assert_equal Encoding::BINARY, data.encoding end test "read css asset with charset" do expected = "\n\nh1 { color: red; }\n" assert_equal expected, @env['utf8-charset.css'].to_s assert_equal expected, @env['utf16le-charset.css'].to_s assert_equal expected, @env['utf16le-bom-charset.css'].to_s end test "read file with content type" do data = @env.read_file(fixture_path('encoding/ascii.js'), 'application/javascript') assert_equal "var foo = \"bar\";\n", data assert_equal Encoding::UTF_8, data.encoding data = @env.read_file(fixture_path('encoding/utf16le-charset.css'), 'text/css') assert_equal "\n\nh1 { color: red; }\n", data assert_equal Encoding::UTF_8, data.encoding end end sprockets-3.7.2/test/test_encoding_utils.rb000066400000000000000000000202431331222022000210750ustar00rootroot00000000000000# encoding: utf-8 require 'minitest/autorun' require 'sprockets/encoding_utils' class TestDigestUtils < MiniTest::Test include Sprockets::EncodingUtils def test_deflate output = deflate("foobar") assert_equal 8, output.length assert_equal [75, 203, 207, 79, 74, 44, 2, 0], output.bytes.take(8) end def test_gzip output = gzip("foobar") assert_equal 26, output.length assert_equal [31, 139, 8, 0, 1, 0, 0, 0], output.bytes.take(8) end def test_base64 assert_equal "Zm9vYmFy", base64("foobar") end def test_unmarshal str = Marshal.dump("abc") assert_equal Marshal.load(str), unmarshaled_deflated(str) end def test_unmarshal_older_minor_version old_verbose, $VERBOSE = $VERBOSE, false begin str = Marshal.dump("abc") str[1] = "\0" assert_equal Marshal.load(str), unmarshaled_deflated(str) ensure $VERBOSE = old_verbose end end def test_fail_to_unmarshal_older_major_version str = Marshal.dump("abc") str[0] = "\1" assert_raises TypeError do Marshal.load(str) end assert_raises TypeError do unmarshaled_deflated(str) end end def test_fail_to_unmarshal_not_enough_data assert_raises ArgumentError do Marshal.load("") end assert_raises ArgumentError do unmarshaled_deflated("") end end def test_unmarshal_deflated str = deflate(Marshal.dump("abc")) assert_equal "abc", unmarshaled_deflated(str) end def test_detect_unicode_bom path = File.expand_path("../fixtures/encoding/ascii.js", __FILE__) str = File.binread(path) assert_equal Encoding::BINARY, str.encoding assert_equal 17, str.bytesize str = detect_unicode_bom(str) assert_equal Encoding::BINARY, str.encoding assert_equal 17, str.bytesize path = File.expand_path("../fixtures/encoding/utf8.js", __FILE__) str = File.binread(path) assert_equal Encoding::BINARY, str.encoding assert_equal 20, str.bytesize str = detect_unicode_bom(str) assert_equal Encoding::BINARY, str.encoding assert_equal 20, str.bytesize path = File.expand_path("../fixtures/encoding/utf8_bom.js", __FILE__) str = File.binread(path) assert_equal Encoding::BINARY, str.encoding assert_equal 23, str.bytesize str = detect_unicode_bom(str) assert_equal Encoding::UTF_8, str.encoding assert_equal 20, str.bytesize path = File.expand_path("../fixtures/encoding/utf8_bom.js", __FILE__) str = File.binread(path) str.force_encoding(Encoding::UTF_8) assert_equal 23, str.bytesize str = detect_unicode_bom(str) assert_equal Encoding::UTF_8, str.encoding assert_equal 20, str.bytesize path = File.expand_path("../fixtures/encoding/utf16le.js", __FILE__) str = File.binread(path) assert_equal Encoding::BINARY, str.encoding assert_equal 38, str.bytesize str = detect_unicode_bom(str) assert_equal Encoding::UTF_16LE, str.encoding assert_equal 36, str.bytesize path = File.expand_path("../fixtures/encoding/utf16le.js", __FILE__) str = File.binread(path) str.force_encoding(Encoding::UTF_16LE) assert_equal 38, str.bytesize str = detect_unicode_bom(str) assert_equal Encoding::UTF_16LE, str.encoding assert_equal 36, str.bytesize path = File.expand_path("../fixtures/encoding/utf16be.js", __FILE__) str = File.binread(path) assert_equal Encoding::BINARY, str.encoding assert_equal 38, str.bytesize str = detect_unicode_bom(str) assert_equal Encoding::UTF_16BE, str.encoding assert_equal 36, str.bytesize path = File.expand_path("../fixtures/encoding/utf32le.js", __FILE__) str = File.binread(path) assert_equal Encoding::BINARY, str.encoding assert_equal 76, str.bytesize str = detect_unicode_bom(str) assert_equal Encoding::UTF_32LE, str.encoding assert_equal 72, str.bytesize path = File.expand_path("../fixtures/encoding/utf32be.js", __FILE__) str = File.binread(path) assert_equal Encoding::BINARY, str.encoding assert_equal 76, str.bytesize str = detect_unicode_bom(str) assert_equal Encoding::UTF_32BE, str.encoding assert_equal 72, str.bytesize end def test_detect_css_charset path = File.expand_path("../fixtures/encoding/utf8-charset.css", __FILE__) str = File.binread(path) assert_equal Encoding::BINARY, str.encoding assert_equal 38, str.bytesize str = detect_css(str) assert_equal Encoding::UTF_8, str.encoding assert_equal 21, str.bytesize assert_equal "\n\nh1 { color: red; }\n", str.encode(Encoding::UTF_8) path = File.expand_path("../fixtures/encoding/utf8-charset.css", __FILE__) str = File.binread(path) str.force_encoding(Encoding::UTF_8) assert_equal 38, str.bytesize str = detect_css(str) assert_equal Encoding::UTF_8, str.encoding assert_equal 21, str.bytesize assert_equal "\n\nh1 { color: red; }\n", str.encode(Encoding::UTF_8) path = File.expand_path("../fixtures/encoding/utf16le-charset.css", __FILE__) str = File.binread(path) assert_equal Encoding::BINARY, str.encoding assert_equal 82, str.bytesize str = detect_css(str) assert_equal Encoding::UTF_16LE, str.encoding assert_equal 42, str.bytesize assert_equal "\n\nh1 { color: red; }\n", str.encode(Encoding::UTF_8) path = File.expand_path("../fixtures/encoding/utf16le-charset.css", __FILE__) str = File.binread(path) str.force_encoding(Encoding::UTF_16LE) assert_equal 82, str.bytesize str = detect_css(str) assert_equal Encoding::UTF_16LE, str.encoding assert_equal 42, str.bytesize assert_equal "\n\nh1 { color: red; }\n", str.encode(Encoding::UTF_8) path = File.expand_path("../fixtures/encoding/utf16le-bom-charset.css", __FILE__) str = File.binread(path) assert_equal Encoding::BINARY, str.encoding assert_equal 84, str.bytesize str = detect_css(str) assert_equal Encoding::UTF_16LE, str.encoding assert_equal 42, str.bytesize assert_equal "\n\nh1 { color: red; }\n", str.encode(Encoding::UTF_8) end def test_detect_html_charset assert_equal Encoding.default_external, Encoding::UTF_8 path = File.expand_path("../fixtures/encoding/utf8-charset.html", __FILE__) str = File.binread(path) assert_equal Encoding::BINARY, str.encoding assert_equal 10, str.bytesize str = detect_html(str) assert_equal Encoding::UTF_8, str.encoding assert_equal 10, str.bytesize assert_equal "

", str.encode(Encoding::UTF_8) path = File.expand_path("../fixtures/encoding/utf8_bom.html", __FILE__) str = File.binread(path) str.force_encoding(Encoding::UTF_8) assert_equal 13, str.bytesize str = detect_html(str) assert_equal Encoding::UTF_8, str.encoding assert_equal 10, str.bytesize assert_equal "

", str.encode(Encoding::UTF_8) path = File.expand_path("../fixtures/encoding/utf16le.html", __FILE__) str = File.binread(path) assert_equal Encoding::BINARY, str.encoding assert_equal 18, str.bytesize str = detect_html(str) assert_equal Encoding::UTF_16LE, str.encoding assert_equal 16, str.bytesize assert_equal "

", str.encode(Encoding::UTF_8) path = File.expand_path("../fixtures/encoding/utf16be.html", __FILE__) str = File.binread(path) str.force_encoding(Encoding::UTF_16BE) assert_equal 18, str.bytesize str = detect_html(str) assert_equal Encoding::UTF_16BE, str.encoding assert_equal 16, str.bytesize assert_equal "

", str.encode(Encoding::UTF_8) path = File.expand_path("../fixtures/encoding/utf32be.html", __FILE__) str = File.binread(path) assert_equal Encoding::BINARY, str.encoding assert_equal 36, str.bytesize str = detect_html(str) assert_equal Encoding::UTF_32BE, str.encoding assert_equal 32, str.bytesize assert_equal "

", str.encode(Encoding::UTF_8) path = File.expand_path("../fixtures/encoding/utf32le.html", __FILE__) str = File.binread(path) assert_equal Encoding::BINARY, str.encoding assert_equal 36, str.bytesize str = detect_html(str) assert_equal Encoding::UTF_32LE, str.encoding assert_equal 32, str.bytesize assert_equal "

", str.encode(Encoding::UTF_8) end end sprockets-3.7.2/test/test_engines.rb000066400000000000000000000017031331222022000175170ustar00rootroot00000000000000require 'sprockets_test' require 'sprockets/engines' class AlertProcessor def self.default_mime_type 'application/javascript' end def initialize(file, &block) @data = block.call end def render(context, locals = {}) "alert(#{@data.inspect});" end end class StringProcessor def initialize(file, &block) @data = block.call end def render(context, locals = {}) @data.gsub(/#\{.*?\}/, "moo") end end class TestEngines < Sprockets::TestCase test "registering engine" do env = new_environment Sprockets::SilenceDeprecation.silence do env.register_engine ".alert", AlertProcessor, silence_deprecation: true end asset = env["hello.alert"] assert_equal "alert(\"Hello world!\\n\");\n", asset.to_s assert_equal 'application/javascript', asset.content_type end def new_environment Sprockets::Environment.new.tap do |env| env.append_path(fixture_path('engines')) end end end sprockets-3.7.2/test/test_environment.rb000066400000000000000000000720131331222022000204350ustar00rootroot00000000000000require 'sprockets_test' require 'rack/mock' require 'execjs' module EnvironmentTests def self.test(name, &block) define_method("test_#{name.inspect}", &block) end test "working directory is the default root" do assert_equal Dir.pwd, @env.root end test "default logger level is set to fatal" do assert_equal Logger::FATAL, @env.logger.level end test "active css compressor" do assert_nil @env.css_compressor end test "active js compressor" do assert_nil @env.js_compressor end test "paths" do assert_equal [fixture_path("default")], @env.paths.to_a end test "register global path" do assert_equal [fixture_path("default")], new_environment.paths.to_a Sprockets.append_path(fixture_path("asset")) assert_equal [fixture_path("asset"), fixture_path("default")], new_environment.paths.to_a Sprockets.clear_paths end test "eco templates" do asset = @env["goodbye.js"] context = ExecJS.compile(asset.to_s) assert_equal "Goodbye world\n", context.call("JST['goodbye']", :name => "world") end test "ejs templates" do assert asset = @env["hello.js"] context = ExecJS.compile(asset.to_s) assert_equal "hello: world\n", context.call("JST['hello']", :name => "world") end test "another ejs templates" do assert asset = @env["hello2.js"] context = ExecJS.compile(asset.to_s) assert_equal "hello2: world\n", context.call("JST2['hello2']", :name => "world") end test "angular templates" do assert asset = @env["ng-view.js"] assert_equal <<-JS, asset.to_s $app.run(function($templateCache) { $templateCache.put('ng-view.html', "
"); }); JS end test "asset_data_uri helper" do assert asset = @env["with_data_uri.css"] assert_equal "body {\n background-image: url(data:image/gif;base64,R0lGODlhAQABAIAAAP%2F%2F%2FwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw%3D%3D) no-repeat;\n}\n", asset.to_s end test "lookup bundle processors" do assert_equal 1, @env.bundle_processors['application/javascript'].size assert_equal 1, @env.bundle_processors['text/css'].size end test "find asset with accept type" do assert asset = @env.find_asset("gallery.js", accept: '*/*') assert_equal fixture_path('default/gallery.js'), asset.filename assert asset = @env.find_asset("gallery", accept: 'application/javascript') assert_equal fixture_path('default/gallery.js'), asset.filename assert asset = @env.find_asset("gallery", accept: 'application/javascript, text/css') assert_equal fixture_path('default/gallery.js'), asset.filename assert asset = @env.find_asset("gallery.js", accept: 'application/javascript') assert_equal fixture_path('default/gallery.js'), asset.filename assert asset = @env.find_asset("gallery", accept: 'text/css, application/javascript') assert_equal fixture_path('default/gallery.css.erb'), asset.filename assert asset = @env.find_asset("coffee/foo", accept: "application/javascript") assert_equal fixture_path('default/coffee/foo.coffee'), asset.filename assert asset = @env.find_asset("coffee/foo.coffee", accept: "application/javascript") assert_equal fixture_path('default/coffee/foo.coffee'), asset.filename assert asset = @env.find_asset("jquery.tmpl.min", accept: 'application/javascript') assert_equal fixture_path('default/jquery.tmpl.min.js'), asset.filename assert asset = @env.find_asset("jquery.tmpl.min.js", accept: 'application/javascript') assert_equal fixture_path('default/jquery.tmpl.min.js'), asset.filename assert asset = @env.find_asset('manifest.js.yml', accept: 'text/yaml') assert_equal fixture_path('default/manifest.js.yml'), asset.filename assert asset = @env.find_asset('manifest.js.yml', accept: 'text/css, */*') assert_equal fixture_path('default/manifest.js.yml'), asset.filename refute @env.find_asset("gallery.js", accept: "text/css") refute @env.find_asset(fixture_path('default/gallery.js'), accept: "text/css") refute @env.find_asset('manifest.js.yml', accept: 'application/javascript') end test "find all linked assets" do assert assets = @env.find_all_linked_assets("missing.js").to_a assert_equal 0, assets.length assert assets = @env.find_all_linked_assets("gallery.js").to_a assert_equal 1, assets.length assert_equal @env["gallery.js"], assets[0] assert assets = @env.find_all_linked_assets("gallery-link.js").to_a assert_equal 2, assets.length assert_equal @env["gallery-link.js"], assets[0] assert_equal @env["gallery.js"], assets[1] assert assets = @env.find_all_linked_assets("explore-link.js").to_a assert_equal 3, assets.length assert_equal @env["explore-link.js"], assets[0] assert_equal @env["gallery-link.js"], assets[1] assert_equal @env["gallery.js"], assets[2] end test "html subresource links" do assert asset = @env["homepage-links.html"] assert_equal "text/html", asset.content_type assert asset.to_s.match(/gallery-[a-z0-9]+\.css/) assert asset.to_s.match(/gallery-[a-z0-9]+\.js/) assert asset.links.include?(@env["gallery.css"].uri) assert asset.links.include?(@env["gallery.js"].uri) end test "web component assets" do assert asset = @env["menu/menu.html"] assert_equal "text/html", asset.content_type assert_equal "\n", asset.to_s assert asset = @env["menu/menu.js"] assert_equal "application/javascript", asset.content_type assert_equal "$.fn.menu = {};\n", asset.to_s assert asset = @env["menu/menu.css"] assert_equal "text/css", asset.content_type assert_equal ".menu {}\n", asset.to_s end test "explicit bower.json access returns json file" do assert_equal fixture_path('default/bower/bower.json'), @env["bower/bower.json"].filename end test "find default bower main" do assert_equal fixture_path('default/bower/main.js'), @env["bower"].filename assert_equal fixture_path('default/qunit/qunit.js'), @env["qunit"].filename assert_equal fixture_path('default/rails/rails.coffee'), @env["rails"].filename end test "find bower main by format extension" do assert_equal fixture_path('default/bower/main.js'), @env["bower.js"].filename refute @env.find_asset("bower.css") assert_equal fixture_path('default/qunit/qunit.js'), @env["qunit.js"].filename assert_equal fixture_path('default/qunit/qunit.css'), @env["qunit.css"].filename assert_equal fixture_path('default/rails/rails.coffee'), @env["rails.js"].filename assert_equal fixture_path('default/requirejs/require.js'), @env.find_asset("requirejs.js").filename end test "find bower main by content type" do assert_equal fixture_path('default/bower/main.js'), @env.find_asset("bower", accept: 'application/javascript').filename assert_equal fixture_path('default/bower/main.js'), @env.find_asset("bower.js", accept: 'application/javascript').filename assert_equal fixture_path('default/qunit/qunit.js'), @env.find_asset("qunit", accept: 'application/javascript').filename assert_equal fixture_path('default/qunit/qunit.js'), @env.find_asset("qunit.js", accept: 'application/javascript').filename assert_equal fixture_path('default/qunit/qunit.css'), @env.find_asset("qunit", accept: 'text/css').filename assert_equal fixture_path('default/qunit/qunit.css'), @env.find_asset("qunit.css", accept: 'text/css').filename assert_equal fixture_path('default/rails/rails.coffee'), @env.find_asset("rails", accept: 'application/javascript').filename assert_equal fixture_path('default/rails/rails.coffee'), @env.find_asset("rails.js", accept: 'application/javascript').filename assert_equal fixture_path('default/requirejs/require.js'), @env.find_asset("requirejs.js", accept: 'application/javascript').filename end test "bower main with invalid files" do assert @env.find_asset("zeroclipboard/FILEFILE") assert @env.find_asset("zeroclipboard/mimetype.unknown") assert @env.find_asset("zeroclipboard/zc.js") assert @env.find_asset("zeroclipboard.js") refute @env.find_asset("zeroclipboard.unknown") end test "find bundled asset in environment" do assert_equal "var Gallery = {};\n", @env["gallery.js"].to_s end test "find bundled asset with absolute path environment" do assert_equal "var Gallery = {};\n", @env[fixture_path("default/gallery.js")].to_s end test "find bundled asset with implicit format" do assert_equal "(function() {\n var foo;\n\n foo = 'hello';\n\n}).call(this);\n", @env["coffee/foo.js"].to_s end test "find static asset in environment" do assert_equal "Hello world\n", @env["hello.txt"].to_s end test "find static asset with leading slash in environment" do assert_equal "Hello world\n", @env[fixture_path("default/hello.txt")].to_s end test "find index.js in directory" do assert_equal "var A;\nvar B;\n", @env["mobile.js"].to_s end test "find index.css in directory" do assert_equal ".c {}\n.d {}\n/*\n\n */\n\n", @env["mobile.css"].to_s end test "ignore index.min.js in directory" do refute @env["mobile-min.js"] end test "find bower.json in directory" do assert_equal "var bower;\n", @env["bower.js"].to_s end test "find multiple bower.json in directory" do assert_equal "var qunit;\n", @env["qunit.js"].to_s assert_equal ".qunit {}\n", @env["qunit.css"].to_s end test "find erb assets" do assert asset = @env.find_asset("erb/a") assert_equal "text/plain", asset.content_type assert asset = @env.find_asset("erb/b") assert_equal "text/plain", asset.content_type assert asset = @env.find_asset("erb/c") assert_equal "application/javascript", asset.content_type assert asset = @env.find_asset("erb/d") assert_equal "text/css", asset.content_type assert asset = @env.find_asset("erb/e") assert_equal "text/html", asset.content_type assert asset = @env.find_asset("erb/f") assert_equal "text/yaml", asset.content_type end test "find html builder asset" do assert asset = @env.find_asset("nokogiri-html.html") assert_equal "text/html", asset.content_type assert_equal <<-HTML, asset.to_s Hello world HTML end test "find xml builder asset" do assert asset = @env.find_asset("nokogiri-xml.xml") assert_equal "application/xml", asset.content_type assert_equal <<-XML, asset.to_s 10 Awesome widget XML end test "svg transformer for extension" do assert asset = @env.find_asset("logo.svg") assert_equal "image/svg+xml", asset.content_type assert_equal "logo.svg", asset.logical_path assert_equal [60, 115, 118, 103, 32, 119, 105, 100, 116, 104], asset.to_s[0, 10].bytes.to_a assert asset = @env.find_asset("logo.png") assert_equal "image/png", asset.content_type assert_equal "logo.png", asset.logical_path assert_equal [137, 80, 78, 71, 13, 10, 26, 10, 60, 115], asset.to_s[0, 10].bytes.to_a end test "svg transformer for accept" do assert asset = @env.find_asset("logo", accept: "image/svg+xml") assert_equal "image/svg+xml", asset.content_type assert_equal "logo.svg", asset.logical_path assert_equal [60, 115, 118, 103, 32, 119, 105, 100, 116, 104], asset.to_s[0, 10].bytes.to_a assert asset = @env.find_asset("logo", accept: "image/png") assert_equal "image/png", asset.content_type assert_equal "logo.png", asset.logical_path assert_equal [137, 80, 78, 71, 13, 10, 26, 10, 60, 115], asset.to_s[0, 10].bytes.to_a end test "full path svg transformer" do assert @env.find_asset(fixture_path("default/logo.svg")) refute @env.find_asset(fixture_path("default/logo.png")) end test "full path svg transformer for accept" do assert asset = @env.find_asset(fixture_path("default/logo.svg"), accept: "image/svg+xml") assert_equal "logo.svg", asset.logical_path assert_equal "image/svg+xml", asset.content_type assert_equal [60, 115, 118, 103, 32, 119, 105, 100, 116, 104], asset.to_s[0, 10].bytes.to_a assert asset = @env.find_asset(fixture_path("default/logo.svg"), accept: "image/png") assert_equal "image/png", asset.content_type assert_equal "logo.png", asset.logical_path assert_equal [137, 80, 78, 71, 13, 10, 26, 10, 60, 115], asset.to_s[0, 10].bytes.to_a end test "asset with + character" do assert asset = @env.find_asset("+plus.js") assert_equal "+plus.js", asset.logical_path assert_equal "application/javascript", asset.content_type end test "missing static path returns nil" do assert_nil @env[fixture_path("default/missing.png")] end test "find static directory returns nil" do assert_nil @env["images"] end test "missing asset returns nil" do assert_equal nil, @env["missing.js"] end test "missing asset path returns nil" do refute @env[fixture_path("default/missing.js")] end test "asset filename outside of load paths" do path = File.expand_path("../../bin/sprockets", __FILE__) assert File.exist?(path), "#{path} didn't exist" refute @env[path] end test "non-existent asset filename outside of load paths" do path = File.expand_path("../../bin/sprockets2", __FILE__) refute File.exist?(path), "#{path} exists" refute @env[path] end test "can't require files outside the load path" do path = fixture_path("default/../asset/project.css") assert File.exist?(path) refute @env[path] end test "asset with missing requires raises an exception" do assert_raises Sprockets::FileNotFound do @env["missing_require.js"] end end test "asset with missing depend_on raises an exception" do assert_raises Sprockets::FileNotFound do @env["missing_depend_on.js"] end end test "asset with missing absolute depend_on raises an exception" do assert_raises Sprockets::FileOutsidePaths do @env["missing_absolute_depend_on.js"] end end test "asset logical path for absolute path" do assert_equal "gallery.js", @env[fixture_path("default/gallery.js")].logical_path assert_equal "application.js", @env[fixture_path("default/application.js.coffee")].logical_path assert_equal "mobile/a.js", @env[fixture_path("default/mobile/a.js")].logical_path end test "mobile index logical path shorthand" do assert_equal "mobile/index.js", @env[fixture_path("default/mobile/index.js")].logical_path assert_equal "mobile-min/index.min.js", @env[fixture_path("default/mobile-min/index.min.js")].logical_path end FIXTURE_ROOT = Sprockets::TestCase::FIXTURE_ROOT FILES_IN_PATH = Dir["#{FIXTURE_ROOT}/default/**/*"].size - 10 test "iterate over each logical path" do paths = [] paths = @env.logical_paths.to_a.map(&:first) assert_equal FILES_IN_PATH, paths.length assert_equal paths.size, paths.uniq.size, "has duplicates" assert paths.include?("application.js") assert paths.include?("coffee/foo.js") assert paths.include?("coffee.js") assert !paths.include?("coffee") end test "iterate over each logical path and filename" do paths = [] filenames = [] @env.logical_paths.each do |logical_path, filename| paths << logical_path filenames << filename end assert_equal FILES_IN_PATH, paths.length assert_equal paths.size, paths.uniq.size, "has duplicates" assert paths.include?("application.js") assert paths.include?("coffee/foo.js") assert paths.include?("coffee.js") assert !paths.include?("coffee") assert filenames.any? { |p| p =~ /application.js.coffee/ } end test "CoffeeScript files are compiled in a closure" do script = @env["coffee"].to_s assert_equal "undefined", ExecJS.exec(script) end test "source pipeline skips all processoring" do assert asset = @env.find_asset("missing_require.js", pipeline: :source) assert_equal "// =require \"notfound\"\n", asset.source assert_equal "application/javascript", asset.content_type assert_equal "missing_require.source.js", asset.logical_path assert asset = @env.find_asset("missing_require.source.js") assert_equal "// =require \"notfound\"\n", asset.source assert_equal "application/javascript", asset.content_type assert_equal "missing_require.source.js", asset.logical_path end test "source pipeline on existing source asset" do assert asset = @env.find_asset("hello.txt", pipeline: :source) assert_equal "Hello world\n", asset.source assert_equal "text/plain", asset.content_type assert_equal "hello.source.txt", asset.logical_path assert asset = @env.find_asset("hello.source.txt") assert_equal "Hello world\n", asset.source assert_equal "text/plain", asset.content_type assert_equal "hello.source.txt", asset.logical_path end end class WhitespaceProcessor def self.call(input) input[:data].gsub(/\s+/, "") end end class WhitespaceCompressor def self.compress(source) source.gsub(/\s+/, "") end end class TestEnvironment < Sprockets::TestCase include EnvironmentTests def new_environment Sprockets::Environment.new(".") do |env| env.append_path(fixture_path('default')) env.cache = {} yield env if block_given? end end def setup @env = new_environment end test "changing logger" do @env.logger = Logger.new($stderr) end test "changing paths" do @env.clear_paths @env.append_path(fixture_path('asset')) end test "default gzip" do assert_equal true, @env.gzip? end test "register bundle processor" do old_size = @env.bundle_processors['text/css'].size @env.register_bundle_processor 'text/css', WhitespaceProcessor assert_equal old_size+1, @env.bundle_processors['text/css'].size end test "register compressor" do assert !@env.compressors['text/css'][:whitespace] @env.register_compressor 'text/css', :whitespace, WhitespaceCompressor assert @env.compressors['text/css'][:whitespace] end test "register global block preprocessor" do Sprockets::SilenceDeprecation.silence do old_size = new_environment.preprocessors['text/css'].size Sprockets.register_preprocessor('text/css', :foo) { |context, data| data } assert_equal old_size+1, new_environment.preprocessors['text/css'].size Sprockets.unregister_preprocessor('text/css', :foo) assert_equal old_size, new_environment.preprocessors['text/css'].size end end test "unregister custom block preprocessor" do Sprockets::SilenceDeprecation.silence do old_size = @env.preprocessors['text/css'].size @env.register_preprocessor('text/css', :foo) { |context, data| data } assert_equal old_size+1, @env.preprocessors['text/css'].size @env.unregister_preprocessor('text/css', :foo) assert_equal old_size, @env.preprocessors['text/css'].size end end test "unregister custom block postprocessor" do Sprockets::SilenceDeprecation.silence do old_size = @env.postprocessors['text/css'].size @env.register_postprocessor('text/css', :foo) { |context, data| data } assert_equal old_size+1, @env.postprocessors['text/css'].size @env.unregister_postprocessor('text/css', :foo) assert_equal old_size, @env.postprocessors['text/css'].size end end test "register global block postprocessor" do Sprockets::SilenceDeprecation.silence do old_size = new_environment.postprocessors['text/css'].size Sprockets.register_postprocessor('text/css', :foo) { |context, data| data } assert_equal old_size+1, new_environment.postprocessors['text/css'].size Sprockets.unregister_postprocessor('text/css', :foo) assert_equal old_size, new_environment.postprocessors['text/css'].size end end test "unregister custom block bundle processor" do Sprockets::SilenceDeprecation.silence do old_size = @env.bundle_processors['text/css'].size @env.register_bundle_processor('text/css', :foo) { |context, data| data } assert_equal old_size+1, @env.bundle_processors['text/css'].size @env.unregister_bundle_processor('text/css', :foo) assert_equal old_size, @env.bundle_processors['text/css'].size end end test "register global bundle processor" do old_size = Sprockets.bundle_processors['text/css'].size Sprockets.register_bundle_processor 'text/css', WhitespaceProcessor assert_equal old_size+1, Sprockets.bundle_processors['text/css'].size env = new_environment assert_equal old_size+1, env.bundle_processors['text/css'].size Sprockets.unregister_bundle_processor 'text/css', WhitespaceProcessor assert_equal old_size, Sprockets.bundle_processors['text/css'].size end test "setting css compressor to nil clears current compressor" do @env.css_compressor = WhitespaceCompressor assert @env.css_compressor @env.css_compressor = nil assert_nil @env.css_compressor end test "setting js compressor to nil clears current compressor" do @env.js_compressor = WhitespaceCompressor assert @env.js_compressor @env.js_compressor = nil assert_nil @env.js_compressor end test "setting js compressor to template handler" do assert_nil @env.js_compressor @env.js_compressor = Sprockets::UglifierCompressor assert_equal Sprockets::UglifierCompressor, @env.js_compressor @env.js_compressor = nil assert_nil @env.js_compressor end test "setting css compressor to template handler" do silence_warnings do require 'sprockets/sass_compressor' end assert_nil @env.css_compressor @env.css_compressor = Sprockets::SassCompressor assert_equal Sprockets::SassCompressor, @env.css_compressor @env.css_compressor = nil assert_nil @env.css_compressor end test "setting js compressor to sym" do assert_nil @env.js_compressor @env.js_compressor = :uglifier assert_equal 'Sprockets::UglifierCompressor', @env.js_compressor.name @env.js_compressor = nil assert_nil @env.js_compressor end test "setting css compressor to sym" do silence_warnings do require 'sprockets/sass_compressor' end assert_nil @env.css_compressor @env.css_compressor = :sass assert_equal 'Sprockets::SassCompressor', @env.css_compressor.name @env.css_compressor = nil assert_nil @env.css_compressor end test "pre/post processors on transformed asset" do @env.register_preprocessor 'image/svg+xml', proc { |input| { data: input[:data], test: Array(input[:metadata][:test]) + [:pre_svg] } } @env.register_postprocessor 'image/svg+xml', proc { |input| { data: input[:data], test: Array(input[:metadata][:test]) + [:post_svg] } } @env.register_preprocessor 'image/png', proc { |input| { data: input[:data], test: Array(input[:metadata][:test]) + [:pre_png] } } @env.register_postprocessor 'image/png', proc { |input| { data: input[:data], test: Array(input[:metadata][:test]) + [:post_png] } } @env.register_preprocessor 'image/gif', proc { |input| { data: input[:data], test: Array(input[:metadata][:test]) + [:pre_gif] } } @env.register_postprocessor 'image/gif', proc { |input| { data: input[:data], test: Array(input[:metadata][:test]) + [:post_gif] } } assert asset = @env.find_asset("logo.svg") assert_equal "image/svg+xml", asset.content_type assert_equal [:pre_svg, :post_svg], asset.metadata[:test] assert asset = @env.find_asset("logo.png") assert_equal "image/png", asset.content_type assert_equal [:pre_svg, :post_svg, :pre_png, :post_png], asset.metadata[:test] assert asset = @env.find_asset("logo.gif") assert_equal "image/gif", asset.content_type assert_equal [:pre_svg, :post_svg, :pre_png, :post_png, :pre_gif, :post_gif], asset.metadata[:test] end test "processor returning a non-string data" do @env.register_postprocessor 'application/javascript', proc { |input| { data: 42 } } assert_raises TypeError do @env.find_asset("application.js") end end test "processor returning a subclassed string data" do my_string = Class.new(String) @env.register_postprocessor 'application/javascript', proc { |input| { data: my_string.new("foo") } } assert_raises TypeError do @env.find_asset("application.js") end end test "processor returning a complex metadata type" do @env.register_postprocessor 'application/javascript', proc { |input| { data: "hello", foo: Object.new } } assert_raises TypeError do @env.find_asset("application.js") end end test "access selector count metadata" do assert asset = @env.find_asset("mobile.css") assert_equal 2, asset.metadata[:selector_count] end test "changing version doesn't affect the assets digest" do old_asset_digest = @env["gallery.js"].hexdigest @env.version = 'v2' assert old_asset_digest == @env["gallery.js"].hexdigest end test "bundled asset is stale if its mtime is updated or deleted" do filename = File.join(fixture_path("default"), "tmp.js") sandbox filename do assert_nil @env["tmp.js"] File.open(filename, 'w') { |f| f.write "foo;\n" } assert_equal "foo;\n", @env["tmp.js"].to_s File.open(filename, 'w') { |f| f.write "bar;\n" } time = Time.now + 60 File.utime(time, time, filename) assert_equal "bar;\n", @env["tmp.js"].to_s File.unlink(filename) assert_nil @env["tmp.js"] end end test "static asset is stale if its mtime is updated or deleted" do filename = File.join(fixture_path("default"), "tmp.png") sandbox filename do assert_nil @env["tmp.png"] File.open(filename, 'wb') { |f| f.write "\x01\x02\x03" } assert_equal "\x01\x02\x03", @env["tmp.png"].to_s File.open(filename, 'wb') { |f| f.write "\x04\x05\x06" } time = Time.now + 60 File.utime(time, time, filename) assert_equal "\x04\x05\x06", @env["tmp.png"].to_s File.unlink(filename) assert_nil @env["tmp.png"] end end test "bundled asset cached if theres an error building it" do @env.cache = nil filename = File.join(fixture_path("default"), "tmp.coffee") sandbox filename do File.open(filename, 'w') { |f| f.write "-->" } begin @env["tmp.js"].to_s rescue ExecJS::Error => e assert e else flunk "nothing raised" end File.open(filename, 'w') { |f| f.write "->" } time = Time.now + 60 File.utime(time, time, filename) assert_equal "(function() {\n (function() {});\n\n}).call(this);\n", @env["tmp.js"].to_s end end test "seperate contexts classes for each instance" do e1 = new_environment e2 = new_environment assert_raises(NameError) { e1.context_class.instance_method(:foo) } assert_raises(NameError) { e2.context_class.instance_method(:foo) } e1.context_class.class_eval do def foo; end end e1.context_class.instance_method(:foo) assert_raises(NameError) { e2.context_class.instance_method(:foo) } end test "disabling default directive preprocessor" do assert processor = @env.preprocessors['application/javascript'][0] assert_kind_of Sprockets::DirectiveProcessor, processor @env.unregister_preprocessor('application/javascript', processor) assert_equal "// =require \"notfound\"\n;\n", @env["missing_require.js"].to_s end end class TestCached < Sprockets::TestCase include EnvironmentTests def new_environment Sprockets::Environment.new(".") do |env| env.append_path(fixture_path('default')) env.cache = {} env.gzip = false yield env if block_given? end.cached end def setup @env = new_environment end test "inherit the gzip option" do assert_equal false, @env.gzip? end test "does not allow to change the gzip option" do assert_raises RuntimeError do @env.gzip = true end end test "does not allow new mime types to be added" do assert_raises RuntimeError do @env.register_mime_type "application/javascript", ".jst" end end test "does not allow new bundle processors to be added" do assert_raises RuntimeError do @env.register_bundle_processor 'text/css', WhitespaceProcessor end end test "does not allow bundle processors to be removed" do assert_raises RuntimeError do @env.unregister_bundle_processor 'text/css', WhitespaceProcessor end end test "change in environment bundle_processors does not affect cache" do env = Sprockets::Environment.new(".") cached = env.cached assert !cached.bundle_processors['text/css'].include?(WhitespaceProcessor) env.register_bundle_processor 'text/css', WhitespaceProcessor assert !cached.bundle_processors['text/css'].include?(WhitespaceProcessor) end test "does not allow css compressor to be changed" do assert_raises RuntimeError do @env.css_compressor = WhitespaceCompressor end end test "does not allow js compressor to be changed" do assert_raises RuntimeError do @env.js_compressor = WhitespaceCompressor end end end sprockets-3.7.2/test/test_erb_processor.rb000066400000000000000000000051031331222022000207340ustar00rootroot00000000000000require 'minitest/autorun' require 'sprockets' require 'sprockets/cache' require 'sprockets/erb_processor' class TestERBProcessor < MiniTest::Test def uri_path(path) path = '/' + path if path[1] == ':' # Windows path / drive letter path end def tset_compile_js_erb_template environment = Sprockets::Environment.new input = { environment: environment, filename: "foo.js.erb", content_type: 'application/javascript', data: "var data = <%= JSON.generate({foo: true}) %>;", metadata: {}, cache: Sprockets::Cache.new } output = "var data = {\"foo\":true};" assert_equal output, Sprockets::ERBProcessor.call(input)[:data] end def test_compile_erb_template_with_depend_on_call root = File.expand_path("../fixtures", __FILE__) environment = Sprockets::Environment.new(root) environment.append_path 'default' path = "#{root}/default/gallery.js" input = { environment: environment, filename: "foo.js.erb", content_type: 'application/javascript', data: "<%= depend_on('#{path}') %>\nvar data = 'DATA';", metadata: {}, cache: Sprockets::Cache.new } output = "var data = 'DATA';" result = Sprockets::ERBProcessor.call(input) assert_equal output, result[:data] assert_equal "file-digest://#{uri_path(path)}", result[:dependencies].first end def test_compile_erb_template_with_depend_on_call_outside_load_paths root = File.expand_path("../fixtures", __FILE__) environment = Sprockets::Environment.new(root) environment.append_path 'default' path = "#{root}/asset/application.js" assert File.exist?(path) input = { environment: environment, filename: "foo.js.erb", content_type: 'application/javascript', data: "<%= depend_on('#{path}') %>\nvar data = 'DATA';", metadata: {}, cache: Sprockets::Cache.new } output = "var data = 'DATA';" result = Sprockets::ERBProcessor.call(input) assert_equal output, result[:data] assert_equal "file-digest://#{uri_path(path)}", result[:dependencies].first end def test_pass_custom_erb_helpers_to_template environment = Sprockets::Environment.new template = Sprockets::ERBProcessor.new do def foo :bar end end input = { environment: environment, filename: "foo.js.erb", content_type: 'application/javascript', data: "var foo = <%= foo %>;", metadata: {}, cache: Sprockets::Cache.new } output = "var foo = bar;" assert_equal output, template.call(input)[:data] end end sprockets-3.7.2/test/test_http_utils.rb000066400000000000000000000106711331222022000202720ustar00rootroot00000000000000require 'minitest/autorun' require 'sprockets/http_utils' class TestHTTPUtils < MiniTest::Test include Sprockets::HTTPUtils def test_match_mime_type assert match_mime_type?("text/html", "text/*") assert match_mime_type?("text/plain", "*") refute match_mime_type?("text/html", "application/json") end def test_match_mime_type_keys h = { "text/html" => 1, "text/plain" => 2, "application/json" => 3, "text/*" => 4, "*/*" => 5, "*" => 6 } assert_equal [6, 5, 4, 1], match_mime_type_keys(h, "text/html") assert_equal [6, 5, 4, 2], match_mime_type_keys(h, "text/plain") assert_equal [6, 5, 3], match_mime_type_keys(h, "application/json") assert_equal [6, 5], match_mime_type_keys(h, "application/javascript") end def test_parse_q_values assert_equal [], parse_q_values(nil) assert_equal [["audio/*", 0.2], ["audio/basic", 1.0]], parse_q_values("audio/*; q=0.2, audio/basic") assert_equal [["text/plain", 0.5], ["text/html", 1.0], ["text/x-dvi", 0.8], ["text/x-c", 1.0]], parse_q_values("text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c") assert_equal [["text/*", 1.0], ["text/html", 1.0], ["text/html", 1.0], ["*/*", 1.0]], parse_q_values("text/*, text/html, text/html;level=1, */*") assert_equal [["text/*", 0.3], ["text/html", 0.7], ["text/html", 1.0], ["text/html", 1.0], ["*/*", 0.5]], parse_q_values("text/*;q=0.3, text/html;q=0.7, text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5") assert_equal [["iso-8859-5", 1.0], ["unicode-1-1", 0.8]], parse_q_values("iso-8859-5, unicode-1-1;q=0.8") assert_equal [["compress", 1.0], ["gzip", 1.0]], parse_q_values("compress, gzip") assert_equal [["*", 1.0]], parse_q_values("*") assert_equal [["compress", 0.5], ["gzip", 1.0]], parse_q_values("compress;q=0.5, gzip;q=1.0") assert_equal [["gzip", 1.0], ["identity", 0.5], ["*", 0.0]], parse_q_values("gzip;q=1.0, identity; q=0.5, *;q=0") end def test_find_q_matches accept = "text/plain; q=0.5, image/*" assert_equal ["text/plain"], find_mime_type_matches(accept, ["text/plain"]) assert_equal ["image/svg+xml"], find_mime_type_matches(accept, ["image/svg+xml"]) assert_equal ["image/svg+xml"], find_mime_type_matches(accept, ["image/svg+xml", "image/png"]) assert_equal ["image/svg+xml", "text/plain"], find_mime_type_matches(accept, ["image/svg+xml", "text/plain"]) assert_equal [], find_mime_type_matches(accept, ["text/css"]) end def test_find_matches_with_parsed_q_values accept = [["text/plain", 0.5], ["image/*", 1.0]] assert_equal ["text/plain"], find_mime_type_matches(accept, ["text/plain"]) assert_equal ["image/svg+xml"], find_mime_type_matches(accept, ["image/svg+xml"]) assert_equal ["image/svg+xml"], find_mime_type_matches(accept, ["image/svg+xml", "image/png"]) assert_equal ["image/svg+xml", "text/plain"], find_mime_type_matches(accept, ["image/svg+xml", "text/plain"]) assert_equal [], find_mime_type_matches(accept, ["text/css"]) end def test_find_best_q_match accept = "text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c" assert_equal "text/plain", find_best_mime_type_match(accept, ["text/plain"]) assert_equal "text/html", find_best_mime_type_match(accept, ["text/html"]) assert_equal "text/html", find_best_mime_type_match(accept, ["text/plain", "text/html"]) assert_equal "text/html", find_best_mime_type_match(accept, ["text/html", "text/plain"]) refute find_best_mime_type_match(accept, ["text/yaml"]) refute find_best_mime_type_match(accept, []) accept = "sdch, gzip, deflate" assert_equal "sdch", find_best_q_match(accept, ["sdch", "gzip"]) assert_equal "gzip", find_best_q_match(accept, ["gzip"]) assert_equal "deflate", find_best_q_match(accept, ["deflate"]) refute find_best_q_match(accept, ["base64"]) refute find_best_q_match(accept, []) refute find_best_q_match(nil, ["gzip"]) end def test_find_best_q_match_with_parsed_q_values assert accept = parse_q_values("text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c") assert_equal "text/plain", find_best_mime_type_match(accept, ["text/plain"]) assert_equal "text/html", find_best_mime_type_match(accept, ["text/html"]) assert_equal "text/html", find_best_mime_type_match(accept, ["text/plain", "text/html"]) assert_equal "text/html", find_best_mime_type_match(accept, ["text/html", "text/plain"]) end end sprockets-3.7.2/test/test_jst_processor.rb000066400000000000000000000021201331222022000207600ustar00rootroot00000000000000require 'minitest/autorun' require 'sprockets/cache' require 'sprockets/jst_processor' class TestJstProcessor < MiniTest::Test def test_export_js_template_in_JST input = { name: 'users/show', content_type: 'application/javascript', data: "function(obj) {\n return 'Hello, '+obj.name;\n}", cache: Sprockets::Cache.new } output = <<-EOS (function() { this.JST || (this.JST = {}); this.JST["users/show"] = function(obj) { return 'Hello, '+obj.name; }; }).call(this); EOS assert_equal output, Sprockets::JstProcessor.call(input) end def test_export_js_template_in_TEMPLATES input = { name: 'users/show', content_type: 'application/javascript', data: "function(obj) {\n return 'Hello, '+obj.name;\n}", cache: Sprockets::Cache.new } output = <<-EOS (function() { this.TEMPLATES || (this.TEMPLATES = {}); this.TEMPLATES["users/show"] = function(obj) { return 'Hello, '+obj.name; }; }).call(this); EOS assert_equal output, Sprockets::JstProcessor.new(namespace: 'this.TEMPLATES').call(input) end end sprockets-3.7.2/test/test_loader.rb000066400000000000000000000035471331222022000173450ustar00rootroot00000000000000require 'sprockets_test' class TestLoader < Sprockets::TestCase def setup @env = Sprockets::Environment.new(".") @env.append_path(fixture_path('default')) end test "load asset by uri" do assert asset = @env.load("file://#{fixture_path_for_uri('default/gallery.js')}?type=application/javascript") assert_equal fixture_path('default/gallery.js'), asset.filename assert_equal 'application/javascript', asset.content_type assert_equal '828e4be75f8bf69529b5d618dd12a6144d58d47cf4c3a9e3f64b0b8812008dab', asset.etag assert asset = @env.load(asset.uri) assert_equal fixture_path('default/gallery.js'), asset.filename assert_equal 'application/javascript', asset.content_type assert_equal '828e4be75f8bf69529b5d618dd12a6144d58d47cf4c3a9e3f64b0b8812008dab', asset.etag assert asset = @env.load("file://#{fixture_path_for_uri('default/gallery.css.erb')}?type=text/css") assert_equal fixture_path('default/gallery.css.erb'), asset.filename assert_equal 'text/css', asset.content_type assert asset = @env.load(Pathname.new("file://#{fixture_path_for_uri('default/gallery.css.erb')}?type=text/css")) assert_equal fixture_path('default/gallery.css.erb'), asset.filename assert_equal 'text/css', asset.content_type bad_id = "0000000000000000000000000000000000000000" assert asset = @env.load("file://#{fixture_path_for_uri('default/gallery.js')}?type=application/javascript&id=#{bad_id}") assert_equal fixture_path('default/gallery.js'), asset.filename assert_equal 'application/javascript', asset.content_type assert_raises Sprockets::FileNotFound do @env.load("file://#{fixture_path_for_uri('default/missing.js')}?type=application/javascript") end assert_raises Sprockets::ConversionError do @env.load("file://#{fixture_path_for_uri('default/gallery.js')}?type=text/css") end end end sprockets-3.7.2/test/test_manifest.rb000066400000000000000000000603241331222022000177010ustar00rootroot00000000000000require 'sprockets_test' require 'fileutils' require 'tmpdir' require 'securerandom' class TestManifest < Sprockets::TestCase def setup @env = Sprockets::Environment.new(".") do |env| env.append_path(fixture_path('default')) end @dir = File.join(Dir::tmpdir, 'sprockets/manifest') FileUtils.mkdir_p(@dir) end def teardown # FileUtils.rm_rf(@dir) # wtf, dunno system "rm -rf #{@dir}" assert Dir["#{@dir}/*"].empty? end test "specify full manifest filename" do directory = Dir::tmpdir filename = File.join(directory, 'manifest.json') manifest = Sprockets::Manifest.new(@env, filename) assert_equal directory, manifest.directory assert_equal filename, manifest.filename assert_equal filename, manifest.path end test "specify manifest directory yields random .sprockets-manifest-*.json" do manifest = Sprockets::Manifest.new(@env, @dir) assert_equal @dir, manifest.directory assert_match(/^\.sprockets-manifest-[a-f0-9]{32}.json/, File.basename(manifest.filename)) manifest.save assert_match(/^\.sprockets-manifest-[a-f0-9]{32}.json/, File.basename(manifest.filename)) end test "specify manifest directory with existing legacy manifest-abc213.json" do path = File.join(@dir, "manifest-#{SecureRandom.hex(16)}.json") File.open(path, 'w') { |f| f.write "{}" } manifest = Sprockets::Manifest.new(@env, @dir) assert_equal @dir, manifest.directory assert_match(/^manifest-[a-f0-9]{32}.json/, File.basename(manifest.filename)) manifest.save assert_match(/^\.sprockets-manifest-[a-f0-9]{32}.json/, File.basename(manifest.filename)) end test "specify manifest directory with existing legacy manifest.json" do path = File.join(@dir, "manifest.json") File.open(path, 'w') { |f| f.write "{}" } manifest = Sprockets::Manifest.new(@env, @dir) assert_equal @dir, manifest.directory assert_equal "manifest.json", File.basename(manifest.filename) manifest.save assert_match(/^\.sprockets-manifest-[a-f0-9]{32}.json/, File.basename(manifest.filename)) end test "specify manifest directory with existing .sprockets-manifest-*.json" do path = File.join(@dir, ".sprockets-manifest-#{SecureRandom.hex(16)}.json") File.open(path, 'w') { |f| f.write "{}" } assert File.exist?(path) manifest = Sprockets::Manifest.new(@env, @dir) assert_equal @dir, manifest.directory assert_equal path, manifest.filename end test "specify manifest directory and seperate location" do root = File.join(Dir::tmpdir, 'public') dir = File.join(root, 'assets') path = File.join(root, 'manifest-123.json') system "rm -rf #{root}" assert !File.exist?(root) manifest = Sprockets::Manifest.new(@env, dir, path) assert_equal dir, manifest.directory assert_equal path, manifest.filename end test "compile asset" do manifest = Sprockets::Manifest.new(@env, File.join(@dir, 'manifest.json')) digest_path = @env['application.js'].digest_path assert !File.exist?("#{@dir}/#{digest_path}") manifest.compile('application.js') assert File.directory?(manifest.directory) assert File.file?(manifest.filename) assert File.exist?("#{@dir}/manifest.json") assert File.exist?("#{@dir}/#{digest_path}") data = JSON.parse(File.read(manifest.filename)) assert data['files'][digest_path] assert_equal "application.js", data['files'][digest_path]['logical_path'] assert data['files'][digest_path]['size'] > 230 assert_equal digest_path, data['assets']['application.js'] end test "compile to directory and seperate location" do manifest = Sprockets::Manifest.new(@env, File.join(@dir, 'manifest.json')) root = File.join(Dir::tmpdir, 'public') dir = File.join(root, 'assets') path = File.join(root, 'manifests', 'manifest-123.json') system "rm -rf #{root}" assert !File.exist?(root) manifest = Sprockets::Manifest.new(@env, dir, path) manifest.compile('application.js') assert File.directory?(manifest.directory) assert File.file?(manifest.filename) end test "compile with legacy manifest" do root = File.join(Dir::tmpdir, 'public') dir = File.join(root, 'assets') path = File.join(root, "manifest-#{SecureRandom.hex(16)}.json") system "rm -rf #{root}" assert !File.exist?(root) system "rm -rf #{dir}/.sprockets-manifest*.json" system "rm -rf #{dir}/manifest*.json" FileUtils.mkdir_p(dir) File.open(path, 'w') { |f| f.write "{}" } manifest = Sprockets::Manifest.new(@env, dir) manifest.compile('application.js') assert File.directory?(manifest.directory) assert File.file?(manifest.filename) assert_match %r{.sprockets-manifest-[a-f0-9]{32}.json}, manifest.filename end test "compile asset with absolute path" do manifest = Sprockets::Manifest.new(@env, File.join(@dir, 'manifest.json')) digest_path = @env['application.js'].digest_path assert !File.exist?("#{@dir}/#{digest_path}") manifest.compile(fixture_path('default/application.js.coffee')) assert File.exist?("#{@dir}/manifest.json") assert File.exist?("#{@dir}/#{digest_path}") data = JSON.parse(File.read(manifest.filename)) assert data['files'][digest_path] assert_equal digest_path, data['assets']['application.js'] end test "compile multiple assets" do manifest = Sprockets::Manifest.new(@env, File.join(@dir, 'manifest.json')) app_digest_path = @env['application.js'].digest_path gallery_digest_path = @env['gallery.css'].digest_path assert !File.exist?("#{@dir}/#{app_digest_path}") assert !File.exist?("#{@dir}/#{gallery_digest_path}") manifest.compile('application.js', 'gallery.css') assert File.exist?("#{@dir}/manifest.json") assert File.exist?("#{@dir}/#{app_digest_path}") assert File.exist?("#{@dir}/#{gallery_digest_path}") data = JSON.parse(File.read(manifest.filename)) assert data['files'][app_digest_path] assert data['files'][gallery_digest_path] assert_equal app_digest_path, data['assets']['application.js'] assert_equal gallery_digest_path, data['assets']['gallery.css'] end test "compile with transformed asset" do manifest = Sprockets::Manifest.new(@env, File.join(@dir, 'manifest.json')) assert svg_digest_path = @env['logo.svg'].digest_path assert png_digest_path = @env['logo.png'].digest_path assert !File.exist?("#{@dir}/#{svg_digest_path}") assert !File.exist?("#{@dir}/#{png_digest_path}") manifest.compile('logo.svg', 'logo.png') assert File.exist?("#{@dir}/manifest.json") assert File.exist?("#{@dir}/#{svg_digest_path}") assert File.exist?("#{@dir}/#{png_digest_path}") data = JSON.parse(File.read(manifest.filename)) assert data['files'][svg_digest_path] assert data['files'][png_digest_path] assert_equal svg_digest_path, data['assets']['logo.svg'] assert_equal png_digest_path, data['assets']['logo.png'] end test "compile asset with links" do manifest = Sprockets::Manifest.new(@env, File.join(@dir, 'manifest.json')) main_digest_path = @env['gallery-link.js'].digest_path dep_digest_path = @env['gallery.js'].digest_path assert !File.exist?("#{@dir}/#{main_digest_path}") assert !File.exist?("#{@dir}/#{dep_digest_path}") manifest.compile('gallery-link.js') assert File.directory?(manifest.directory) assert File.file?(manifest.filename) assert File.exist?("#{@dir}/manifest.json") assert File.exist?("#{@dir}/#{main_digest_path}") assert File.exist?("#{@dir}/#{dep_digest_path}") data = JSON.parse(File.read(manifest.filename)) assert data['files'][main_digest_path] assert data['files'][dep_digest_path] assert_equal "gallery-link.js", data['files'][main_digest_path]['logical_path'] assert_equal "gallery.js", data['files'][dep_digest_path]['logical_path'] assert_equal main_digest_path, data['assets']['gallery-link.js'] assert_equal dep_digest_path, data['assets']['gallery.js'] end test "compile nested asset with links" do manifest = Sprockets::Manifest.new(@env, File.join(@dir, 'manifest.json')) main_digest_path = @env['explore-link.js'].digest_path dep_digest_path = @env['gallery-link.js'].digest_path subdep_digest_path = @env['gallery.js'].digest_path assert !File.exist?("#{@dir}/#{main_digest_path}") assert !File.exist?("#{@dir}/#{dep_digest_path}") assert !File.exist?("#{@dir}/#{subdep_digest_path}") manifest.compile('explore-link.js') assert File.directory?(manifest.directory) assert File.file?(manifest.filename) assert File.exist?("#{@dir}/manifest.json") assert File.exist?("#{@dir}/#{main_digest_path}") assert File.exist?("#{@dir}/#{dep_digest_path}") assert File.exist?("#{@dir}/#{subdep_digest_path}") data = JSON.parse(File.read(manifest.filename)) assert data['files'][main_digest_path] assert data['files'][dep_digest_path] assert data['files'][subdep_digest_path] assert_equal "explore-link.js", data['files'][main_digest_path]['logical_path'] assert_equal "gallery-link.js", data['files'][dep_digest_path]['logical_path'] assert_equal "gallery.js", data['files'][subdep_digest_path]['logical_path'] assert_equal main_digest_path, data['assets']['explore-link.js'] assert_equal dep_digest_path, data['assets']['gallery-link.js'] assert_equal subdep_digest_path, data['assets']['gallery.js'] end test "compile index asset" do manifest = Sprockets::Manifest.new(@env, File.join(@dir, 'manifest.json')) digest_path = @env['coffee.js'].digest_path assert_match(/coffee\/index-\w+.js/, digest_path) assert !File.exist?("#{@dir}/#{digest_path}") manifest.compile('coffee.js') assert File.exist?("#{@dir}/#{digest_path}") data = JSON.parse(File.read(manifest.filename)) assert data['files'][digest_path] assert_equal "coffee/index.js", data['files'][digest_path]['logical_path'] assert_equal digest_path, data['assets']['coffee/index.js'] assert_equal digest_path, data['assets']['coffee.js'] end test "compile with regex" do manifest = Sprockets::Manifest.new(@env, File.join(@dir, 'manifest.json')) app_digest_path = @env['application.js'].digest_path gallery_digest_path = @env['gallery.css'].digest_path assert !File.exist?("#{@dir}/#{app_digest_path}") assert !File.exist?("#{@dir}/#{gallery_digest_path}") manifest.compile('gallery.css', /application.js/) assert File.exist?("#{@dir}/manifest.json") assert File.exist?("#{@dir}/#{app_digest_path}") assert File.exist?("#{@dir}/#{gallery_digest_path}") data = JSON.parse(File.read(manifest.filename)) assert data['files'][app_digest_path] assert data['files'][gallery_digest_path] assert_equal app_digest_path, data['assets']['application.js'] assert_equal gallery_digest_path, data['assets']['gallery.css'] end test "recompile asset" do manifest = Sprockets::Manifest.new(@env, File.join(@dir, 'manifest.json')) digest_path = @env['application.js'].digest_path filename = fixture_path('default/application.js.coffee') sandbox filename do assert !File.exist?("#{@dir}/#{digest_path}"), Dir["#{@dir}/*"].inspect manifest.compile('application.js') assert File.exist?("#{@dir}/manifest.json") assert File.exist?("#{@dir}/#{digest_path}") data = JSON.parse(File.read(manifest.filename)) assert data['files'][digest_path] assert_equal digest_path, data['assets']['application.js'] File.open(filename, 'w') { |f| f.write "change;" } mtime = Time.now + 1 File.utime(mtime, mtime, filename) new_digest_path = @env['application.js'].digest_path manifest.compile('application.js') assert File.exist?("#{@dir}/manifest.json") assert File.exist?("#{@dir}/#{digest_path}") assert File.exist?("#{@dir}/#{new_digest_path}") data = JSON.parse(File.read(manifest.filename)) assert data['files'][digest_path] assert data['files'][new_digest_path] assert_equal new_digest_path, data['assets']['application.js'] end end test "remove asset" do manifest = Sprockets::Manifest.new(@env, @dir) digest_path = @env['application.js'].digest_path manifest.compile('application.js') assert File.exist?("#{@dir}/#{digest_path}") data = JSON.parse(File.read(manifest.filename)) assert data['files'][digest_path] assert data['assets']['application.js'] manifest.remove(digest_path) assert !File.exist?("#{@dir}/#{digest_path}") data = JSON.parse(File.read(manifest.filename)) assert !data['files'][digest_path] assert !data['assets']['application.js'] end test "remove old asset" do manifest = Sprockets::Manifest.new(@env, @dir) digest_path = @env['application.js'].digest_path filename = fixture_path('default/application.js.coffee') sandbox filename do manifest.compile('application.js') assert File.exist?("#{@dir}/#{digest_path}") File.open(filename, 'w') { |f| f.write "change;" } mtime = Time.now + 1 File.utime(mtime, mtime, filename) new_digest_path = @env['application.js'].digest_path manifest.compile('application.js') assert File.exist?("#{@dir}/#{new_digest_path}") manifest.remove(digest_path) assert !File.exist?("#{@dir}/#{digest_path}") data = JSON.parse(File.read(manifest.filename)) assert !data['files'][digest_path] assert data['files'][new_digest_path] assert_equal new_digest_path, data['assets']['application.js'] end end test "remove old backups(count)" do manifest = Sprockets::Manifest.new(@env, @dir) digest_path = @env['application.js'].digest_path filename = fixture_path('default/application.js.coffee') sandbox filename do manifest.compile('application.js') assert File.exist?("#{@dir}/#{digest_path}") File.open(filename, 'w') { |f| f.write "a;" } mtime = Time.now + 1 File.utime(mtime, mtime, filename) new_digest_path1 = @env['application.js'].digest_path manifest.compile('application.js') assert File.exist?("#{@dir}/#{new_digest_path1}") File.open(filename, 'w') { |f| f.write "b;" } mtime = Time.now + 2 File.utime(mtime, mtime, filename) new_digest_path2 = @env['application.js'].digest_path manifest.compile('application.js') assert File.exist?("#{@dir}/#{new_digest_path2}") File.open(filename, 'w') { |f| f.write "c;" } mtime = Time.now + 3 File.utime(mtime, mtime, filename) new_digest_path3 = @env['application.js'].digest_path manifest.compile('application.js') assert File.exist?("#{@dir}/#{new_digest_path3}") manifest.clean(1, 0) assert !File.exist?("#{@dir}/#{digest_path}") assert !File.exist?("#{@dir}/#{new_digest_path1}") assert File.exist?("#{@dir}/#{new_digest_path2}") assert File.exist?("#{@dir}/#{new_digest_path3}") data = JSON.parse(File.read(manifest.filename)) assert !data['files'][digest_path] assert !data['files'][new_digest_path1] assert data['files'][new_digest_path2] assert data['files'][new_digest_path3] assert_equal new_digest_path3, data['assets']['application.js'] end end test "remove old backups(age)" do manifest = Sprockets::Manifest.new(@env, @dir) filename = fixture_path('default/application.js.coffee') sandbox filename do File.open(filename, 'w') { |f| f.write "a;" } mtime = Time.local(2014, 4, 26, 12, 0, 0) File.utime(mtime, mtime, filename) new_digest_path1 = @env['application.js'].digest_path manifest.compile('application.js') assert File.exist?("#{@dir}/#{new_digest_path1}") File.open(filename, 'w') { |f| f.write "b;" } mtime = Time.local(2014, 4, 27, 8, 0, 0) File.utime(mtime, mtime, filename) new_digest_path2 = @env['application.js'].digest_path manifest.compile('application.js') assert File.exist?("#{@dir}/#{new_digest_path2}") File.open(filename, 'w') { |f| f.write "c;" } mtime = Time.local(2014, 4, 27, 9, 0, 0) File.utime(mtime, mtime, filename) new_digest_path3 = @env['application.js'].digest_path manifest.compile('application.js') assert File.exist?("#{@dir}/#{new_digest_path3}") Time.stub(:now, Time.local(2014, 4, 27, 12, 0, 0)) do manifest.clean(0, 60 * 60 * 24) end assert !File.exist?("#{@dir}/#{new_digest_path1}") assert File.exist?("#{@dir}/#{new_digest_path2}") assert File.exist?("#{@dir}/#{new_digest_path3}") data = JSON.parse(File.read(manifest.filename)) assert !data['files'][new_digest_path1] assert data['files'][new_digest_path2] assert data['files'][new_digest_path3] assert_equal new_digest_path3, data['assets']['application.js'] end end test "test manifest does not exist" do assert !File.exist?("#{@dir}/manifest.json") manifest = Sprockets::Manifest.new(@env, File.join(@dir, 'manifest.json')) manifest.compile('application.js') assert File.exist?("#{@dir}/manifest.json") data = JSON.parse(File.read(manifest.filename)) assert data['assets']['application.js'] end test "test blank manifest" do assert !File.exist?("#{@dir}/manifest.json") FileUtils.mkdir_p(@dir) File.open("#{@dir}/manifest.json", 'w') { |f| f.write "" } assert_equal "", File.read("#{@dir}/manifest.json") manifest = Sprockets::Manifest.new(@env, File.join(@dir, 'manifest.json')) manifest.compile('application.js') assert File.exist?("#{@dir}/manifest.json") data = JSON.parse(File.read(manifest.filename)) assert data['assets']['application.js'] end test "test skip invalid manifest" do assert !File.exist?("#{@dir}/manifest.json") FileUtils.mkdir_p(@dir) File.open("#{@dir}/manifest.json", 'w') { |f| f.write "not valid json;" } assert_equal "not valid json;", File.read("#{@dir}/manifest.json") manifest = Sprockets::Manifest.new(@env, File.join(@dir, 'manifest.json')) manifest.compile('application.js') assert File.exist?("#{@dir}/manifest.json") data = JSON.parse(File.read(manifest.filename)) assert data['assets']['application.js'] end test "nil environment raises compilation error" do assert !File.exist?("#{@dir}/manifest.json") manifest = Sprockets::Manifest.new(nil, File.join(@dir, 'manifest.json')) assert_raises Sprockets::Error do manifest.compile('application.js') end end test "no environment raises compilation error" do assert !File.exist?("#{@dir}/manifest.json") manifest = Sprockets::Manifest.new(File.join(@dir, 'manifest.json')) assert_raises Sprockets::Error do manifest.compile('application.js') end end test "find all filenames matching fnmatch filters" do manifest = Sprockets::Manifest.new(@env, @dir) paths = [] manifest.find("mobile/*.js").each do |asset| paths << asset.logical_path end assert paths.include?("mobile/a.js") assert paths.include?("mobile/b.js") assert !paths.include?("mobile/c.css") end test "iterate over each logical path matches index files" do manifest = Sprockets::Manifest.new(@env, @dir) paths = [] manifest.find("coffee.js").each do |asset| paths << asset.logical_path end assert paths.include?("coffee/index.js") assert !paths.include?("coffee.js") end test "each logical path enumerator matching fnmatch filters" do manifest = Sprockets::Manifest.new(@env, @dir) paths = [] enum = manifest.find("mobile/*.js") enum.to_a.each do |asset| paths << asset.logical_path end assert paths.include?("mobile/a.js") assert paths.include?("mobile/b.js") assert !paths.include?("mobile/c.css") end test "iterate over each logical path matching regexp filters" do manifest = Sprockets::Manifest.new(@env, @dir) paths = [] manifest.find(/mobile\/.*\.js/).each do |asset| paths << asset.logical_path end assert paths.include?("mobile/a.js") assert paths.include?("mobile/b.js") assert !paths.include?("mobile/c.css") end test "iterate over each logical path matching proc filters" do manifest = Sprockets::Manifest.new(@env, @dir) paths = [] manifest.find(proc { |fn| fn.match("mobile/") && File.extname(fn) == '.js' }).each do |asset| paths << asset.logical_path end assert paths.include?("mobile/a.js") assert paths.include?("mobile/b.js") assert !paths.include?("mobile/c.css") end test "iterate over each logical path matching proc filters with full path arg" do manifest = Sprockets::Manifest.new(@env, @dir) paths = [] manifest.find(proc { |_, fn| fn.match(fixture_path('default/mobile')) }).each do |asset| paths << asset.logical_path end assert paths.include?("mobile/a.js") assert paths.include?("mobile/b.js") assert !paths.include?("application.js") end test "find_sources with environment" do manifest = Sprockets::Manifest.new(@env, @dir) result = manifest.find_sources("mobile/a.js", "mobile/b.js") assert_equal ["var A;\n", "var B;\n"], result.to_a.sort result = manifest.find_sources("not_existent.js", "also_not_existent.js") assert_equal [], result.to_a result = manifest.find_sources("mobile/a.js", "also_not_existent.js") assert_equal ["var A;\n"], result.to_a end test "find_sources without environment" do manifest = Sprockets::Manifest.new(@env, @dir) manifest.compile('mobile/a.js', 'mobile/b.js') manifest = Sprockets::Manifest.new(nil, @dir) result = manifest.find_sources("mobile/a.js", "mobile/b.js") assert_equal ["var A;\n", "var B;\n"], result.to_a result = manifest.find_sources("not_existent.js", "also_not_existent.js") assert_equal [], result.to_a result = manifest.find_sources("mobile/a.js", "also_not_existent.js") assert_equal ["var A;\n"], result.to_a end test "compress non-binary assets" do manifest = Sprockets::Manifest.new(@env, @dir) %W{ gallery.css application.js logo.svg favicon.ico }.each do |file_name| original_path = @env[file_name].digest_path manifest.compile(file_name) assert File.exist?("#{@dir}/#{original_path}.gz"), "Expecting '#{original_path}' to generate gzipped file: '#{original_path}.gz' but it did not" assert_equal File.stat("#{@dir}/#{original_path}").mtime, Zlib::GzipReader.open("#{@dir}/#{original_path}.gz") {|gz| gz.mtime } end end test "writes gzip files even if files were already on disk" do @env.gzip = false manifest = Sprockets::Manifest.new(@env, @dir) files = %W{ gallery.css application.js logo.svg favicon.ico} files.each do |file_name| original_path = @env[file_name].digest_path manifest.compile(file_name) assert File.exist?("#{@dir}/#{original_path}"), "Expecting \"#{@dir}/#{original_path}\" to exist but did not" end @env.gzip = true files.each do |file_name| original_path = @env[file_name].digest_path manifest.compile(file_name) assert File.exist?("#{@dir}/#{original_path}.gz"), "Expecting '#{original_path}' to generate gzipped file: '#{original_path}.gz' but it did not" assert_equal File.stat("#{@dir}/#{original_path}").mtime, Zlib::GzipReader.open("#{@dir}/#{original_path}.gz") {|gz| gz.mtime } end end test "disable file gzip" do @env.gzip = false manifest = Sprockets::Manifest.new(@env, @dir) %W{ gallery.css application.js logo.svg favicon.ico }.each do |file_name| original_path = @env[file_name].digest_path manifest.compile(file_name) refute File.exist?("#{@dir}/#{original_path}.gz"), "Expecting '#{original_path}' to not generate gzipped file: '#{original_path}.gz' but it did" end end test "do not compress binary assets" do manifest = Sprockets::Manifest.new(@env, @dir) %W{ blank.gif }.each do |file_name| original_path = @env[file_name].digest_path manifest.compile(file_name) refute File.exist?("#{@dir}/#{original_path}.gz"), "Expecting '#{original_path}' to not generate gzipped file: '#{original_path}.gz' but it did" end end test 'raises exception when gzip fails' do manifest = Sprockets::Manifest.new(@env, @dir) Zlib::GzipWriter.stub(:new, -> { fail 'kaboom' }) do assert_raises('kaboom') { manifest.compile('application.js') } end end end sprockets-3.7.2/test/test_manifest_utils.rb000066400000000000000000000014371331222022000211210ustar00rootroot00000000000000require 'minitest/autorun' require 'sprockets/manifest_utils' class TestManifestUtils < MiniTest::Test include Sprockets::ManifestUtils def test_generate_manifest_path assert_match(MANIFEST_RE, generate_manifest_path) end def test_find_directory_manifest root = File.expand_path("../fixtures/manifest_utils", __FILE__) assert_match MANIFEST_RE, File.basename(find_directory_manifest(root)) assert_equal "#{root}/default/.sprockets-manifest-f4bf345974645583d284686ddfb7625e.json", find_directory_manifest("#{root}/default") assert_equal "#{root}/legacy/manifest-02f33520c330d408567423cefa7a03ba.json", find_directory_manifest("#{root}/legacy") assert_equal "#{root}/legacy2/manifest.json", find_directory_manifest("#{root}/legacy2") end end sprockets-3.7.2/test/test_path_dependency_utils.rb000066400000000000000000000061451331222022000224460ustar00rootroot00000000000000require 'minitest/autorun' require 'sprockets/path_dependency_utils' class TestPathDependencyUtils < MiniTest::Test include Sprockets::PathDependencyUtils def test_entries_with_dependencies path = File.expand_path("../fixtures", __FILE__) filenames, deps = entries_with_dependencies(path) assert_kind_of Array, filenames assert filenames.size > 1 assert_equal [build_file_digest_uri(path)], deps.to_a path = "/tmp/sprockets/missingdir" filenames, deps = entries_with_dependencies(path) assert_kind_of Array, filenames assert filenames.empty? assert_equal [build_file_digest_uri(path)], deps.to_a end FILES_IN_SERVER = Dir["#{File.expand_path("../fixtures/server", __FILE__)}/*"] def test_stat_directory_with_dependencies dirname = File.expand_path("../fixtures/server", __FILE__) filenames, deps = stat_directory_with_dependencies(dirname) assert_equal FILES_IN_SERVER.size, filenames.size assert_equal [build_file_digest_uri(dirname)], deps.to_a path, stat = filenames.first assert_equal File.expand_path("../fixtures/server/app", __FILE__), path assert_kind_of File::Stat, stat dirname = File.expand_path("../fixtures/missing", __FILE__) filenames, deps = stat_directory_with_dependencies(dirname) assert_equal [], filenames assert_equal [build_file_digest_uri(dirname)], deps.to_a end def test_stat_sorted_tree_with_dependencies dirname = File.expand_path("../fixtures/asset/tree/all", __FILE__) filenames, deps = stat_sorted_tree_with_dependencies(dirname) assert_equal 11, filenames.size assert_equal [ File.expand_path("../fixtures/asset/tree/all", __FILE__), File.expand_path("../fixtures/asset/tree/all/b", __FILE__), File.expand_path("../fixtures/asset/tree/all/b/c", __FILE__), File.expand_path("../fixtures/asset/tree/all/d", __FILE__) ].map { |p| build_file_digest_uri(p) }, deps.to_a path, stat = filenames.first assert_equal File.expand_path("../fixtures/asset/tree/all/README.md", __FILE__), path assert_kind_of File::Stat, stat assert_equal [ File.expand_path("../fixtures/asset/tree/all/README.md", __FILE__), File.expand_path("../fixtures/asset/tree/all/b.css", __FILE__), File.expand_path("../fixtures/asset/tree/all/b.js.erb", __FILE__), File.expand_path("../fixtures/asset/tree/all/b", __FILE__), File.expand_path("../fixtures/asset/tree/all/b/c.js", __FILE__), File.expand_path("../fixtures/asset/tree/all/b/c", __FILE__), File.expand_path("../fixtures/asset/tree/all/b/c/d.js", __FILE__), File.expand_path("../fixtures/asset/tree/all/b/c/e.js", __FILE__), File.expand_path("../fixtures/asset/tree/all/d", __FILE__), File.expand_path("../fixtures/asset/tree/all/d/c.js.coffee", __FILE__), File.expand_path("../fixtures/asset/tree/all/d/e.js", __FILE__), ], filenames.map(&:first) dirname = File.expand_path("../fixtures/missing", __FILE__) filenames, deps = stat_sorted_tree_with_dependencies(dirname) assert_equal [], filenames assert_equal [build_file_digest_uri(dirname)], deps.to_a end end sprockets-3.7.2/test/test_path_digest_utils.rb000066400000000000000000000050631331222022000216050ustar00rootroot00000000000000require 'minitest/autorun' require 'sprockets/path_digest_utils' class TestPathDigestUtils < MiniTest::Test include Sprockets::PathDigestUtils def test_file_stat_digest path = File.expand_path("../fixtures/default/hello.txt", __FILE__) assert_equal "81491ac958ab51a3bc7f34cae434cf00c49861402bf6c8961e8ee32afa7c4cf8", stat_digest(path, File.stat(path)).unpack("h*")[0] assert_equal "81491ac958ab51a3bc7f34cae434cf00c49861402bf6c8961e8ee32afa7c4cf8", file_digest(path).unpack("h*")[0] end def test_directory_stat_digest path = File.expand_path("../fixtures/default/app", __FILE__) assert_equal "8514e7f087b1666549d97352c8b80925de62e6e27b5a61c3dab780366e2b19a6", stat_digest(path, File.stat(path)).unpack("h*")[0] assert_equal "8514e7f087b1666549d97352c8b80925de62e6e27b5a61c3dab780366e2b19a6", file_digest(path).unpack("h*")[0] end def test_symlink_stat_digest skip "no symlinks available" unless File.symlink?(File.expand_path("../fixtures/default/symlink", __FILE__)) path = File.expand_path("../fixtures/default/mobile", __FILE__) assert_equal "e571f54b8982049817ee30d0bf0dcf5dd8c09252b50696f7ccb44019c9229ccd", stat_digest(path, File.stat(path)).unpack("h*")[0] path = File.expand_path("../fixtures/default/symlink", __FILE__) assert_equal "e571f54b8982049817ee30d0bf0dcf5dd8c09252b50696f7ccb44019c9229ccd", stat_digest(path, File.stat(path)).unpack("h*")[0] assert_equal "e571f54b8982049817ee30d0bf0dcf5dd8c09252b50696f7ccb44019c9229ccd", file_digest(path).unpack("h*")[0] end def test_unix_device_stat_digest if File.exist?("/dev/stdin") && File.stat("/dev/stdin").chardev? assert_raises(TypeError) do stat_digest("/dev/stdin", File.stat("/dev/stdin")) end assert_raises(TypeError) do file_digest("/dev/stdin") end else skip "no unix device available" end end def test_missing_file_digest path = "./filedoesnotexist" refute File.exist?(path) refute file_digest(path) end def test_multiple_file_digests skip "no symlinks available" unless File.symlink?(File.expand_path("../fixtures/default/symlink", __FILE__)) paths = [] paths << File.expand_path("../fixtures/default/hello.txt", __FILE__) paths << File.expand_path("../fixtures/default/app", __FILE__) paths << File.expand_path("../fixtures/default/symlink", __FILE__) paths << "./filedoesnotexist" assert_equal "95f41ef27ae30ceaaa726f85b3298e1be4ff4bf5bf83deec0f760b50e3ffc09f", files_digest(paths).unpack("h*")[0] end end sprockets-3.7.2/test/test_path_utils.rb000066400000000000000000000264511331222022000202520ustar00rootroot00000000000000require 'minitest/autorun' require 'sprockets/path_utils' class TestPathUtils < MiniTest::Test include Sprockets::PathUtils DOSISH = File::ALT_SEPARATOR != nil DOSISH_DRIVE_LETTER = File.dirname("A:") == "A:." DOSISH_UNC = File.dirname("//") == "//" def test_stat assert_kind_of File::Stat, stat(File.expand_path("../fixtures", __FILE__)) refute stat("/tmp/sprockets/missingfile") end def test_file assert_equal true, file?(File.expand_path("../fixtures/default/hello.txt", __FILE__)) assert_equal false, file?(File.expand_path("../fixtures", __FILE__)) end def test_directory assert_equal true, directory?(File.expand_path("../fixtures", __FILE__)) assert_equal false, directory?(File.expand_path("../fixtures/default/hello.txt", __FILE__)) end def test_entries assert_equal [ "asset", "compass", "context", "default", "directives", "encoding", "engines", "errors", "manifest_utils", "octicons", "paths", "public", "resolve", "sass", "server", "source-maps", "symlink" ], entries(File.expand_path("../fixtures", __FILE__)) [ ['a', 'b'], ['a', 'b', '.', '..'] ].each do |dir_contents| Dir.stub :entries, dir_contents do assert_equal ['a', 'b'], entries(Dir.tmpdir) end end assert_equal [], entries("/tmp/sprockets/missingdir") end def test_check_absolute_path assert absolute_path?(Dir.pwd) assert absolute_path?("/foo.rb") refute absolute_path?("foo.rb") refute absolute_path?("./foo.rb") refute absolute_path?("../foo.rb") if DOSISH_DRIVE_LETTER assert absolute_path?("A:foo.rb") assert absolute_path?("A:/foo.rb") assert absolute_path?("A:\\foo.rb") end if DOSISH assert absolute_path?("/foo.rb") assert absolute_path?("\\foo.rb") end end def test_check_relative_path assert relative_path?(".") assert relative_path?("..") assert relative_path?("./") assert relative_path?("../") assert relative_path?("./foo.rb") assert relative_path?("../foo.rb") if DOSISH assert relative_path?(".\\") assert relative_path?("..\\") assert relative_path?(".\\foo.rb") assert relative_path?("..\\foo.rb") end refute relative_path?(Dir.pwd) refute relative_path?("/foo.rb") refute relative_path?("foo.rb") refute relative_path?(".foo.rb") refute relative_path?("..foo.rb") end def test_split_subpath_from_root_path path = File.expand_path("../fixtures/default", __FILE__) subpath = File.expand_path("../fixtures/default/application.js", __FILE__) assert_equal "application.js", split_subpath(path, subpath) subpath = File.expand_path("../fixtures/default/application.js", __FILE__) assert_equal "application.js", split_subpath(path + "/", subpath) subpath = File.expand_path("../fixtures/default/app/application.js", __FILE__) assert_equal "app/application.js", split_subpath(path, subpath) subpath = File.expand_path("../fixtures/default", __FILE__) assert_equal "", split_subpath(path, subpath) subpath = File.expand_path("../fixtures/other/app/application.js", __FILE__) refute split_subpath(path, subpath) end def test_split_paths_root_from_base paths = [File.expand_path("../fixtures/default", __FILE__)] filename = File.expand_path("../fixtures/default/application.js", __FILE__) expected = [paths.first, "application.js"] assert_equal expected, paths_split(paths, filename) filename = File.expand_path("../fixtures/default/app/application.js", __FILE__) expected = [paths.first, "app/application.js"] assert_equal expected, paths_split(paths, filename) filename = File.expand_path("../fixtures/default", __FILE__) expected = [paths.first, ""] assert_equal expected, paths_split(paths, filename) filename = File.expand_path("../fixtures/other/app/application.js", __FILE__) refute paths_split(paths, filename) end def test_path_extensions assert_equal [".txt"], path_extnames("hello.txt") assert_equal [".txt"], path_extnames("sub/hello.txt") assert_equal [".txt"], path_extnames("sub.dir/hello.txt") assert_equal [".js"], path_extnames("jquery.js") assert_equal [".min", ".js"], path_extnames("jquery.min.js") assert_equal [".js", ".erb"], path_extnames("jquery.js.erb") assert_equal [".min", ".js", ".erb"], path_extnames("jquery.min.js.erb") end def test_match_path_extname extensions = { ".txt" => "text/plain" } assert_equal [".txt", "text/plain"], match_path_extname("hello.txt", extensions) assert_equal [".txt", "text/plain"], match_path_extname("sub/hello.txt", extensions) refute match_path_extname("hello.text", extensions) extensions = { ".js" => "application/javascript" } assert_equal [".js", "application/javascript"], match_path_extname("jquery.js", extensions) assert_equal [".js", "application/javascript"], match_path_extname("jquery.min.js", extensions) refute match_path_extname("jquery.js.erb", extensions) refute match_path_extname("jquery.min.js.erb", extensions) extensions = { ".js" => "application/javascript", ".js.erb" => "application/javascript+ruby" } assert_equal [".js", "application/javascript"], match_path_extname("jquery.js", extensions) assert_equal [".js", "application/javascript"], match_path_extname("jquery.min.js", extensions) assert_equal [".js.erb", "application/javascript+ruby"], match_path_extname("jquery.js.erb", extensions) assert_equal [".js.erb", "application/javascript+ruby"], match_path_extname("jquery.min.js.erb", extensions) refute match_path_extname("jquery.min.coffee.erb", extensions) extensions = { ".js.map" => "application/json", ".css.map" => "application/json" } assert_equal [".js.map", "application/json"], match_path_extname("jquery.js.map", extensions) assert_equal [".js.map", "application/json"], match_path_extname("jquery.min.js.map", extensions) assert_equal [".css.map", "application/json"], match_path_extname("jquery-ui.css.map", extensions) assert_equal [".css.map", "application/json"], match_path_extname("jquery-ui.min.css.map", extensions) refute match_path_extname("jquery.map", extensions) refute match_path_extname("jquery.map.js", extensions) refute match_path_extname("jquery.map.css", extensions) extensions = { ".coffee" => "application/coffeescript", ".js" => "application/javascript", ".js.jsx.coffee" => "application/jsx+coffee" } assert_equal [".js.jsx.coffee", "application/jsx+coffee"], match_path_extname("component.js.jsx.coffee", extensions) end def test_path_parents root = File.expand_path("../..", __FILE__) assert_kind_of Array, path_parents(File.expand_path(__FILE__)) assert_equal ["#{root}/test", root], path_parents(File.expand_path(__FILE__), root) assert_equal ["#{root}/test", root], path_parents("#{root}/test/fixtures/", root) assert_equal ["#{root}/test/fixtures", "#{root}/test", root], path_parents("#{root}/test/fixtures/default", root) assert_equal ["#{root}/test/fixtures/default", "#{root}/test/fixtures", "#{root}/test", root], path_parents("#{root}/test/fixtures/default/POW.png", root) assert_equal ["#{root}/test/fixtures/default", "#{root}/test/fixtures", "#{root}/test"], path_parents("#{root}/test/fixtures/default/POW.png", "#{root}/test") assert_equal ["#{root}/test/fixtures/default"], path_parents("#{root}/test/fixtures/default/POW.png", "#{root}/test/fixtures/default") end def test_find_upwards root = File.expand_path("../..", __FILE__) assert_equal "#{root}/Gemfile", find_upwards("Gemfile", File.expand_path(__FILE__)) assert_equal "#{root}/Gemfile", find_upwards("Gemfile", "#{root}/test/fixtures/") assert_equal "#{root}/Gemfile", find_upwards("Gemfile", "#{root}/test/fixtures/default/POW.png") assert_equal "#{root}/test/sprockets_test.rb", find_upwards("sprockets_test.rb", "#{root}/test/fixtures/default/POW.png") end FILES_IN_SERVER = Dir["#{File.expand_path("../fixtures/server", __FILE__)}/*"] def test_stat_directory files = stat_directory(File.expand_path("../fixtures/server", __FILE__)).to_a assert_equal FILES_IN_SERVER.size, files.size path, stat = stat_directory(File.expand_path("../fixtures/server", __FILE__)).first assert_equal File.expand_path("../fixtures/server/app", __FILE__), path assert_kind_of File::Stat, stat assert_equal [], stat_directory(File.expand_path("../fixtures/missing", __FILE__)).to_a end def test_stat_tree files = stat_tree(File.expand_path("../fixtures/asset/tree/all", __FILE__)).to_a assert_equal 11, files.size path, stat = files.first assert_equal File.expand_path("../fixtures/asset/tree/all/README.md", __FILE__), path assert_kind_of File::Stat, stat assert_equal [ File.expand_path("../fixtures/asset/tree/all/README.md", __FILE__), File.expand_path("../fixtures/asset/tree/all/b", __FILE__), File.expand_path("../fixtures/asset/tree/all/b/c", __FILE__), File.expand_path("../fixtures/asset/tree/all/b/c/d.js", __FILE__), File.expand_path("../fixtures/asset/tree/all/b/c/e.js", __FILE__), File.expand_path("../fixtures/asset/tree/all/b/c.js", __FILE__), File.expand_path("../fixtures/asset/tree/all/b.css", __FILE__), File.expand_path("../fixtures/asset/tree/all/b.js.erb", __FILE__), File.expand_path("../fixtures/asset/tree/all/d", __FILE__), File.expand_path("../fixtures/asset/tree/all/d/c.js.coffee", __FILE__), File.expand_path("../fixtures/asset/tree/all/d/e.js", __FILE__) ], files.map(&:first) assert_equal [], stat_tree("#{File.expand_path("../fixtures", __FILE__)}/missing").to_a end def test_stat_sorted_tree files = stat_sorted_tree(File.expand_path("../fixtures/asset/tree/all", __FILE__)).to_a assert_equal 11, files.size path, stat = files.first assert_equal File.expand_path("../fixtures/asset/tree/all/README.md", __FILE__), path assert_kind_of File::Stat, stat assert_equal [ File.expand_path("../fixtures/asset/tree/all/README.md", __FILE__), File.expand_path("../fixtures/asset/tree/all/b.css", __FILE__), File.expand_path("../fixtures/asset/tree/all/b.js.erb", __FILE__), File.expand_path("../fixtures/asset/tree/all/b", __FILE__), File.expand_path("../fixtures/asset/tree/all/b/c.js", __FILE__), File.expand_path("../fixtures/asset/tree/all/b/c", __FILE__), File.expand_path("../fixtures/asset/tree/all/b/c/d.js", __FILE__), File.expand_path("../fixtures/asset/tree/all/b/c/e.js", __FILE__), File.expand_path("../fixtures/asset/tree/all/d", __FILE__), File.expand_path("../fixtures/asset/tree/all/d/c.js.coffee", __FILE__), File.expand_path("../fixtures/asset/tree/all/d/e.js", __FILE__), ], files.map(&:first) assert_equal [], stat_tree(File.expand_path("../fixtures/missing", __FILE__)).to_a end def test_atomic_write_without_errors filename = "atomic.file" begin contents = "Atomic Text" atomic_write(filename) do |file| file.write(contents) assert !File.exist?(filename) end assert File.exist?(filename) assert_equal contents, File.read(filename) ensure File.unlink(filename) rescue nil end end end sprockets-3.7.2/test/test_performance.rb000066400000000000000000000344311331222022000203740ustar00rootroot00000000000000require 'sprockets_test' $file_stat_calls = nil class << File alias_method :original_stat, :stat def stat(filename) if $file_stat_calls $file_stat_calls[filename.to_s] ||= [] $file_stat_calls[filename.to_s] << caller end original_stat(filename) end end $dir_entires_calls = nil class << Dir alias_method :original_entries, :entries def entries(dirname, *args) if $dir_entires_calls $dir_entires_calls[dirname.to_s] ||= [] $dir_entires_calls[dirname.to_s] << caller end original_entries(dirname, *args) end end class TestPerformance < Sprockets::TestCase class Cache def initialize @cache = {} end def get(key) $cache_get_calls[key] ||= [] $cache_get_calls[key] << caller @cache[key] end def set(key, value) $cache_set_calls[key] ||= [] $cache_set_calls[key] << caller @cache[key] = value end end def setup @env = new_environment reset_stats! end def teardown $file_stat_calls = nil $dir_entires_calls = nil $processor_calls = nil $bundle_processor_calls = nil $cache_get_calls = nil $cache_set_calls = nil end test "simple file" do @env["gallery.js"].to_s assert_no_redundant_stat_calls assert_no_redundant_processor_calls assert_no_redundant_bundle_processor_calls end test "cached simple file" do @env.cached["gallery.js"].to_s assert_no_redundant_stat_calls assert_no_redundant_processor_calls assert_no_redundant_bundle_processor_calls end test "file with deps" do @env["mobile.js"].to_s assert_no_redundant_stat_calls assert_no_redundant_processor_calls assert_no_redundant_bundle_processor_calls end test "cached file with deps" do @env.cached["mobile.js"].to_s assert_no_redundant_stat_calls assert_no_redundant_processor_calls assert_no_redundant_bundle_processor_calls end test "loading from backend cache" do env1, env2 = new_environment, new_environment cache = Cache.new env1.cache = cache env2.cache = cache env1["mobile.js"] assert_no_redundant_processor_calls assert_no_redundant_bundle_processor_calls assert_no_redundant_cache_set_calls reset_stats! env2["mobile.js"] assert_no_redundant_stat_calls assert_no_processor_calls assert_no_bundle_processor_calls assert_no_redundant_cache_get_calls assert_no_cache_set_calls end test "moving root of project after generation is still freaky fast" do env1 = new_environment env1.cache = Cache.new env1["mobile.js"] assert_no_redundant_processor_calls assert_no_redundant_bundle_processor_calls assert_no_redundant_cache_set_calls Dir.mktmpdir do |dir| Dir.chdir(dir) do `cp -R #{File.join(fixture_path("default"), "*")} .` env2 = new_environment("./default") env2.cache = env1.cache reset_stats! env2["mobile.js"] assert_no_redundant_stat_calls assert_no_processor_calls assert_no_bundle_processor_calls assert_no_redundant_cache_get_calls assert_no_cache_set_calls end end end test "loading from instance cache" do env = @env.cached env["mobile.js"] assert_no_redundant_processor_calls assert_no_redundant_bundle_processor_calls reset_stats! env["mobile.js"] assert_no_stat_calls assert_no_processor_calls assert_no_bundle_processor_calls end test "loading from cached with backend cache" do env1, env2 = new_environment, new_environment cache = Cache.new env1.cache = cache env2.cache = cache env1.cached["mobile.js"] assert_no_redundant_processor_calls assert_no_redundant_bundle_processor_calls assert_no_redundant_cache_set_calls reset_stats! env2.cached["mobile.js"] assert_no_redundant_stat_calls assert_no_processor_calls assert_no_bundle_processor_calls assert_no_redundant_cache_get_calls assert_no_cache_set_calls end test "rollback version" do env = new_environment env.cache = Cache.new env.version = "1" assert asset = env["mobile.js"] id1 = asset.id assert_no_redundant_processor_calls assert_no_redundant_bundle_processor_calls assert_no_redundant_cache_set_calls reset_stats! env.version = "2" assert asset = env["mobile.js"] id2 = asset.id assert_no_redundant_processor_calls assert_no_redundant_bundle_processor_calls assert_no_redundant_cache_set_calls reset_stats! env.version = "1" assert asset = env["mobile.js"] assert_equal id1, asset.id assert_no_redundant_stat_calls assert_no_processor_calls assert_no_bundle_processor_calls assert_no_redundant_cache_get_calls assert_no_cache_set_calls reset_stats! env.version = "2" assert asset = env["mobile.js"] assert_equal id2, asset.id assert_no_redundant_stat_calls assert_no_processor_calls assert_no_bundle_processor_calls assert_no_redundant_cache_get_calls assert_no_cache_set_calls end test "rollback path change" do env = new_environment env.cache = Cache.new env.clear_paths env.append_path(fixture_path('default')) assert asset = env["mobile.js"] path1 = asset.id assert_no_redundant_processor_calls assert_no_redundant_bundle_processor_calls assert_no_redundant_cache_set_calls reset_stats! env.clear_paths env.append_path(fixture_path('asset')) env.append_path(fixture_path('default')) assert asset = env["mobile.js"] path2 = asset.id assert_no_redundant_processor_calls assert_no_redundant_bundle_processor_calls assert_no_redundant_cache_set_calls reset_stats! env.clear_paths env.append_path(fixture_path('default')) assert asset = env["mobile.js"] assert_equal path1, asset.id assert_no_redundant_stat_calls assert_no_processor_calls assert_no_bundle_processor_calls assert_no_redundant_cache_get_calls assert_no_cache_set_calls reset_stats! env.clear_paths env.append_path(fixture_path('asset')) env.append_path(fixture_path('default')) assert asset = env["mobile.js"] assert_equal path2, asset.id assert_no_redundant_stat_calls assert_no_processor_calls assert_no_bundle_processor_calls assert_no_redundant_cache_get_calls assert_no_cache_set_calls end test "rollback file change" do env = new_environment env.cache = Cache.new filename = fixture_path("default/tmp.js") sandbox filename do write(filename, "a;", 1421000000) reset_stats! assert asset = env["tmp.js"] assert_equal "a;\n", asset.source ida = asset.id assert_no_redundant_processor_calls assert_no_redundant_bundle_processor_calls assert_no_redundant_cache_set_calls write(filename, "b;", 1421000001) reset_stats! assert asset = env["tmp.js"] assert_equal "b;\n", asset.source idb = asset.id assert_no_redundant_processor_calls assert_no_redundant_bundle_processor_calls assert_no_redundant_cache_set_calls write(filename, "a;", 1421000000) reset_stats! assert asset = env["tmp.js"] assert_equal "a;\n", asset.source assert_equal ida, asset.id assert_no_redundant_stat_calls assert_no_processor_calls assert_no_bundle_processor_calls assert_no_redundant_cache_get_calls assert_no_cache_set_calls write(filename, "b;", 1421000001) reset_stats! assert asset = env["tmp.js"] assert_equal "b;\n", asset.source assert_equal idb, asset.id assert_no_redundant_stat_calls assert_no_processor_calls assert_no_bundle_processor_calls assert_no_redundant_cache_get_calls assert_no_cache_set_calls end end test "rollback file dependency change" do env = new_environment env.cache = Cache.new main = fixture_path("default/tmp-main.js") dep = fixture_path("default/tmp-dep.js") sandbox main, dep do write(main, "//= require ./tmp-dep", 1421000000) write(dep, "a;", 1421000000) reset_stats! assert asset = env["tmp-main.js"] assert_equal "a;\n", asset.source ida = asset.id assert_no_redundant_processor_calls assert_no_redundant_bundle_processor_calls assert_no_redundant_cache_set_calls write(dep, "b;", 1421000001) reset_stats! assert asset = env["tmp-main.js"] assert_equal "b;\n", asset.source idb = asset.id assert_no_redundant_processor_calls assert_no_redundant_bundle_processor_calls assert_no_redundant_cache_set_calls write(dep, "a;", 1421000000) reset_stats! assert asset = env["tmp-main.js"] assert_equal "a;\n", asset.source assert_equal ida, asset.id assert_no_redundant_stat_calls assert_no_processor_calls assert_no_bundle_processor_calls assert_no_redundant_cache_get_calls assert_no_cache_set_calls write(dep, "b;", 1421000001) reset_stats! assert asset = env["tmp-main.js"] assert_equal "b;\n", asset.source assert_equal idb, asset.id assert_no_redundant_stat_calls assert_no_processor_calls assert_no_bundle_processor_calls assert_no_redundant_cache_get_calls assert_no_cache_set_calls end end test "rollback file dependency add/remove" do env = new_environment env.cache = Cache.new main = fixture_path("default/tmp.js") deps = fixture_path("default/tmp") depa = fixture_path("default/tmp/a.js") depb = fixture_path("default/tmp/b.js") sandbox main, deps, depa, depb do FileUtils.mkdir_p(deps) write(main, "//= require_directory ./tmp", 1421000000) write(depa, "a;", 1421000000) File.utime(1421000000, 1421000000, deps) reset_stats! assert asset = env["tmp.js"] assert_equal "a;\n", asset.source ida = asset.id assert_no_redundant_processor_calls assert_no_redundant_bundle_processor_calls assert_no_redundant_cache_set_calls write(depb, "b;", 142100001) File.utime(1421000001, 1421000001, deps) reset_stats! assert asset = env["tmp.js"] assert_equal "a;\nb;\n", asset.source idab = asset.id assert_no_redundant_processor_calls assert_no_redundant_bundle_processor_calls assert_no_redundant_cache_set_calls FileUtils.rm(depb) File.utime(1421000000, 1421000000, deps) reset_stats! assert asset = env["tmp.js"] assert_equal "a;\n", asset.source assert_equal ida, asset.id assert_no_redundant_stat_calls assert_no_processor_calls assert_no_bundle_processor_calls assert_no_redundant_cache_get_calls assert_no_redundant_cache_set_calls write(depb, "b;", 142100001) File.utime(1421000001, 1421000001, deps) reset_stats! assert asset = env["tmp.js"] assert_equal "a;\nb;\n", asset.source assert_equal idab, asset.id assert_no_redundant_stat_calls assert_no_processor_calls assert_no_bundle_processor_calls assert_no_redundant_cache_get_calls assert_no_redundant_cache_set_calls end end def new_environment(path = fixture_path('default')) Sprockets::Environment.new(".") do |env| env.cache = Cache.new env.append_path(path) env.register_preprocessor 'application/javascript', proc { |input| $processor_calls[input[:filename]] ||= [] $processor_calls[input[:filename]] << caller nil } env.register_bundle_processor 'application/javascript', proc { |input| $bundle_processor_calls[input[:filename]] ||= [] $bundle_processor_calls[input[:filename]] << caller nil } end end def reset_stats! $file_stat_calls = {} $dir_entires_calls = {} $processor_calls = {} $bundle_processor_calls = {} $cache_get_calls = {} $cache_set_calls = {} end def assert_no_stat_calls $file_stat_calls.each do |path, callers| assert_equal 0, callers.size, "File.stat(#{path.inspect}) called #{callers.size} times\n\n#{format_callers(callers)}" end $dir_entires_calls.each do |path, callers| assert_equal 0, callers.size, "Dir.entries(#{path.inspect}) called #{callers.size} times\n\n#{format_callers(callers)}" end end def assert_no_redundant_stat_calls $file_stat_calls.each do |path, callers| assert_equal 1, callers.size, "File.stat(#{path.inspect}) called #{callers.size} times\n\n#{format_callers(callers)}" end $dir_entires_calls.each do |path, callers| assert_equal 1, callers.size, "Dir.entries(#{path.inspect}) called #{callers.size} times\n\n#{format_callers(callers)}" end end def assert_no_processor_calls $processor_calls.each do |path, callers| assert_equal 0, callers.size, "Processor ran on #{path.inspect} #{callers.size} times\n\n#{format_callers(callers)}" end end def assert_no_redundant_processor_calls $processor_calls.each do |path, callers| assert_equal 1, callers.size, "Processor ran on #{path.inspect} #{callers.size} times\n\n#{format_callers(callers)}" end end def assert_no_bundle_processor_calls $bundle_processor_calls.each do |path, callers| assert_equal 0, callers.size, "Bundle Processor ran on #{path.inspect} #{callers.size} times\n\n#{format_callers(callers)}" end end def assert_no_redundant_bundle_processor_calls $bundle_processor_calls.each do |path, callers| assert_equal 1, callers.size, "Bundle Processor ran on #{path.inspect} #{callers.size} times\n\n#{format_callers(callers)}" end end def assert_no_redundant_cache_get_calls $cache_get_calls.each do |key, callers| assert_equal 1, callers.size, "cache get #{key.inspect} #{callers.size} times\n\n#{format_callers(callers)}" end end def assert_no_cache_set_calls $cache_set_calls.each do |key, callers| assert_equal 0, callers.size, "cache set #{key.inspect} #{callers.size} times\n\n#{format_callers(callers)}" end end def assert_no_redundant_cache_set_calls $cache_set_calls.each do |key, callers| assert_equal 1, callers.size, "cache set #{key.inspect} #{callers.size} times\n\n#{format_callers(callers)}" end end def format_callers(callers) callers.map { |c| c.join("\n") }.join("\n\n\n") end end sprockets-3.7.2/test/test_processor_utils.rb000066400000000000000000000247341331222022000213370ustar00rootroot00000000000000require 'minitest/autorun' require 'sprockets/processor_utils' require 'sprockets/cache' require 'sprockets/coffee_script_processor' require 'sprockets/uglifier_compressor' require 'sprockets_test' class TestCallingProcessors < Sprockets::TestCase def setup @env = Sprockets::Environment.new @env.append_path fixture_path('default') end def test_charset_supersedes_default_when_nil processor = Proc.new do |input| {data: input[:data], charset: nil} end @env.register_processor('image/png' , processor) asset = @env['troll.png'] assert_equal nil, asset.charset ensure @env.unregister_preprocessor('image/png' , processor) end def test_charset_supersedes_default processor = Proc.new do |input| {data: input[:data], charset: 'foo'} end @env.register_processor('image/png' , processor) asset = @env['troll.png'] assert_equal 'foo', asset.charset ensure @env.unregister_preprocessor('image/png' , processor) end end class TestProcessorUtils < MiniTest::Test include Sprockets::ProcessorUtils class Processor def initialize(cache_key = nil, &block) @cache_key, @proc = cache_key, block end attr_reader :cache_key def call(*args) @proc.call(*args) end end def test_call_nothing a = proc {} input = { data: " " }.freeze assert result = call_processor(a, input) assert_equal " ", result[:data] end def test_call_function a = proc { |input| { data: input[:data] + ",a" } } input = { data: " " }.freeze assert result = call_processor(a, input) assert_equal " ,a", result[:data] end def test_call_single_function a = proc { |input| { data: input[:data] + ",a" } } input = { data: " " }.freeze assert result = call_processors([a], input) assert_equal " ,a", result[:data] end def test_call_hash_return a = proc { |input| { data: input[:data] + ",a" } } b = proc { |input| { data: input[:data] + ",b" } } input = { data: " " }.freeze assert result = call_processors([b, a], input) assert_equal " ,a,b", result[:data] end def test_call_string_return a = proc { |input| input[:data] + ",a" } b = proc { |input| input[:data] + ",b" } input = { data: " " }.freeze assert result = call_processors([b, a], input) assert_equal " ,a,b", result[:data] end def test_call_noop_return a = proc { |input| input[:data] + ",a" } b = proc { |input| nil } input = { data: " " }.freeze assert result = call_processors([a, b], input) assert_equal " ,a", result[:data] assert result = call_processors([b, a], input) assert_equal " ,a", result[:data] end def test_call_metadata a = proc { |input| { a: true } } b = proc { |input| { b: true } } input = {} assert result = call_processors([a, b], input) assert result[:a] assert result[:b] end def test_call_metadata_merge a = proc { |input| { trace: input[:metadata][:trace] + [:a] } } b = proc { |input| { trace: input[:metadata][:trace] + [:b] } } input = { metadata: { trace: [] }.freeze }.freeze assert result = call_processors([b, a], input) assert_equal [:a, :b], result[:trace] end def test_compose_nothing a = compose_processors() input = { data: " " }.freeze assert result = a.call(input) assert_equal " ", result[:data] end def test_compose_single_function a = proc { |input| { data: input[:data] + ",a" } } b = compose_processors(a) input = { data: " " }.freeze assert result = b.call(input) assert_equal " ,a", result[:data] end def test_compose_hash_return a = proc { |input| { data: input[:data] + ",a" } } b = proc { |input| { data: input[:data] + ",b" } } c = compose_processors(b, a) input = { data: " " }.freeze assert result = c.call(input) assert_equal " ,a,b", result[:data] end def test_compose_string_return a = proc { |input| input[:data] + ",a" } b = proc { |input| input[:data] + ",b" } c = compose_processors(b, a) input = { data: " " }.freeze assert result = c.call(input) assert_equal " ,a,b", result[:data] end def test_compose_noop_return a = proc { |input| input[:data] + ",a" } b = proc { |input| nil } c = compose_processors(a, b) d = compose_processors(b, a) input = { data: " " }.freeze assert result = c.call(input) assert_equal " ,a", result[:data] assert result = d.call(input) assert_equal " ,a", result[:data] end def test_compose_metadata a = proc { |input| { a: true } } b = proc { |input| { b: true } } c = compose_processors(a, b) input = {} assert result = c.call(input) assert result[:a] assert result[:b] end def test_compose_metadata_merge a = proc { |input| { trace: input[:metadata][:trace] + [:a] } } b = proc { |input| { trace: input[:metadata][:trace] + [:b] } } c = compose_processors(b, a) input = { metadata: { trace: [] }.freeze }.freeze assert result = c.call(input) assert_equal [:a, :b], result[:trace] end def test_multiple_functional_compose a = proc { |input| { data: input[:data] + ",a" } } b = proc { |input| { data: input[:data] + ",b" } } c = proc { |input| { data: input[:data] + ",c" } } d = proc { |input| { data: input[:data] + ",d" } } e = compose_processors(d, compose_processors(c, compose_processors(b, compose_processors(a)))) input = { data: " " }.freeze assert result = e.call(input) assert_equal " ,a,b,c,d", result[:data] end def test_multiple_functional_compose_metadata a = proc { |input| { trace: input[:metadata][:trace] + [:a] } } b = proc { |input| { trace: input[:metadata][:trace] + [:b] } } c = proc { |input| { trace: input[:metadata][:trace] + [:c] } } d = proc { |input| { trace: input[:metadata][:trace] + [:d] } } e = compose_processors(d, compose_processors(c, compose_processors(b, compose_processors(a)))) input = { metadata: { trace: [].freeze }.freeze }.freeze assert result = e.call(input) assert_equal [:a, :b, :c, :d], result[:trace] end def test_multiple_array_compose a = proc { |input| { data: input[:data] + ",a" } } b = proc { |input| { data: input[:data] + ",b" } } c = proc { |input| { data: input[:data] + ",c" } } d = proc { |input| { data: input[:data] + ",d" } } e = compose_processors(d, c, b, a) input = { data: " " } assert result = e.call(input) assert_equal " ,a,b,c,d", result[:data] end def test_multiple_array_compose_metadata a = proc { |input| { trace: input[:metadata][:trace] + [:a] } } b = proc { |input| { trace: input[:metadata][:trace] + [:b] } } c = proc { |input| { trace: input[:metadata][:trace] + [:c] } } d = proc { |input| { trace: input[:metadata][:trace] + [:d] } } e = compose_processors(d, c, b, a) input = { metadata: { trace: [].freeze }.freeze }.freeze assert result = e.call(input) assert_equal [:a, :b, :c, :d], result[:trace] end def test_compose_coffee_and_uglifier processor = compose_processors(Sprockets::UglifierCompressor, Sprockets::CoffeeScriptProcessor) input = { content_type: 'application/javascript', data: "self.square = (n) -> n * n", cache: Sprockets::Cache.new }.freeze assert result = processor.call(input) assert_match "self.square=function", result[:data] end def test_bad_processor_return_type a = proc { |input| Object.new } b = compose_processors(a) input = { data: " " }.freeze assert_raises(TypeError) do b.call(input) end end def test_compose_class_processors a = Processor.new { |input| { data: input[:data] + ",a" } } b = Processor.new { |input| { data: input[:data] + ",b" } } c = compose_processors(b, a) input = { data: " " }.freeze assert result = c.call(input) assert_equal " ,a,b", result[:data] end def test_compose_processors_cache_keys a = Processor.new("a") b = Processor.new("b") c = compose_processors(b, a) assert_equal "a", a.cache_key assert_equal "b", b.cache_key assert_equal ["b", "a"], c.cache_key end def test_compose_processors_missing_cache_keys a = Processor.new("a") b = proc {} c = Processor.new("c") e = compose_processors(c, b, a) assert_equal "a", a.cache_key assert_equal "c", c.cache_key assert_equal ["c", nil, "a"], e.cache_key end def test_multiple_array_compose_cache_keys a = Processor.new("a") b = Processor.new("b") c = Processor.new("c") d = Processor.new("d") e = compose_processors(d, c, b, a) assert_equal "a", a.cache_key assert_equal "b", b.cache_key assert_equal "c", c.cache_key assert_equal "d", d.cache_key assert_equal ["d", "c", "b", "a"], e.cache_key end def test_multiple_functional_compose_cache_keys a = Processor.new("a") b = Processor.new("b") c = Processor.new("c") d = Processor.new("d") e = compose_processors(d, compose_processors(c, compose_processors(b, compose_processors(a)))) assert_equal "a", a.cache_key assert_equal "b", b.cache_key assert_equal "c", c.cache_key assert_equal "d", d.cache_key assert_equal ["d", ["c", ["b", ["a"]]]], e.cache_key end def test_validate_processor_result validate_processor_result!({data: "hello"}) validate_processor_result!({data: "hello", foo: nil}) validate_processor_result!({data: "hello", foo: 1}) validate_processor_result!({data: "hello", foo: "bye"}) validate_processor_result!({data: "hello", foo: :bye}) validate_processor_result!({data: "hello", foo: [1, 2, 3]}) validate_processor_result!({data: "hello", foo: Set.new([1, 2, 3])}) validate_processor_result!({data: "hello", foo: {bar: 1}}) my_string = Class.new(String) assert_raises(TypeError) { validate_processor_result!(nil) } assert_raises(TypeError) { validate_processor_result!({}) } assert_raises(TypeError) { validate_processor_result!({data: 123}) } assert_raises(TypeError) { validate_processor_result!({data: "hello", "foo" => 1}) } assert_raises(TypeError) { validate_processor_result!({data: my_string.new("hello")}) } assert_raises(TypeError) { validate_processor_result!({data: "hello", foo: Object.new}) } assert_raises(TypeError) { validate_processor_result!({data: "hello", foo: [Object.new]}) } assert_raises(TypeError) { validate_processor_result!({data: "hello", foo: Set.new([Object.new])}) } assert_raises(TypeError) { validate_processor_result!({data: "hello", foo: {bar: Object.new}}) } end end sprockets-3.7.2/test/test_rake_task.rb000066400000000000000000000052731331222022000200410ustar00rootroot00000000000000require 'sprockets_test' require 'rake/sprocketstask' require 'rake' class TestRakeTask < Sprockets::TestCase def setup @rake = Rake::Application.new Rake.application = @rake @env = Sprockets::Environment.new(".") do |env| env.append_path(fixture_path('default')) end @dir = File.join(Dir::tmpdir, 'sprockets/manifest') @manifest_custom_dir = Sprockets::Manifest.new(@env, @dir) @manifest_custom_path = Sprockets::Manifest.new(@env, @dir, File.join(@dir, 'manifest.json')) Rake::SprocketsTask.new do |t| t.environment = @env t.output = @dir t.assets = ['application.js'] t.log_level = :fatal end end def teardown Rake.application = nil # FileUtils.rm_rf(@dir) # wtf, dunno system "rm -rf #{@dir}" assert Dir["#{@dir}/*"].empty? end test "assets" do digest_path = @env['application.js'].digest_path assert !File.exist?("#{@dir}/#{digest_path}") @rake[:assets].invoke assert Dir["#{@dir}/.sprockets-manifest-*.json"].first assert File.exist?("#{@dir}/#{digest_path}") end test "clobber" do digest_path = @env['application.js'].digest_path @rake[:assets].invoke assert File.exist?("#{@dir}/#{digest_path}") @rake[:clobber_assets].invoke assert !File.exist?("#{@dir}/#{digest_path}") end test "custom manifest directory" do Rake::SprocketsTask.new do |t| t.environment = nil t.manifest = @manifest_custom_dir t.assets = ['application.js'] t.log_level = :fatal end digest_path = @env['application.js'].digest_path assert !File.exist?("#{@dir}/#{digest_path}") @rake[:assets].invoke assert Dir["#{@dir}/.sprockets-manifest-*.json"].first assert File.exist?("#{@dir}/#{digest_path}") end test "custom manifest path" do Rake::SprocketsTask.new do |t| t.environment = nil t.manifest = @manifest_custom_path t.assets = ['application.js'] t.log_level = :fatal end digest_path = @env['application.js'].digest_path assert !File.exist?("#{@dir}/#{digest_path}") @rake[:assets].invoke assert Dir["#{@dir}/manifest.json"].first assert File.exist?("#{@dir}/#{digest_path}") end test "lazy custom manifest" do Rake::SprocketsTask.new do |t| t.environment = nil t.manifest = lambda { @manifest_custom_dir } t.assets = ['application.js'] t.log_level = :fatal end digest_path = @env['application.js'].digest_path assert !File.exist?("#{@dir}/#{digest_path}") @rake[:assets].invoke assert Dir["#{@dir}/.sprockets-manifest-*.json"].first assert File.exist?("#{@dir}/#{digest_path}") end end sprockets-3.7.2/test/test_require.rb000066400000000000000000000006001331222022000175360ustar00rootroot00000000000000require 'minitest/autorun' class TestRequire < MiniTest::Test parallelize_me! ROOT = File.expand_path("../..", __FILE__) Dir["#{ROOT}/lib/**/*.rb"].each do |fn| next if File.basename(fn) == "version.rb" define_method "test_require_individual_library_files: #{fn}" do system "ruby", fn assert $?.success?, "Failed to load #{fn.inspect}" end end end sprockets-3.7.2/test/test_resolve.rb000066400000000000000000000321521331222022000175500ustar00rootroot00000000000000require 'sprockets_test' class TestResolve < Sprockets::TestCase def setup @env = Sprockets::Environment.new(".") end test "resolve in default environment" do @env.append_path(fixture_path_for_uri('default')) assert_equal "file://#{fixture_path_for_uri('default/gallery.js')}?type=application/javascript", resolve("gallery.js") assert_equal "file://#{fixture_path_for_uri('default/coffee/foo.coffee')}?type=application/javascript", resolve("coffee/foo.js") assert_equal "file://#{fixture_path_for_uri('default/jquery.tmpl.min.js')}?type=application/javascript", resolve("jquery.tmpl.min") assert_equal "file://#{fixture_path_for_uri('default/jquery.tmpl.min.js')}?type=application/javascript", resolve("jquery.tmpl.min.js") assert_equal "file://#{fixture_path_for_uri('default/manifest.js.yml')}?type=text/yaml", resolve('manifest.js.yml') refute resolve("null") end test "resolve accept type list before paths" do @env.append_path(fixture_path_for_uri('resolve/javascripts')) @env.append_path(fixture_path_for_uri('resolve/stylesheets')) foo_js_uri = "file://#{fixture_path_for_uri('resolve/javascripts/foo.js')}?type=application/javascript" foo_css_uri = "file://#{fixture_path_for_uri('resolve/stylesheets/foo.css')}?type=text/css" assert_equal foo_js_uri, resolve('foo', accept: 'application/javascript') assert_equal foo_css_uri, resolve('foo', accept: 'text/css') assert_equal foo_js_uri, resolve('foo', accept: 'application/javascript, text/css') assert_equal foo_js_uri, resolve('foo', accept: 'text/css, application/javascript') assert_equal foo_js_uri, resolve('foo', accept: 'application/javascript; q=0.8, text/css') assert_equal foo_js_uri, resolve('foo', accept: 'text/css; q=0.8, application/javascript') assert_equal foo_js_uri, resolve('foo', accept: '*/*; q=0.8, application/javascript') assert_equal foo_js_uri, resolve('foo', accept: '*/*; q=0.8, text/css') end test "resolve under load path" do @env.append_path(scripts = fixture_path_for_uri('resolve/javascripts')) @env.append_path(styles = fixture_path_for_uri('resolve/stylesheets')) foo_js_uri = "file://#{fixture_path_for_uri('resolve/javascripts/foo.js')}?type=application/javascript" foo_css_uri = "file://#{fixture_path_for_uri('resolve/stylesheets/foo.css')}?type=text/css" assert_equal foo_js_uri, resolve('foo.js', load_paths: [scripts]) assert_equal foo_css_uri, resolve('foo.css', load_paths: [styles]) refute resolve('foo.js', load_paths: [styles]) refute resolve('foo.css', load_paths: [scripts]) end test "resolve absolute" do @env.append_path(fixture_path_for_uri('default')) gallery_js_uri = "file://#{fixture_path_for_uri('default/gallery.js')}?type=application/javascript" assert_equal gallery_js_uri, resolve(fixture_path_for_uri('default/gallery.js')) assert_equal gallery_js_uri, resolve(fixture_path_for_uri('default/app/../gallery.js')) assert_equal gallery_js_uri, resolve(fixture_path_for_uri('default/gallery.js'), accept: 'application/javascript') assert_equal "file://#{fixture_path_for_uri('default/blank.gif')}?type=image/gif", resolve(fixture_path_for_uri('default/blank.gif')) assert_equal "file://#{fixture_path_for_uri('default/hello.txt')}?type=text/plain", resolve(fixture_path_for_uri('default/hello.txt')) assert_equal "file://#{fixture_path_for_uri('default/README.md')}", resolve(fixture_path_for_uri('default/README.md')) refute resolve(fixture_path_for_uri('asset/POW.png')) refute resolve(fixture_path_for_uri('default/missing')) refute resolve(fixture_path_for_uri('default/gallery.js'), accept: 'text/css') end test "resolve absolute identity" do @env.append_path(fixture_path_for_uri('default')) @env.stat_tree(fixture_path_for_uri('default')).each do |expected_path, stat| next unless stat.file? actual_path, _ = @env.parse_asset_uri(resolve(expected_path)) assert_equal expected_path, actual_path end end test "resolve relative" do @env.append_path(fixture_path_for_uri('default')) gallery_js_uri = "file://#{fixture_path_for_uri('default/gallery.js')}?type=application/javascript" assert_equal gallery_js_uri, resolve("./gallery.js", base_path: fixture_path_for_uri('default')) assert_equal gallery_js_uri, resolve("../gallery.js", base_path: fixture_path_for_uri('default/app')) assert_equal gallery_js_uri, resolve("./../gallery.js", base_path: fixture_path_for_uri('default/app')) assert_equal gallery_js_uri, resolve("../../gallery.js", base_path: fixture_path_for_uri('default/vendor/gems')) refute resolve("./missing.js", base_path: fixture_path_for_uri('default')) refute resolve("../asset/application.js", base_path: fixture_path_for_uri('default')) refute resolve("../default/gallery.js", base_path: fixture_path_for_uri('app')) end test "resolve extension before accept type" do @env.append_path(fixture_path_for_uri('resolve/javascripts')) @env.append_path(fixture_path_for_uri('resolve/stylesheets')) foo_js_uri = "file://#{fixture_path_for_uri('resolve/javascripts/foo.js')}?type=application/javascript" foo_css_uri = "file://#{fixture_path_for_uri('resolve/stylesheets/foo.css')}?type=text/css" assert_equal foo_js_uri, resolve('foo.js', accept: 'application/javascript') assert_equal foo_css_uri, resolve('foo.css', accept: 'text/css') refute resolve('foo.js', accept: 'text/css') refute resolve('foo.css', accept: 'application/javascript') assert_equal foo_js_uri, resolve('foo.js', accept: '*/*') assert_equal foo_css_uri, resolve('foo.css', accept: '*/*') assert_equal foo_js_uri, resolve('foo.js', accept: 'text/css, */*') assert_equal foo_css_uri, resolve('foo.css', accept: 'application/javascript, */*') end test "resolve accept type quality in paths" do @env.append_path(fixture_path_for_uri('resolve/javascripts')) bar_js_uri = "file://#{fixture_path_for_uri('resolve/javascripts/bar.js')}?type=application/javascript" bar_css_uri = "file://#{fixture_path_for_uri('resolve/javascripts/bar.css')}?type=text/css" assert_equal bar_js_uri, resolve('bar', accept: 'application/javascript') assert_equal bar_css_uri, resolve('bar', accept: 'text/css') assert_equal bar_js_uri, resolve('bar', accept: 'application/javascript, text/css') assert_equal bar_css_uri, resolve('bar', accept: 'text/css, application/javascript') assert_equal bar_css_uri, resolve('bar', accept: 'application/javascript; q=0.8, text/css') assert_equal bar_js_uri, resolve('bar', accept: 'text/css; q=0.8, application/javascript') assert_equal bar_js_uri, resolve('bar', accept: '*/*; q=0.8, application/javascript') assert_equal bar_css_uri, resolve('bar', accept: '*/*; q=0.8, text/css') end test "resolve with dependencies" do @env.append_path(fixture_path_for_uri('default')) uri, deps = @env.resolve("gallery.js", compat: false) assert_equal "file://#{fixture_path_for_uri('default/gallery.js')}?type=application/javascript", uri assert_includes deps, "file-digest://#{fixture_path_for_uri('default/gallery.js')}" assert_includes deps, "file-digest://#{fixture_path_for_uri('default')}" uri, deps = @env.resolve("coffee/foo.js", compat: false) assert_equal "file://#{fixture_path_for_uri('default/coffee/foo.coffee')}?type=application/javascript", uri assert_includes deps, "file-digest://#{fixture_path_for_uri('default/coffee/foo.coffee')}" assert_includes deps, "file-digest://#{fixture_path_for_uri('default/coffee')}" uri, deps = @env.resolve("manifest.js.yml", compat: false) assert_equal "file://#{fixture_path_for_uri('default/manifest.js.yml')}?type=text/yaml", uri assert_includes deps, "file-digest://#{fixture_path_for_uri('default/manifest.js.yml')}" assert_includes deps, "file-digest://#{fixture_path_for_uri('default')}" uri, deps = @env.resolve("gallery", accept: 'application/javascript', compat: false) assert_equal "file://#{fixture_path_for_uri('default/gallery.js')}?type=application/javascript", uri assert_includes deps, "file-digest://#{fixture_path_for_uri('default/gallery.js')}" assert_includes deps, "file-digest://#{fixture_path_for_uri('default')}" end test "resolve under load path with dependencies" do @env.append_path(scripts = fixture_path_for_uri('resolve/javascripts')) @env.append_path(styles = fixture_path_for_uri('resolve/stylesheets')) uri, deps = @env.resolve('foo.js', load_paths: [scripts], compat: false) assert_equal "file://#{fixture_path_for_uri('resolve/javascripts/foo.js')}?type=application/javascript", uri assert_includes deps, "file-digest://#{fixture_path_for_uri('resolve/javascripts/foo.js')}" assert_includes deps, "file-digest://#{fixture_path_for_uri('resolve/javascripts')}" uri, deps = @env.resolve('foo.css', load_paths: [styles], compat: false) assert_equal "file://#{fixture_path_for_uri('resolve/stylesheets/foo.css')}?type=text/css", uri assert_includes deps, "file-digest://#{fixture_path_for_uri('resolve/stylesheets/foo.css')}" assert_includes deps, "file-digest://#{fixture_path_for_uri('resolve/stylesheets')}" uri, deps = @env.resolve('foo.js', load_paths: [styles], compat: false) refute uri assert_includes deps, "file-digest://#{fixture_path_for_uri('resolve/stylesheets')}" uri, deps = @env.resolve('foo.css', load_paths: [scripts], compat: false) refute uri assert_includes deps, "file-digest://#{fixture_path_for_uri('resolve/javascripts')}" end test "resolve absolute with dependencies" do @env.append_path(fixture_path_for_uri('default')) uri, deps = @env.resolve(fixture_path_for_uri('default/gallery.js'), compat: false) assert_equal "file://#{fixture_path_for_uri('default/gallery.js')}?type=application/javascript", uri assert_includes deps, "file-digest://#{fixture_path_for_uri('default/gallery.js')}" end test "resolve uri identity with dependencies" do @env.append_path(fixture_path_for_uri('default')) uri1 = "file://#{fixture_path_for_uri('default/gallery.js')}?type=application/javascript" uri2, deps = @env.resolve(uri1, compat: false) assert_equal uri1, uri2 assert_includes deps, "file-digest://#{fixture_path_for_uri('default/gallery.js')}" end test "resolve with pipeline" do @env.append_path(fixture_path_for_uri('default')) assert_equal "file://#{fixture_path_for_uri('default/gallery.js')}?type=application/javascript&pipeline=source", resolve("gallery.js", pipeline: :source) assert_equal "file://#{fixture_path_for_uri('default/coffee/foo.coffee')}?type=application/javascript&pipeline=source", resolve("coffee/foo.js", pipeline: :source) assert_equal "file://#{fixture_path_for_uri('default/jquery.tmpl.min.js')}?type=application/javascript&pipeline=source", resolve("jquery.tmpl.min", pipeline: :source) assert_equal "file://#{fixture_path_for_uri('default/jquery.tmpl.min.js')}?type=application/javascript&pipeline=source", resolve("jquery.tmpl.min.js", pipeline: :source) assert_equal "file://#{fixture_path_for_uri('default/manifest.js.yml')}?type=text/yaml&pipeline=source", resolve('manifest.js.yml', pipeline: :source) refute resolve("null", pipeline: :source) assert_equal "file://#{fixture_path_for_uri('default/gallery.js')}?type=application/javascript&pipeline=source", resolve("gallery.source.js") assert_equal "file://#{fixture_path_for_uri('default/coffee/foo.coffee')}?type=application/javascript&pipeline=source", resolve("coffee/foo.source.js") assert_equal "file://#{fixture_path_for_uri('default/jquery.tmpl.min.js')}?type=application/javascript&pipeline=source", resolve("jquery.tmpl.min.source") assert_equal "file://#{fixture_path_for_uri('default/jquery.tmpl.min.js')}?type=application/javascript&pipeline=source", resolve("jquery.tmpl.min.source.js") assert_equal "file://#{fixture_path_for_uri('default/manifest.js.yml')}?type=text/yaml&pipeline=source", resolve('manifest.js.source.yml') end test "verify all logical paths" do Dir.entries(Sprockets::TestCase::FIXTURE_ROOT).each do |dir| unless %w( . ..).include?(dir) @env.append_path(fixture_path_for_uri(dir)) end end @env.logical_paths.each do |logical_path, filename| actual_path, _ = @env.parse_asset_uri(resolve(logical_path)) assert_equal filename, actual_path, "Expected #{logical_path.inspect} to resolve to #{filename}" end end test "legacy logical path iterator with matchers" do @env.append_path(fixture_path_for_uri('default')) assert_equal ["application.js", "gallery.css"], @env.each_logical_path("application.js", /gallery\.css/).to_a end test "adds paths to exceptions" do random_path = SecureRandom.hex @env.append_path(random_path) error = assert_raises(Sprockets::FileNotFound) do uri, _ = @env.resolve!("thisfiledoesnotexistandshouldraiseerrors", {}) uri end assert_match /#{ random_path }/, error.message end def resolve(path, options = {}) uri, _ = @env.resolve(path, options.merge(compat: false)) uri end end sprockets-3.7.2/test/test_sass.rb000066400000000000000000000220611331222022000170400ustar00rootroot00000000000000require 'sprockets_test' silence_warnings do require 'sass' end class TestBaseSass < Sprockets::TestCase CACHE_PATH = File.expand_path("../../.sass-cache", __FILE__) COMPASS_PATH = File.join(FIXTURE_ROOT, 'compass') def teardown refute ::Sass::Script::Functions.instance_methods.include?(:asset_path) FileUtils.rm_r(CACHE_PATH) if File.exist?(CACHE_PATH) assert !File.exist?(CACHE_PATH) end end class TestNoSassFunction < TestBaseSass module ::Sass::Script::Functions def javascript_path(path) ::Sass::Script::String.new("/js/#{path.value}", :string) end module Compass def stylesheet_path(path) ::Sass::Script::String.new("/css/#{path.value}", :string) end end include Compass end test "aren't included globally" do silence_warnings do assert ::Sass::Script::Functions.instance_methods.include?(:javascript_path) assert ::Sass::Script::Functions.instance_methods.include?(:stylesheet_path) filename = fixture_path('sass/paths.scss') assert data = File.read(filename) engine = ::Sass::Engine.new(data, { filename: filename, syntax: :scss }) assert ::Sass::Script::Functions.instance_methods.include?(:javascript_path) assert ::Sass::Script::Functions.instance_methods.include?(:stylesheet_path) assert_equal <<-EOS, engine.render div { url: url(asset-path("foo.svg")); url: url(image-path("foo.png")); url: url(video-path("foo.mov")); url: url(audio-path("foo.mp3")); url: url(font-path("foo.woff")); url: url("/js/foo.js"); url: url("/css/foo.css"); } EOS end end end class TestSprocketsSass < TestBaseSass def setup super @env = Sprockets::Environment.new(".") do |env| env.cache = {} env.append_path(fixture_path('.')) env.append_path(fixture_path('compass')) env.append_path(fixture_path('octicons')) end end def teardown assert !File.exist?(CACHE_PATH) end def render(path) path = fixture_path(path) silence_warnings do @env[path].to_s end end test "process variables" do assert_equal <<-EOS, render('sass/variables.sass') .content-navigation { border-color: #3bbfce; color: #2ca2af; } .border { padding: 8px; margin: 8px; border-color: #3bbfce; } EOS end test "process nesting" do assert_equal <<-EOS, render('sass/nesting.scss') table.hl { margin: 2em 0; } table.hl td.ln { text-align: right; } li { font-family: serif; font-weight: bold; font-size: 1.2em; } EOS end test "@import scss partial from scss" do assert_equal <<-EOS, render('sass/import_partial.scss') #navbar li { border-top-radius: 10px; -moz-border-radius-top: 10px; -webkit-border-top-radius: 10px; } #footer { border-top-radius: 5px; -moz-border-radius-top: 5px; -webkit-border-top-radius: 5px; } #sidebar { border-left-radius: 8px; -moz-border-radius-left: 8px; -webkit-border-left-radius: 8px; } EOS end test "@import scss partial from sass" do assert_equal <<-EOS, render('sass/import_partial.sass') #navbar li { border-top-radius: 10px; -moz-border-radius-top: 10px; -webkit-border-top-radius: 10px; } #footer { border-top-radius: 5px; -moz-border-radius-top: 5px; -webkit-border-top-radius: 5px; } #sidebar { border-left-radius: 8px; -moz-border-radius-left: 8px; -webkit-border-left-radius: 8px; } EOS end test "@import sass non-partial from scss" do assert_equal <<-EOS, render('sass/import_nonpartial.scss') .content-navigation { border-color: #3bbfce; color: #2ca2af; } .border { padding: 8px; margin: 8px; border-color: #3bbfce; } EOS end test "@import css file from load path" do assert_equal <<-EOS, render('sass/import_load_path.scss') EOS end test "process css file" do assert_equal <<-EOS, render('sass/reset.css') article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; } EOS end test "@import relative file" do assert_equal <<-EOS, render('sass/shared/relative.scss') #navbar li { border-top-radius: 10px; -moz-border-radius-top: 10px; -webkit-border-top-radius: 10px; } #footer { border-top-radius: 5px; -moz-border-radius-top: 5px; -webkit-border-top-radius: 5px; } #sidebar { border-left-radius: 8px; -moz-border-radius-left: 8px; -webkit-border-left-radius: 8px; } EOS end test "@import relative nested file" do assert_equal <<-EOS, render('sass/relative.scss') body { background: #666666; } EOS end test "modify file causes it to recompile" do filename = fixture_path('sass/test.scss') sandbox filename do File.open(filename, 'w') { |f| f.write "body { background: red; };" } assert_equal "body {\n background: red; }\n", render(filename) File.open(filename, 'w') { |f| f.write "body { background: blue; };" } mtime = Time.now + 1 File.utime(mtime, mtime, filename) assert_equal "body {\n background: blue; }\n", render(filename) end end test "modify partial causes it to recompile" do filename, partial = fixture_path('sass/test.scss'), fixture_path('sass/_partial.scss') sandbox filename, partial do File.open(filename, 'w') { |f| f.write "@import 'partial';" } File.open(partial, 'w') { |f| f.write "body { background: red; };" } assert_equal "body {\n background: red; }\n", render(filename) File.open(partial, 'w') { |f| f.write "body { background: blue; };" } mtime = Time.now + 1 File.utime(mtime, mtime, partial) assert_equal "body {\n background: blue; }\n", render(filename) end end test "reference @import'd variable" do assert_equal <<-EOS, render('sass/links.scss') a:link { color: "red"; } EOS end test "@import reference variable" do assert_equal <<-EOS, render('sass/main.scss') #header { color: "blue"; } EOS end test "raise sass error with line number" do begin ::Sass::Util.silence_sass_warnings do render('sass/error.sass') end flunk rescue Sass::SyntaxError => error assert error.message.include?("invalid") trace = error.backtrace[0] assert trace.include?("error.sass") assert trace.include?(":5") end end test "track sass dependencies metadata" do asset = nil silence_warnings do asset = @env.find_asset('sass/import_partial.css') end assert asset assert_equal [ fixture_path('sass/_rounded.scss'), fixture_path('sass/import_partial.sass') ], asset.metadata[:sass_dependencies].to_a.sort end end class TestSassCompressor < TestBaseSass test "compress css" do silence_warnings do uncompressed = "p {\n margin: 0;\n padding: 0;\n}\n" compressed = "p{margin:0;padding:0}\n" input = { data: uncompressed, cache: Sprockets::Cache.new } assert_equal compressed, Sprockets::SassCompressor.call(input) end end end class TestSassFunctions < TestSprocketsSass def setup super define_asset_path end def define_asset_path @env.context_class.class_eval do def asset_path(path, options = {}) link_asset(path) "/#{path}" end end end test "path functions" do assert_equal <<-EOS, render('sass/paths.scss') div { url: url("/foo.svg"); url: url("/foo.png"); url: url("/foo.mov"); url: url("/foo.mp3"); url: url("/foo.woff"); url: url("/foo.js"); url: url("/foo.css"); } EOS end test "url functions" do assert_equal <<-EOS, render('sass/urls.scss') div { url: url(/foo.svg); url: url(/foo.png); url: url(/foo.mov); url: url(/foo.mp3); url: url(/foo.woff); url: url(/foo.js); url: url(/foo.css); } EOS end test "url functions with query and hash parameters" do assert_equal <<-EOS, render('octicons/octicons.scss') @font-face { font-family: 'octicons'; src: url(/octicons.eot?#iefix) format("embedded-opentype"), url(/octicons.woff) format("woff"), url(/octicons.ttf) format("truetype"), url(/octicons.svg#octicons) format("svg"); font-weight: normal; font-style: normal; } EOS end test "path function generates links" do asset = silence_warnings do @env['sass/paths.scss'] end assert_equal [ "file://#{fixture_path('compass/foo.css')}?type=text/css&id=xxx", "file://#{fixture_path('compass/foo.js')}?type=application/javascript&id=xxx", "file://#{fixture_path('compass/foo.mov')}?id=xxx", "file://#{fixture_path('compass/foo.mp3')}?type=audio/mpeg&id=xxx", "file://#{fixture_path('compass/foo.svg')}?type=image/png&id=xxx", "file://#{fixture_path('compass/foo.svg')}?type=image/svg+xml&id=xxx", "file://#{fixture_path('compass/foo.woff')}?type=application/font-woff&id=xxx" ], asset.links.to_a.map { |uri| uri.sub(/id=\w+/, 'id=xxx') }.sort end test "data-url function" do assert_equal <<-EOS, render('sass/data_url.scss') div { url: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAMAAAAoyzS7AAAABlBMVEUFO2sAAADPfNHpAAAACklEQVQIW2NgAAAAAgABYkBPaAAAAABJRU5ErkJggg%3D%3D); } EOS end end sprockets-3.7.2/test/test_server.rb000066400000000000000000000311561331222022000174020ustar00rootroot00000000000000# -*- coding: utf-8 -*- require 'sprockets_test' require 'rack/builder' require 'rack/test' class TestServer < Sprockets::TestCase include Rack::Test::Methods def setup @env = Sprockets::Environment.new @env.append_path(fixture_path("server/app/javascripts")) @env.append_path(fixture_path("server/app/images")) @env.append_path(fixture_path("server/vendor/javascripts")) @env.append_path(fixture_path("server/vendor/stylesheets")) end def default_app env = @env Rack::Builder.new do map "/assets" do run env end map "/cached/javascripts" do run env.cached end end end def app @app ||= Rack::Lint.new(default_app) end test "serve single source file" do get "/assets/foo.js" assert_equal 200, last_response.status assert_equal "9", last_response.headers['Content-Length'] assert_equal "Accept-Encoding", last_response.headers['Vary'] assert_equal "var foo;\n", last_response.body end test "serve single source file body" do get "/assets/foo.js?body=1" assert_equal 200, last_response.status assert_equal "9", last_response.headers['Content-Length'] assert_equal "var foo;\n", last_response.body end test "serve single self file" do get "/assets/foo.self.js" assert_equal 200, last_response.status assert_equal "9", last_response.headers['Content-Length'] assert_equal "var foo;\n", last_response.body end test "serve single source file from cached environment" do get "/cached/javascripts/foo.js" assert_equal "var foo;\n", last_response.body end test "serve source with dependencies" do get "/assets/application.js" assert_equal "var foo;\n\n(function() {\n application.boot();\n})();\n", last_response.body end test "serve source file body that has dependencies" do get "/assets/application.js?body=true" assert_equal 200, last_response.status assert_equal "\n(function() {\n application.boot();\n})();\n", last_response.body assert_equal "43", last_response.headers['Content-Length'] end test "serve source file self that has dependencies" do get "/assets/application.self.js" assert_equal 200, last_response.status assert_equal "\n(function() {\n application.boot();\n})();\n", last_response.body assert_equal "43", last_response.headers['Content-Length'] end test "serve source with content type headers" do get "/assets/application.js" assert_equal "application/javascript", last_response.headers['Content-Type'] get "/assets/bootstrap.css" assert_equal "text/css; charset=utf-8", last_response.headers['Content-Type'] end test "serve source with etag headers" do digest = @env['application.js'].etag get "/assets/application.js" assert_equal "\"#{digest}\"", last_response.headers['ETag'] end test "not modified partial response when if-none-match etags match" do get "/assets/application.js" assert_equal 200, last_response.status etag, cache_control, expires, vary = last_response.headers.values_at( 'ETag', 'Cache-Control', 'Expires', 'Vary' ) get "/assets/application.js", {}, 'HTTP_IF_NONE_MATCH' => etag assert_equal 304, last_response.status # Allow 304 headers assert_equal cache_control, last_response.headers['Cache-Control'] assert_equal etag, last_response.headers['ETag'] assert_equal expires, last_response.headers['Expires'] assert_equal vary, last_response.headers['Vary'] # Disallowed 304 headers refute last_response.headers['Content-Type'] refute last_response.headers['Content-Length'] refute last_response.headers['Content-Encoding'] end test "response when if-none-match etags don't match" do get "/assets/application.js", {}, 'HTTP_IF_NONE_MATCH' => "nope" assert_equal 200, last_response.status assert_equal '"b452c9ae1d5c8d9246653e0d93bc83abce0ee09ef725c0f0a29a41269c217b83"', last_response.headers['ETag'] assert_equal '52', last_response.headers['Content-Length'] end test "not modified partial response with fingerprint and if-none-match etags match" do get "/assets/application.js" assert_equal 200, last_response.status etag = last_response.headers['ETag'] digest = etag[/"(.+)"/, 1] get "/assets/application-#{digest}.js", {}, 'HTTP_IF_NONE_MATCH' => etag assert_equal 304, last_response.status end test "ok response with fingerprint and if-nonematch etags don't match" do get "/assets/application.js" assert_equal 200, last_response.status etag = last_response.headers['ETag'] digest = etag[/"(.+)"/, 1] get "/assets/application-#{digest}.js", {}, 'HTTP_IF_NONE_MATCH' => "nope" assert_equal 200, last_response.status end test "not found with if-none-match" do get "/assets/missing.js", {}, 'HTTP_IF_NONE_MATCH' => '"000"' assert_equal 404, last_response.status end test "not found fingerprint with if-none-match" do get "/assets/missing-b452c9ae1d5c8d9246653e0d93bc83abce0ee09ef725c0f0a29a41269c217b83.js", {}, 'HTTP_IF_NONE_MATCH' => '"b452c9ae1d5c8d9246653e0d93bc83abce0ee09ef725c0f0a29a41269c217b83"' assert_equal 404, last_response.status end test "not found with response with incorrect fingerprint and matching if-none-match etags" do get "/assets/application.js" assert_equal 200, last_response.status etag = last_response.headers['ETag'] get "/assets/application-0000000000000000000000000000000000000000.js", {}, 'HTTP_IF_NONE_MATCH' => etag assert_equal 404, last_response.status end test "ok partial response when if-match etags match" do get "/assets/application.js" assert_equal 200, last_response.status etag = last_response.headers['ETag'] get "/assets/application.js", {}, 'HTTP_IF_MATCH' => etag assert_equal 200, last_response.status assert_equal '"b452c9ae1d5c8d9246653e0d93bc83abce0ee09ef725c0f0a29a41269c217b83"', last_response.headers['ETag'] assert_equal '52', last_response.headers['Content-Length'] end test "precondition failed with if-match is a mismatch" do get "/assets/application.js", {}, 'HTTP_IF_MATCH' => '"000"' assert_equal 412, last_response.status refute last_response.headers['ETag'] end test "not found with if-match" do get "/assets/missing.js", {}, 'HTTP_IF_MATCH' => '"000"' assert_equal 404, last_response.status end test "if sources didnt change the server shouldnt rebundle" do get "/assets/application.js" asset_before = @env["application.js"] assert asset_before get "/assets/application.js" asset_after = @env["application.js"] assert asset_after assert asset_before.eql?(asset_after) end test "fingerprint digest sets expiration to the future" do get "/assets/application.js" digest = last_response.headers['ETag'][/"(.+)"/, 1] get "/assets/application-#{digest}.js" assert_equal 200, last_response.status assert_match %r{max-age}, last_response.headers['Cache-Control'] end test "fingerprint digest of file body" do get "/assets/application.js?body=1" digest = last_response.headers['ETag'][/"(.+)"/, 1] get "/assets/application-#{digest}.js?body=1" assert_equal 200, last_response.status assert_equal "\n(function() {\n application.boot();\n})();\n", last_response.body assert_equal "43", last_response.headers['Content-Length'] assert_match %r{max-age}, last_response.headers['Cache-Control'] end test "fingerprint digest of file self" do get "/assets/application.self.js" digest = last_response.headers['ETag'][/"(.+)"/, 1] get "/assets/application.self-#{digest}.js" assert_equal 200, last_response.status assert_equal "\n(function() {\n application.boot();\n})();\n", last_response.body assert_equal "43", last_response.headers['Content-Length'] assert_match %r{max-age}, last_response.headers['Cache-Control'] end test "using non-body fingerprint for body only request" do get "/assets/application.js" digest = last_response.headers['ETag'][/"(.+)"/, 1] get "/assets/application-#{digest}.js?body=1" assert_equal 200, last_response.status assert_equal "\n(function() {\n application.boot();\n})();\n", last_response.body assert_equal "43", last_response.headers['Content-Length'] assert_match %r{max-age}, last_response.headers['Cache-Control'] end test "using non-body fingerprint for self only request" do get "/assets/application.js" digest = last_response.headers['ETag'][/"(.+)"/, 1] get "/assets/application.self-#{digest}.js" assert_equal 200, last_response.status assert_equal "\n(function() {\n application.boot();\n})();\n", last_response.body assert_equal "43", last_response.headers['Content-Length'] assert_match %r{max-age}, last_response.headers['Cache-Control'] end test "bad fingerprint digest returns a 404" do get "/assets/application-0000000000000000000000000000000000000000.js" assert_equal 404, last_response.status head "/assets/application-0000000000000000000000000000000000000000.js" assert_equal 404, last_response.status assert_equal "0", last_response.headers['Content-Length'] assert_equal "", last_response.body end test "missing source" do get "/assets/none.js" assert_equal 404, last_response.status assert_equal "pass", last_response.headers['X-Cascade'] end test "re-throw JS exceptions in the browser" do get "/assets/missing_require.js" assert_equal 200, last_response.status assert_match /Sprockets::FileNotFound: couldn't find file 'notfound' with type 'application\/javascript'/, last_response.body assert_match /(in #{fixture_path("server/vendor/javascripts/missing_require.js")}:1)/, last_response.body end test "display CSS exceptions in the browser" do get "/assets/missing_require.css" assert_equal 200, last_response.status assert_match %r{content: ".*?Sprockets::FileNotFound}, last_response.body end test "serve encoded utf-8 filename" do get "/assets/%E6%97%A5%E6%9C%AC%E8%AA%9E.js" assert_equal "var japanese = \"日本語\";\n", last_response.body end test "illegal require outside load path" do get "/assets//etc/passwd" assert_equal 403, last_response.status get "/assets/%2fetc/passwd" assert_equal 403, last_response.status get "/assets//%2fetc/passwd" assert_equal 403, last_response.status get "/assets/%2f/etc/passwd" assert_equal 403, last_response.status get "/assets/../etc/passwd" assert_equal 403, last_response.status get "/assets/%2e%2e/etc/passwd" assert_equal 403, last_response.status get "/assets/.-0000000./etc/passwd" assert_equal 403, last_response.status head "/assets/.-0000000./etc/passwd" assert_equal 403, last_response.status assert_equal "0", last_response.headers['Content-Length'] assert_equal "", last_response.body end test "illegal access of a file asset" do absolute_path = fixture_path("server/app/javascripts") get "assets/file:%2f%2f//#{absolute_path}/foo.js" assert_equal 403, last_response.status end test "add new source to tree" do filename = fixture_path("server/app/javascripts/baz.js") sandbox filename do get "/assets/tree.js" assert_equal "var foo;\n\n(function() {\n application.boot();\n})();\nvar bar;\nvar japanese = \"日本語\";\n", last_response.body File.open(filename, "w") do |f| f.write "var baz;\n" end path = fixture_path "server/app/javascripts" mtime = Time.now + 60 File.utime(mtime, mtime, path) get "/assets/tree.js" assert_equal "var foo;\n\n(function() {\n application.boot();\n})();\nvar bar;\nvar baz;\nvar japanese = \"日本語\";\n", last_response.body end end test "serving static assets" do get "/assets/logo.png" assert_equal 200, last_response.status assert_equal "image/png", last_response.headers['Content-Type'] refute last_response.headers['Content-Encoding'] assert_equal File.binread(fixture_path("server/app/images/logo.png")), last_response.body end test "disallow non-get methods" do get "/assets/foo.js" assert_equal 200, last_response.status head "/assets/foo.js" assert_equal 200, last_response.status assert_equal "application/javascript", last_response.headers['Content-Type'] assert_equal "0", last_response.headers['Content-Length'] assert_equal "", last_response.body post "/assets/foo.js" assert_equal 405, last_response.status put "/assets/foo.js" assert_equal 405, last_response.status delete "/assets/foo.js" assert_equal 405, last_response.status end end sprockets-3.7.2/test/test_source_maps.rb000066400000000000000000000066771331222022000204260ustar00rootroot00000000000000require 'sprockets_test' require 'sprockets/bundle' silence_warnings do require 'sass' end class TestSourceMaps < Sprockets::TestCase def setup @env = Sprockets::Environment.new @env.append_path fixture_path('source-maps') end test "compile coffeescript source map" do assert asset = @env.find_asset("coffee/main.js") assert_equal fixture_path('source-maps/coffee/main.coffee'), asset.filename assert_equal "application/javascript", asset.content_type assert_match "(function() {", asset.source assert_match "Math.sqrt", asset.source assert asset = @env.find_asset("coffee/main.js.map") assert_equal fixture_path('source-maps/coffee/main.coffee'), asset.filename assert_equal "coffee/main.js.map", asset.logical_path assert_equal "application/js-sourcemap+json", asset.content_type # Dummy data, make it real in 4.x assert map = JSON.parse(asset.source) assert_equal({ "version" => 3, "file" => "coffee/main.js", "mappings" => ";123" }, map) end test "use precompiled coffeescript source map" do assert asset = @env.find_asset("coffee/precompiled/main.js") assert_equal fixture_path('source-maps/coffee/precompiled/main.coffee'), asset.filename assert_equal "application/javascript", asset.content_type assert_match "(function() {", asset.source assert_match "Math.sqrt", asset.source assert asset = @env.find_asset("coffee/precompiled/main.js.map") assert_equal fixture_path('source-maps/coffee/precompiled/main.js.map'), asset.filename assert_equal "coffee/precompiled/main.js.map", asset.logical_path assert_equal "application/js-sourcemap+json", asset.content_type assert map = JSON.parse(asset.source) assert_equal 3, map['version'] assert_equal "main.js", map['file'] assert_equal 779, map['mappings'].size end test "compile scss source map" do asset = silence_warnings do @env.find_asset("sass/main.css") end assert asset assert_equal fixture_path('source-maps/sass/main.scss'), asset.filename assert_equal "text/css", asset.content_type assert_match "nav a {", asset.source asset = silence_warnings do @env.find_asset("sass/main.css.map") end assert asset assert_equal fixture_path('source-maps/sass/main.scss'), asset.filename assert_equal "sass/main.css.map", asset.logical_path assert_equal "application/css-sourcemap+json", asset.content_type # Dummy data, make it real in 4.x assert map = JSON.parse(asset.source) assert_equal({ "version" => 3, "file" => "sass/main.css", "mappings" => ";123" }, map) end test "use precompiled scss source map" do asset = silence_warnings do @env.find_asset("sass/precompiled/main.css") end assert asset assert_equal fixture_path('source-maps/sass/precompiled/main.css'), asset.filename assert_equal "text/css", asset.content_type assert_match "nav a {", asset.source asset = silence_warnings do @env.find_asset("sass/precompiled/main.css.map") end assert asset assert_equal fixture_path('source-maps/sass/precompiled/main.css.map'), asset.filename assert_equal "sass/precompiled/main.css.map", asset.logical_path assert_equal "application/css-sourcemap+json", asset.content_type assert map = JSON.parse(asset.source) assert_equal 3, map['version'] assert_equal "main.css", map['file'] assert_equal 172, map['mappings'].size end end sprockets-3.7.2/test/test_sprocketize.rb000066400000000000000000000056611331222022000204400ustar00rootroot00000000000000require 'sprockets_test' require 'shellwords' require 'tmpdir' class TestSprockets < Sprockets::TestCase parallelize_me! def setup super @env = Sprockets::Environment.new(".") do |env| env.append_path(fixture_path('default')) end @dir = Dir.mktmpdir("sprockets") end def teardown FileUtils.rm_rf @dir super end test "show version for -v flag" do output = sprockets "-v" assert_equal "#{Sprockets::VERSION}\n", output end test "show help for -h flag" do output = sprockets "-h" assert_match "Usage: sprockets", output end test "show help for no flags or inputs" do output = sprockets assert_match "Usage: sprockets", output end test "error if load path is missing" do sprockets fixture_path("default/gallery.js") assert_equal 1, $?.exitstatus end test "compile simple file" do output = sprockets "-I", fixture_path("default"), fixture_path("default/gallery.js") assert_equal "var Gallery = {};\n", output end test "show error if multiple files are given" do sprockets fixture_path("default/gallery.js"), fixture_path("default/application.js") assert_equal 1, $?.exitstatus end test "compile file with dependencies" do output = sprockets "-I", fixture_path("asset"), fixture_path("asset/application.js") assert_equal "var Project = {\n find: function(id) {\n }\n};\nvar Users = {\n find: function(id) {\n }\n};\n\n\n\ndocument.on('dom:loaded', function() {\n $('search').focus();\n});\n", output end test "compile asset to output directory" do digest_path = @env['gallery.js'].digest_path output = sprockets "-I", fixture_path("default"), "-o", @dir, fixture_path("default/gallery.js") assert_equal "", output assert Dir["#{@dir}/.sprockets-manifest-*.json"].first assert File.exist?("#{@dir}/#{digest_path}") end test "compile multiple assets to output directory" do digest_path1, digest_path2 = @env['gallery.js'].digest_path, @env['gallery.css'].digest_path output = sprockets "-I", fixture_path("default"), "-o", @dir, fixture_path("default/gallery.js"), fixture_path("default/gallery.css.erb") assert_equal "", output assert Dir["#{@dir}/.sprockets-manifest-*.json"].first assert File.exist?("#{@dir}/#{digest_path1}") assert File.exist?("#{@dir}/#{digest_path2}") end test "minify js with uglify" do output = sprockets "-I", fixture_path("default"), "--js-compressor", "uglify", fixture_path("default/gallery.js") assert_equal "var Gallery={};\n", output end test "compress css with sass" do output = sprockets "-I", fixture_path("default"), "--css-compressor", "sass", fixture_path("default/gallery.css.erb") assert_equal ".gallery{color:red}\n", output end def sprockets(*args) script = File.expand_path("../../bin/sprockets", __FILE__) lib = File.expand_path("../../lib", __FILE__) `ruby -I#{lib} #{script} #{Shellwords.join(args)} 2>&1` end end sprockets-3.7.2/test/test_transformers.rb000066400000000000000000000157771331222022000206340ustar00rootroot00000000000000require 'sprockets_test' class TestTransformers < Sprockets::TestCase def setup @env = Sprockets::Environment.new(".") end test "resolve transform type for svg" do assert_equal 'image/svg+xml', @env.resolve_transform_type('image/svg+xml', 'image/svg+xml') assert_equal 'image/svg+xml', @env.resolve_transform_type('image/svg+xml', '*/*') assert_equal 'image/svg+xml', @env.resolve_transform_type('image/svg+xml', nil) assert_equal 'image/svg+xml', @env.resolve_transform_type('image/svg+xml', 'image/*') assert_equal 'image/png', @env.resolve_transform_type('image/svg+xml', 'image/png') assert_equal 'image/svg+xml', @env.resolve_transform_type('image/svg+xml', 'image/svg+xml, image/png') assert_equal 'image/png', @env.resolve_transform_type('image/svg+xml', 'image/png, image/svg+xml') assert_equal 'image/png', @env.resolve_transform_type('image/svg+xml', 'image/svg+xml; q=0.8, image/png') assert_equal 'image/svg+xml', @env.resolve_transform_type('image/svg+xml', 'text/yaml, image/svg+xml, image/png') assert_equal 'image/png', @env.resolve_transform_type('image/svg+xml', 'text/yaml, image/png, image/svg+xml') refute @env.resolve_transform_type('image/svg+xml', 'text/yaml') refute @env.resolve_transform_type(nil, 'image/svg+xml') refute @env.resolve_transform_type(nil, nil) end test "resolve multistep transform type for svg" do noop = proc {} assert_equal 'test/svg', @env.resolve_transform_type('test/svg', 'test/svg') assert_equal 'test/png', @env.resolve_transform_type('test/png', 'test/png') assert_equal 'test/jpg', @env.resolve_transform_type('test/jpg', 'test/jpg') assert_equal 'test/gif', @env.resolve_transform_type('test/gif', 'test/gif') assert_equal 'test/tif', @env.resolve_transform_type('test/tif', 'test/tif') assert_equal 'test/jif', @env.resolve_transform_type('test/jif', 'test/jif') refute @env.resolve_transform_type('test/svg', 'test/png') refute @env.resolve_transform_type('test/svg', 'test/jpg') refute @env.resolve_transform_type('test/svg', 'test/gif') refute @env.resolve_transform_type('test/svg', 'test/tif') refute @env.resolve_transform_type('test/svg', 'test/jif') @env.register_transformer 'test/svg', 'test/png', noop assert_equal 'test/png', @env.resolve_transform_type('test/svg', 'test/png') refute @env.resolve_transform_type('test/svg', 'test/jpg') refute @env.resolve_transform_type('test/svg', 'test/gif') refute @env.resolve_transform_type('test/svg', 'test/tif') refute @env.resolve_transform_type('test/svg', 'test/jif') @env.register_transformer 'test/svg', 'test/jpg', noop assert_equal 'test/png', @env.resolve_transform_type('test/svg', 'test/png') assert_equal 'test/jpg', @env.resolve_transform_type('test/svg', 'test/jpg') refute @env.resolve_transform_type('test/svg', 'test/gif') refute @env.resolve_transform_type('test/svg', 'test/tif') refute @env.resolve_transform_type('test/svg', 'test/jif') refute @env.resolve_transform_type('test/png', 'test/jpg') @env.register_transformer 'test/jpg', 'test/gif', noop assert_equal 'test/png', @env.resolve_transform_type('test/svg', 'test/png') assert_equal 'test/jpg', @env.resolve_transform_type('test/svg', 'test/jpg') assert_equal 'test/gif', @env.resolve_transform_type('test/jpg', 'test/gif') assert_equal 'test/gif', @env.resolve_transform_type('test/svg', 'test/gif') refute @env.resolve_transform_type('test/svg', 'test/tif') refute @env.resolve_transform_type('test/svg', 'test/jif') refute @env.resolve_transform_type('test/png', 'test/jpg') refute @env.resolve_transform_type('test/png', 'test/gif') @env.register_transformer 'test/gif', 'test/tif', noop assert_equal 'test/png', @env.resolve_transform_type('test/svg', 'test/png') assert_equal 'test/jpg', @env.resolve_transform_type('test/svg', 'test/jpg') assert_equal 'test/gif', @env.resolve_transform_type('test/jpg', 'test/gif') assert_equal 'test/gif', @env.resolve_transform_type('test/svg', 'test/gif') assert_equal 'test/tif', @env.resolve_transform_type('test/gif', 'test/tif') assert_equal 'test/tif', @env.resolve_transform_type('test/jpg', 'test/tif') assert_equal 'test/tif', @env.resolve_transform_type('test/svg', 'test/tif') refute @env.resolve_transform_type('test/svg', 'test/jif') refute @env.resolve_transform_type('test/png', 'test/jpg') refute @env.resolve_transform_type('test/png', 'test/gif') refute @env.resolve_transform_type('test/png', 'test/tif') @env.register_transformer 'test/tif', 'test/jif', noop assert_equal 'test/png', @env.resolve_transform_type('test/svg', 'test/png') assert_equal 'test/jpg', @env.resolve_transform_type('test/svg', 'test/jpg') assert_equal 'test/gif', @env.resolve_transform_type('test/jpg', 'test/gif') assert_equal 'test/gif', @env.resolve_transform_type('test/svg', 'test/gif') assert_equal 'test/tif', @env.resolve_transform_type('test/gif', 'test/tif') assert_equal 'test/tif', @env.resolve_transform_type('test/jpg', 'test/tif') assert_equal 'test/tif', @env.resolve_transform_type('test/svg', 'test/tif') assert_equal 'test/jif', @env.resolve_transform_type('test/jpg', 'test/jif') assert_equal 'test/jif', @env.resolve_transform_type('test/gif', 'test/jif') assert_equal 'test/jif', @env.resolve_transform_type('test/tif', 'test/jif') assert_equal 'test/jif', @env.resolve_transform_type('test/svg', 'test/jif') refute @env.resolve_transform_type('test/png', 'test/jpg') refute @env.resolve_transform_type('test/png', 'test/gif') refute @env.resolve_transform_type('test/png', 'test/tif') refute @env.resolve_transform_type('test/png', 'test/jif') end test "expand transform accepts" do assert_equal [['text/plain', 1.0]], @env.expand_transform_accepts(@env.parse_q_values('text/plain')) assert_equal [['application/javascript', 1.0]], @env.expand_transform_accepts(@env.parse_q_values('application/javascript')) assert_equal [['image/png', 1.0], ['image/svg+xml', 0.8]], @env.expand_transform_accepts(@env.parse_q_values('image/png')) end test "compose transformers" do transformers = { "image/svg" => { "image/png" => proc { |input| { data: input[:data] + ",svg->png" } } }, "image/png" => { "image/gif" => proc { |input| { data: input[:data] + ",png->gif" } } } } processor = @env.compose_transformers(transformers, ["image/svg", "image/png"]) assert_equal({data: ",svg->png"}, processor.call({data: ""})) processor = @env.compose_transformers(transformers, ["image/svg", "image/png", "image/gif"]) assert_equal({data: ",svg->png,png->gif"}, processor.call({data: ""})) assert_raises(Sprockets::ArgumentError) do @env.compose_transformers(transformers, ["image/svg"]) end assert_raises(Sprockets::ArgumentError) do @env.compose_transformers(transformers, ["image/svg", "image/jif"]) end end end sprockets-3.7.2/test/test_uglifier_compressor.rb000066400000000000000000000010351331222022000221470ustar00rootroot00000000000000require 'minitest/autorun' require 'sprockets/cache' require 'sprockets/uglifier_compressor' class TestUglifierCompressor < MiniTest::Test def test_compress_javascript input = { content_type: 'application/javascript', data: "/* Copyright Rails */\nfunction foo() {\n return true;\n}", cache: Sprockets::Cache.new } output = "function foo(){return!0}" assert_equal output, Sprockets::UglifierCompressor.call(input) end def test_cache_key assert Sprockets::UglifierCompressor.cache_key end end sprockets-3.7.2/test/test_uri_tar.rb000066400000000000000000000056171331222022000175440ustar00rootroot00000000000000require 'sprockets_test' class TestURITar < Sprockets::TestCase def setup @fake_env = Class.new do include Sprockets::PathUtils attr_accessor :root end.new end test "works with nix" do skip "Only runs on nix" if File::ALT_SEPARATOR uri = "/Sites/sprockets/test/fixtures/paths/application.css?type=text/css" @fake_env.root = "/Different/path" tar = Sprockets::URITar.new(uri, @fake_env) assert_equal uri, tar.expand assert_equal uri, tar.compress assert_equal uri, tar.compressed_path uri = "file:///Sites/sprockets/test/fixtures/paths/application.css?type=text/css" @fake_env.root = "/Sites/sprockets" tar = Sprockets::URITar.new(uri, @fake_env) assert_equal uri, tar.expand assert_equal Sprockets::URITar.new(tar.compress, @fake_env).expand, uri assert_equal "test/fixtures/paths/application.css?type=text/css", tar.compressed_path assert_equal "file://test/fixtures/paths/application.css?type=text/css", tar.compress assert_equal Sprockets::URITar.new(tar.compress, @fake_env).compress, tar.compress assert_equal Sprockets::URITar.new(tar.expand, @fake_env).compress, tar.compress uri = "/Sites/sprockets/test/fixtures/paths/application.css?type=text/css" @fake_env.root = "/Sites/sprockets" tar = Sprockets::URITar.new(uri, @fake_env) assert_equal uri, tar.expand assert_equal "test/fixtures/paths/application.css?type=text/css", tar.compressed_path assert_equal "test/fixtures/paths/application.css?type=text/css", tar.compress end test "works with windows" do skip "Only runs on windows" unless File::ALT_SEPARATOR uri = "C:/Sites/sprockets/test/fixtures/paths/application.css?type=text/css" @fake_env.root = "C:/Different/path" tar = Sprockets::URITar.new(uri, @fake_env) assert_equal uri, tar.expand assert_equal uri, tar.compress assert_equal uri, tar.compressed_path uri = "file:///C:/Sites/sprockets/test/fixtures/paths/application.css?type=text/css" @fake_env.root = "C:/Sites/sprockets" tar = Sprockets::URITar.new(uri, @fake_env) assert_equal uri, tar.expand assert_equal Sprockets::URITar.new(tar.compress, @fake_env).expand, uri assert_equal "test/fixtures/paths/application.css?type=text/css", tar.compressed_path assert_equal "file://test/fixtures/paths/application.css?type=text/css", tar.compress assert_equal Sprockets::URITar.new(tar.compress, @fake_env).compress, tar.compress assert_equal Sprockets::URITar.new(tar.expand, @fake_env).compress, tar.compress uri = "C:/Sites/sprockets/test/fixtures/paths/application.css?type=text/css" @fake_env.root = "C:/Sites/sprockets" tar = Sprockets::URITar.new(uri, @fake_env) assert_equal uri, tar.expand assert_equal "test/fixtures/paths/application.css?type=text/css", tar.compressed_path assert_equal "test/fixtures/paths/application.css?type=text/css", tar.compress end end sprockets-3.7.2/test/test_uri_utils.rb000066400000000000000000000212641331222022000201120ustar00rootroot00000000000000require 'minitest/autorun' require 'sprockets/uri_utils' class TestURIUtils < MiniTest::Test include Sprockets::URIUtils DOSISH = File::ALT_SEPARATOR != nil DOSISH_DRIVE_LETTER = File.dirname("A:") == "A:." DOSISH_UNC = File.dirname("//") == "//" def test_split_uri parts = split_uri("https://josh:Passw0rd1@github.com:433/sstephenson/sprockets/issues?author=josh#issue1") assert_equal ["https", "josh:Passw0rd1", "github.com", "433", nil, "/sstephenson/sprockets/issues", nil, "author=josh", "issue1"], parts end def test_join_uri assert_equal "https://josh:Passw0rd1@github.com:433/sstephenson/sprockets/issues?author=josh#issue1", join_uri("https", "josh:Passw0rd1", "github.com", "433", nil, "/sstephenson/sprockets/issues", nil, "author=josh", "issue1") end def test_inverse_uri_functions [ "http://github.com", "http://github.com:8080", "https://github.com/", "https://github.com/home", "https://github.com#logo", "https://josh:Passw0rd1@github.com:433/sstephenson/sprockets/issues?author=josh#issue1", "urn:md5:68b329da9893e34099c7d8ad5cb9c940", ].each do |uri| assert parts = split_uri(uri) assert_equal uri, join_uri(*parts) end end def test_split_file_uri parts = split_file_uri("file://localhost/etc/fstab") assert_equal ['file', 'localhost', '/etc/fstab', nil], parts parts = split_file_uri("file:///etc/fstab") assert_equal ['file', nil, '/etc/fstab', nil], parts parts = split_file_uri("file:///usr/local/bin/ruby%20on%20rails") assert_equal ['file', nil, '/usr/local/bin/ruby on rails', nil], parts parts = split_file_uri("file:///usr/local/var/github/app/assets/javascripts/application.js") assert_equal ['file', nil, '/usr/local/var/github/app/assets/javascripts/application.js', nil], parts parts = split_file_uri("file:///C:/Documents%20and%20Settings/davris/FileSchemeURIs.doc") assert_equal ['file', nil, 'C:/Documents and Settings/davris/FileSchemeURIs.doc', nil], parts parts = split_file_uri("file:///D:/Program%20Files/Viewer/startup.htm") assert_equal ['file', nil, 'D:/Program Files/Viewer/startup.htm', nil], parts parts = split_file_uri("file:///C:/Program%20Files/Music/Web%20Sys/main.html?REQUEST=RADIO") assert_equal ['file', nil, 'C:/Program Files/Music/Web Sys/main.html', 'REQUEST=RADIO'], parts end def test_join_uri_path assert_equal "file://localhost/etc/fstab", join_file_uri('file', 'localhost', '/etc/fstab', nil) assert_equal "file:///etc/fstab", join_file_uri('file', nil, '/etc/fstab', nil) assert_equal "file:///usr/local/bin/ruby%20on%20rails", join_file_uri('file', nil, '/usr/local/bin/ruby on rails', nil) end def test_inverse_file_uri_functions [ "file://localhost/etc/fstab", "file:///etc/fstab", "file:///usr/local/bin/ruby%20on%20rails", "file:///usr/local/var/github/app/assets/javascripts/application.js", "file:///usr/local/var/github/app/assets/javascripts/application.coffee?type=application/javascript", "file:///C:/Documents%20and%20Settings/davris/FileSchemeURIs.doc", "file:///D:/Program%20Files/Viewer/startup.htm" ].each do |uri| assert parts = split_file_uri(uri) assert_equal uri, join_file_uri(*parts) end end def test_validate assert valid_asset_uri?("file:///usr/local/var/github/app/assets/javascripts/application.js") assert valid_asset_uri?("file:///C:/Users/IEUser/Documents/github/app/assets/javascripts/application.js") refute valid_asset_uri?("http:///usr/local/var/github/app/assets/javascripts/application.js") refute valid_asset_uri?("/usr/local/var/github/app/assets/javascripts/application.js") end def test_validate_with_invalid_uri_error refute valid_asset_uri?("file:///[]") end def test_parse_file_paths assert_equal ["/usr/local/var/github/app/assets/javascripts/application.js", {}], parse_asset_uri("file:///usr/local/var/github/app/assets/javascripts/application.js") assert_equal ["/usr/local/var/github/app/assets/javascripts/foo bar.js", {}], parse_asset_uri("file:///usr/local/var/github/app/assets/javascripts/foo%20bar.js") assert_equal ["C:/Users/IEUser/Documents/github/app/assets/javascripts/application.js", {}], parse_asset_uri("file:///C:/Users/IEUser/Documents/github/app/assets/javascripts/application.js") end def test_parse_query_params assert_equal ["/usr/local/var/github/app/assets/javascripts/application.coffee", {type: 'application/javascript'}], parse_asset_uri("file:///usr/local/var/github/app/assets/javascripts/application.coffee?type=application/javascript") assert_equal ["/usr/local/var/github/app/assets/stylesheets/users.css", {type: 'text/css', flag: true}], parse_asset_uri("file:///usr/local/var/github/app/assets/stylesheets/users.css?type=text/css&flag") assert_equal ["/usr/local/var/github/app/assets/views/users.html", {type: 'text/html; charset=utf-8'}], parse_asset_uri("file:///usr/local/var/github/app/assets/views/users.html?type=text/html;%20charset=utf-8") end def test_asset_uri_raise_erorr_when_invalid_uri_scheme assert_raises URI::InvalidURIError do parse_asset_uri("http:///usr/local/var/github/app/assets/javascripts/application.js") end end def test_build_file_path assert_equal "file:///usr/local/var/github/app/assets/javascripts/application.js", build_asset_uri("/usr/local/var/github/app/assets/javascripts/application.js") assert_equal "file:///usr/local/var/github/app/assets/javascripts/foo%20bar.js", build_asset_uri("/usr/local/var/github/app/assets/javascripts/foo bar.js") assert_equal "file:///C:/Users/IEUser/Documents/github/app/assets/javascripts/application.js", build_asset_uri("C:/Users/IEUser/Documents/github/app/assets/javascripts/application.js") end def test_build_query_params assert_equal "file:///usr/local/var/github/app/assets/javascripts/application.coffee?type=application/javascript", build_asset_uri("/usr/local/var/github/app/assets/javascripts/application.coffee", type: 'application/javascript') assert_equal "file:///usr/local/var/github/app/assets/images/logo.svg?type=image/svg+xml", build_asset_uri("/usr/local/var/github/app/assets/images/logo.svg", type: 'image/svg+xml') assert_equal "file:///usr/local/var/github/app/assets/stylesheets/users.css?type=text/css&flag", build_asset_uri("/usr/local/var/github/app/assets/stylesheets/users.css", type: 'text/css', flag: true) assert_equal "file:///usr/local/var/github/app/assets/stylesheets/users.css?type=text/css", build_asset_uri("/usr/local/var/github/app/assets/stylesheets/users.css", type: 'text/css', flag: false) assert_equal "file:///usr/local/var/github/app/assets/stylesheets/users.css?type=css", build_asset_uri("/usr/local/var/github/app/assets/stylesheets/users.css", type: :css) assert_equal "file:///usr/local/var/github/app/assets/views/users.html?type=text/html;%20charset=utf-8", build_asset_uri("/usr/local/var/github/app/assets/views/users.html", type: 'text/html; charset=utf-8') end def test_raise_error_when_invalid_param_value assert_raises TypeError do build_asset_uri("/usr/local/var/github/app/assets/images/logo.png", encodings: ['gzip', 'deflate']) end end def test_parse_file_digest_uri assert_equal "/usr/local/var/github/app/assets/javascripts/application.js", parse_file_digest_uri("file-digest:///usr/local/var/github/app/assets/javascripts/application.js") assert_equal "/usr/local/var/github/app/assets/javascripts/foo bar.js", parse_file_digest_uri("file-digest:///usr/local/var/github/app/assets/javascripts/foo%20bar.js") assert_equal "C:/Users/IEUser/Documents/github/app/assets/javascripts/application.js", parse_file_digest_uri("file-digest:///C:/Users/IEUser/Documents/github/app/assets/javascripts/application.js") end def test_build_file_digest_uri assert_equal "file-digest:///usr/local/var/github/app/assets/javascripts/application.js", build_file_digest_uri("/usr/local/var/github/app/assets/javascripts/application.js") assert_equal "file-digest:///usr/local/var/github/app/assets/javascripts/foo%20bar.js", build_file_digest_uri("/usr/local/var/github/app/assets/javascripts/foo bar.js") assert_equal "file-digest:///C:/Users/IEUser/Documents/github/app/assets/javascripts/application.js", build_file_digest_uri("C:/Users/IEUser/Documents/github/app/assets/javascripts/application.js") end def test_file_digest_raise_erorr_when_invalid_uri_scheme assert_raises URI::InvalidURIError do parse_file_digest_uri("http:///usr/local/var/github/app/assets/javascripts/application.js") end end end sprockets-3.7.2/test/test_utils.rb000066400000000000000000000144731331222022000172370ustar00rootroot00000000000000require 'minitest/autorun' require 'sprockets/utils' class TestUtils < MiniTest::Test include Sprockets::Utils def test_duplicable_pre_ruby_2_4 skip if RUBY_VERSION >= "2.4" objs = [nil, true, false, 1, "foo", :foo, [], {}] objs.each do |obj| begin obj.dup rescue TypeError refute duplicable?(obj), "can't dup: #{obj.inspect}" else assert duplicable?(obj), "can dup: #{obj.inspect}" end end end def test_duplicable_post_ruby_2_4 skip if RUBY_VERSION < "2.4" objs = [nil, true, false, 1, "foo", :foo, [], {}] objs.each do |obj| begin obj.dup rescue TypeError refute duplicable?(obj), "can't dup: #{obj.inspect}" else assert duplicable?(obj), "can dup: #{obj.inspect}" end end end def test_hash_reassoc h = hash_reassoc({}.freeze, :foo) do |value| refute value nil end assert_equal({foo: nil}, h) assert h.frozen? h = hash_reassoc({}, :foo) do |value| refute value true end assert_equal({foo: true}, h) assert h.frozen? h = hash_reassoc({foo: 1}.freeze, :foo) do |value| assert_equal 1, value 2 end assert_equal({foo: 2}, h) assert h.frozen? h = hash_reassoc({foo: "bar".freeze}.freeze, :foo) do |value| assert_equal "bar", value refute value.frozen? "baz" end assert_equal({foo: "baz"}, h) assert h.frozen? assert h[:foo].frozen? h = hash_reassoc({foo: "bar".freeze}.freeze, :foo) do |value| assert_equal "bar", value refute value.frozen? value.sub!("r", "z") end assert_equal({foo: "baz"}, h) assert h.frozen? assert h[:foo].frozen? h = hash_reassoc({foo: {bar: "baz".freeze}.freeze}.freeze, :foo, :bar) do |value| assert_equal "baz", value refute value.frozen? "biz" end assert_equal({foo: {bar: "biz"}}, h) assert h.frozen? assert h[:foo].frozen? assert h[:foo][:bar].frozen? h = hash_reassoc({foo: {bar: {baz: "biz".freeze}.freeze}.freeze}.freeze, :foo, :bar, :baz) do |value| assert_equal "biz", value refute value.frozen? "foo" end assert_equal({foo: {bar: {baz: "foo"}}}, h) assert h.frozen? assert h[:foo].frozen? assert h[:foo][:bar].frozen? assert h[:foo][:bar][:baz].frozen? end def test_string_ends_with_semicolon assert string_end_with_semicolon?("var foo;") refute string_end_with_semicolon?("var foo") assert string_end_with_semicolon?("var foo;\n") refute string_end_with_semicolon?("var foo\n") assert string_end_with_semicolon?("var foo;\n\n") refute string_end_with_semicolon?("var foo\n\n") assert string_end_with_semicolon?(" var foo;\n \n") refute string_end_with_semicolon?(" var foo\n \n") assert string_end_with_semicolon?("\tvar foo;\n\t\n") refute string_end_with_semicolon?("\tvar foo\n\t\n") assert string_end_with_semicolon?("var foo\n;\n") refute string_end_with_semicolon?("var foo\n\n") end def test_concat_javascript_sources assert_equal "var foo;\n", apply_concat_javascript_sources("".freeze, "var foo;\n".freeze) assert_equal "\nvar foo;\n", apply_concat_javascript_sources("\n".freeze, "var foo;\n".freeze) assert_equal " \nvar foo;\n", apply_concat_javascript_sources(" ".freeze, "var foo;\n".freeze) assert_equal "var foo;\nvar bar;\n", apply_concat_javascript_sources("var foo;\n".freeze, "var bar;\n".freeze) assert_equal "var foo;\nvar bar;\n", apply_concat_javascript_sources("var foo".freeze, "var bar".freeze) assert_equal "var foo;\nvar bar;\n", apply_concat_javascript_sources("var foo;".freeze, "var bar;".freeze) assert_equal "var foo;\nvar bar;\n", apply_concat_javascript_sources("var foo".freeze, "var bar;".freeze) end def apply_concat_javascript_sources(*args) args.reduce(String.new(""), &method(:concat_javascript_sources)) end def test_post_order_depth_first_search m = [] m[11] = [4, 5, 10] m[4] = [2, 3] m[10] = [8, 9] m[2] = [0, 1] m[8] = [6, 7] assert_equal Set.new(0..11), dfs(11) { |n| m[n] } m = [] m[11] = [4, 5, 10] m[4] = [2, 3] m[3] = [1] m[5] = [1, 2] m[10] = [8, 9] m[2] = [0, 1] m[8] = [6, 7] m[6] = [5] assert_equal Set.new(0..11), dfs(11) { |n| m[n] } end def test_post_order_depth_first_find_all_paths m = [] m[0] = [1] m[1] = [2] m[2] = [3] m[3] = [4, 5] m[4] = [1] assert_equal [ [0, 1], [0, 1, 2], [0, 1, 2, 3], [0, 1, 2, 3, 4], [0, 1, 2, 3, 5] ], dfs_paths([0]) { |n| m[n] } assert_equal [ [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 5] ], dfs_paths([1]) { |n| m[n] } assert_equal [], dfs_paths([5]) { |n| m[n] } end module Functions module InstanceMethods def bar 2 end end include InstanceMethods def foo 1 end end module ScopedFunctions def foo 7 end def bar 8 end def baz 9 end end module OtherScopedFunctions def bar 3 end def baz 4 end end class Context include Functions end def test_module_include context = Context.new assert context.respond_to?(:foo) assert context.respond_to?(:bar) refute context.respond_to?(:baz) assert_equal 1, context.foo assert_equal 2, context.bar module_include(Functions, ScopedFunctions) do assert context.respond_to?(:foo) assert context.respond_to?(:bar) assert context.respond_to?(:baz) assert_equal 7, context.foo assert_equal 8, context.bar assert_equal 9, context.baz end assert context.respond_to?(:foo) assert context.respond_to?(:bar) refute context.respond_to?(:baz) assert_equal 1, context.foo assert_equal 2, context.bar module_include(Functions, OtherScopedFunctions) do assert context.respond_to?(:foo) assert context.respond_to?(:bar) assert context.respond_to?(:baz) assert_equal 1, context.foo assert_equal 3, context.bar assert_equal 4, context.baz end assert context.respond_to?(:foo) assert context.respond_to?(:bar) refute context.respond_to?(:baz) assert_equal 1, context.foo assert_equal 2, context.bar end end sprockets-3.7.2/test/test_yui_compressor.rb000066400000000000000000000016641331222022000211570ustar00rootroot00000000000000require 'minitest/autorun' require 'sprockets/cache' require 'sprockets/yui_compressor' class TestYUICompressor < MiniTest::Test def test_compress_javascript input = { content_type: 'application/javascript', data: "function foo() {\n return true;\n}", cache: Sprockets::Cache.new } output = "function foo(){return true};" begin assert_equal output, Sprockets::YUICompressor.call(input) rescue YUI::Compressor::RuntimeError skip "No Java runtime present" end end def test_compress_css input = { content_type: 'text/css', data: "h1 {\n color: red;\n}\n", cache: Sprockets::Cache.new } output = "h1{color:red}" begin assert_equal output, Sprockets::YUICompressor.call(input) rescue YUI::Compressor::RuntimeError skip "No Java runtime present" end end def test_cache_key assert Sprockets::YUICompressor.cache_key end end