rack-pack 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/.rspec +1 -0
- data/Gemfile +2 -0
- data/LICENSE +20 -0
- data/README.md +89 -0
- data/Rakefile +13 -0
- data/lib/rack-pack.rb +1 -0
- data/lib/rack/pack.rb +87 -0
- data/lib/rack/pack/javascript.rb +28 -0
- data/lib/rack/pack/package.rb +82 -0
- data/lib/rack/pack/stylesheet.rb +22 -0
- data/lib/rack/pack/version.rb +5 -0
- data/rack-pack.gemspec +31 -0
- data/spec/rack/pack/javascript_spec.rb +77 -0
- data/spec/rack/pack/package_spec.rb +167 -0
- data/spec/rack/pack/stylesheet_spec.rb +49 -0
- data/spec/rack/pack_spec.rb +185 -0
- data/spec/spec_helper.rb +41 -0
- metadata +232 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Peter Browne
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# Rack::Pack
|
2
|
+
|
3
|
+
Rack::Pack is a piece of Rack Middleware that packages and optionally compresses assets such as javascripts and stylesheets into single files. In a development environment, assets will be packaged on each request if there have been changes to the source files. In a production environment, assets will only be packaged one time, and only if there have been changes.
|
4
|
+
|
5
|
+
### Why?
|
6
|
+
|
7
|
+
I've tried a dozen different asset packaging solutions including AssetPackager, BundleFu, Jammit, Sprockets, etc...none of which were quite what I wanted. I didn't need any helpers, controllers, embedded images, rake tasks, or Yaml config files. I just wanted something to take my assets and package them into one file, and you're looking at it.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
gem install rack-pack
|
12
|
+
|
13
|
+
## Basic Usage
|
14
|
+
|
15
|
+
require 'rack-pack'
|
16
|
+
use Rack::Pack
|
17
|
+
|
18
|
+
or in Rails:
|
19
|
+
|
20
|
+
# Gemfile
|
21
|
+
gem 'rack-pack'
|
22
|
+
|
23
|
+
# config/application.rb
|
24
|
+
config.middleware.use Rack::Pack
|
25
|
+
|
26
|
+
### Packages
|
27
|
+
|
28
|
+
Two files will be packaged out of the box: `javascripts/application.js` & `stylesheets/application.css`. Rack::Pack will look in `vendor/javascripts`, `app/javascripts`, & `./javascripts` for any .js files and `vendor/stylesheets`, `app/stylesheets`, & `./stylesheets` for any .css files. These files will be packaged in the order they're found.
|
29
|
+
|
30
|
+
To create your own packages, pass in the name of the output file and the source files as options:
|
31
|
+
|
32
|
+
use Rack::Pack, 'js/main.js' => [
|
33
|
+
'vendor/javascripts/jquery.js',
|
34
|
+
'vendor/javascripts/swfobject.js,
|
35
|
+
'app/javascripts/misc.js',
|
36
|
+
'app/javascripts/main.js'
|
37
|
+
]
|
38
|
+
# Creates a 'public/js/main.js' file
|
39
|
+
|
40
|
+
Notice how the output file is relative to the public dir. By default this is just `'public'`, but this can be changed using the `:public_dir` option:
|
41
|
+
|
42
|
+
use Rack::Pack, :public_dir => 'html', 'js/main.js' => %w(js/plugins.js js/main.js)
|
43
|
+
# Creates a 'html/js/main.js' file
|
44
|
+
|
45
|
+
You can also pass a glob string for the source files. This string will be used to search for new files on each request. The downside is the source files will be concatenated in the order they're found.
|
46
|
+
|
47
|
+
use Rack::Pack, 'assets/scripts.js' => 'app/js/**/*.js'
|
48
|
+
|
49
|
+
In fact, this is how the default packages are declared:
|
50
|
+
|
51
|
+
use Rack::Pack,
|
52
|
+
'javascripts/application.js' => '{vendor,app,.}/javascripts/*.js',
|
53
|
+
'stylesheets/application.css' => '{vendor,app,.}/stylesheets/*.css'
|
54
|
+
|
55
|
+
Beautiful, isn't it? I don't think you can get simpler than that. No Yaml config files or rake tasks. You'll set it up once then forget about it completely. Well unless you have to add a new source file and you were explicity setting your source files for a package, but whatever.
|
56
|
+
|
57
|
+
### Compression
|
58
|
+
|
59
|
+
What good would an asset packager be without compression? Rack::Pack determines which javascript compressor you want to use based on which one has been required.
|
60
|
+
|
61
|
+
require 'packr'
|
62
|
+
use Rack::Pack
|
63
|
+
# would use Packr
|
64
|
+
|
65
|
+
or in Rails:
|
66
|
+
|
67
|
+
# Gemfile
|
68
|
+
gem 'jsmin'
|
69
|
+
|
70
|
+
# config/application.rb
|
71
|
+
config.middleware.use Rack::Pack
|
72
|
+
# would use JSMin
|
73
|
+
|
74
|
+
To pass options to the javascript compressor just use the `:js_compressor` option:
|
75
|
+
|
76
|
+
require 'packr'
|
77
|
+
use Rack::Pack, :js_compression => { :shrink_vars => true }
|
78
|
+
|
79
|
+
By default, packages are only compressed in a production environment. If for some reason you want them to always be compressed, pass the `:always_compress` option:
|
80
|
+
|
81
|
+
use Rack::Pack, :always_compress => true
|
82
|
+
|
83
|
+
## Heroku and other read-only filesystems
|
84
|
+
|
85
|
+
Because Rack::Pack relies on writing the packaged files, it won't package anything on Heroku. But, you could just check in your packaged files and push them to Heroku. I'll look into other options for future versions.
|
86
|
+
|
87
|
+
## Copyright
|
88
|
+
|
89
|
+
Copyright (c) 2010 [Peter Browne](http://petebrowne.com). See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rspec/core'
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
Rspec::Core::RakeTask.new
|
7
|
+
|
8
|
+
desc 'Open an irb session preloaded with this library'
|
9
|
+
task :console do
|
10
|
+
sh 'irb -rubygems -I lib -r mock_ftp.rb'
|
11
|
+
end
|
12
|
+
|
13
|
+
task :default => :spec
|
data/lib/rack-pack.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'rack/pack'
|
data/lib/rack/pack.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
class Pack
|
5
|
+
autoload :Javascript, 'rack/pack/javascript'
|
6
|
+
autoload :Package, 'rack/pack/package'
|
7
|
+
autoload :Stylesheet, 'rack/pack/stylesheet'
|
8
|
+
autoload :Version, 'rack/pack/version'
|
9
|
+
|
10
|
+
DEFAULT_OPTIONS = {
|
11
|
+
:public_dir => 'public',
|
12
|
+
:always_update => false,
|
13
|
+
:always_compress => false,
|
14
|
+
:js_compression => {},
|
15
|
+
:css_compression => {}
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
class << self
|
19
|
+
attr_accessor :packages, :options, :environment
|
20
|
+
|
21
|
+
def production?
|
22
|
+
self.environment.to_s == 'production'
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_package(output_file, source_files)
|
26
|
+
if source_files.nil?
|
27
|
+
packages.delete(output_file)
|
28
|
+
else
|
29
|
+
public_output_file = ::File.join(self.options[:public_dir], output_file.to_s)
|
30
|
+
package_class = Package[output_file]
|
31
|
+
packages[output_file] = package_class.new(public_output_file, source_files)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize(app, options = {})
|
37
|
+
@app = app
|
38
|
+
|
39
|
+
Pack.packages = {}
|
40
|
+
Pack.options = DEFAULT_OPTIONS.dup
|
41
|
+
Pack.environment = if defined?(RAILS_ENV)
|
42
|
+
RAILS_ENV # Rails 2
|
43
|
+
elsif defined?(Rails) && defined?(Rails.env)
|
44
|
+
Rails.env # Rails 3
|
45
|
+
elsif defined?(app.settings) && defined?(app.settings.environment)
|
46
|
+
app.settings.environment # Sinatra
|
47
|
+
elsif ENV.key?('RACK_ENV')
|
48
|
+
ENV['RACK_ENV']
|
49
|
+
else
|
50
|
+
:development
|
51
|
+
end
|
52
|
+
|
53
|
+
Pack.options.each_key do |key|
|
54
|
+
Pack.options[key] = options.delete(key) if options.key?(key)
|
55
|
+
end
|
56
|
+
|
57
|
+
Pack.add_package 'javascripts/application.js', '{vendor,app,.}/javascripts/*.js'
|
58
|
+
Pack.add_package 'stylesheets/application.css', '{vendor,app,.}/stylesheets/*.css'
|
59
|
+
|
60
|
+
options.each do |to_file, from_files|
|
61
|
+
Pack.add_package(to_file, from_files)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def call(env)
|
66
|
+
update_packages unless skip_update?
|
67
|
+
@app.call(env)
|
68
|
+
end
|
69
|
+
|
70
|
+
protected
|
71
|
+
|
72
|
+
def update_packages
|
73
|
+
Pack.packages.each_value do |package|
|
74
|
+
package.update if package.stale?
|
75
|
+
end
|
76
|
+
@updated = true
|
77
|
+
end
|
78
|
+
|
79
|
+
def skip_update?
|
80
|
+
return false if Pack.options[:always_update]
|
81
|
+
Pack.production? && @updated
|
82
|
+
end
|
83
|
+
|
84
|
+
Package.register :js, Javascript
|
85
|
+
Package.register :css, Stylesheet
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Rack
|
2
|
+
class Pack
|
3
|
+
class Javascript < Package
|
4
|
+
def compress(source)
|
5
|
+
if defined?(JSMin)
|
6
|
+
JSMin.minify(source)
|
7
|
+
elsif defined?(Packr)
|
8
|
+
options = compression_options :shrink_vars => true
|
9
|
+
Packr.pack(source, options)
|
10
|
+
elsif defined?(YUI) and defined?(YUI::JavaScriptCompressor)
|
11
|
+
options = compression_options :munge => true
|
12
|
+
YUI::JavaScriptCompressor.new(options).compress(source)
|
13
|
+
elsif defined?(Closure) and defined?(Closure::Compiler)
|
14
|
+
Closure::Compiler.new(compression_options).compile(source)
|
15
|
+
else
|
16
|
+
source
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
def compression_options(defaults = {})
|
23
|
+
return defaults unless Pack.options
|
24
|
+
defaults.merge Pack.options[:js_compression]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
class Pack
|
5
|
+
class Package
|
6
|
+
class << self
|
7
|
+
def mappings
|
8
|
+
@package_mappings ||= {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def register(ext, package_class)
|
12
|
+
ext = ext.to_s.sub(/^\./, '').downcase
|
13
|
+
mappings[ext] = package_class
|
14
|
+
end
|
15
|
+
|
16
|
+
def [](file)
|
17
|
+
ext = ::File.extname(file.to_s).sub(/^\./, '').downcase
|
18
|
+
mappings[ext] || self
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :file
|
23
|
+
|
24
|
+
def initialize(output_file, source_files)
|
25
|
+
@file = to_pathname(output_file)
|
26
|
+
@from = if source_files.is_a?(Array)
|
27
|
+
source_files.map { |file| to_pathname(file) }
|
28
|
+
else
|
29
|
+
source_files.to_s
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def update
|
34
|
+
file.dirname.mkpath
|
35
|
+
file.open('w') do |file|
|
36
|
+
file << compile
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def compile
|
41
|
+
compiled = source_files.map(&:read).join
|
42
|
+
compiled = compress(compiled) if compress?
|
43
|
+
compiled.strip
|
44
|
+
end
|
45
|
+
|
46
|
+
def compress(source)
|
47
|
+
source
|
48
|
+
end
|
49
|
+
|
50
|
+
def stale?
|
51
|
+
@source_files = nil
|
52
|
+
source_files? && (file_missing? || source_files_newer?)
|
53
|
+
end
|
54
|
+
|
55
|
+
def source_files
|
56
|
+
@source_files ||= @from.is_a?(Array) ? @from : Pathname.glob(@from)
|
57
|
+
end
|
58
|
+
|
59
|
+
def compress?
|
60
|
+
Pack.production? || Pack.options && Pack.options[:always_compress]
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
|
65
|
+
def to_pathname(file)
|
66
|
+
file.is_a?(Pathname) ? file : Pathname.new(file)
|
67
|
+
end
|
68
|
+
|
69
|
+
def source_files?
|
70
|
+
!source_files.empty?
|
71
|
+
end
|
72
|
+
|
73
|
+
def file_missing?
|
74
|
+
!file.exist?
|
75
|
+
end
|
76
|
+
|
77
|
+
def source_files_newer?
|
78
|
+
source_files.map(&:mtime).max > file.mtime
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Rack
|
2
|
+
class Pack
|
3
|
+
class Stylesheet < Package
|
4
|
+
def compress(source)
|
5
|
+
if defined?(Rainpress)
|
6
|
+
Rainpress.compress(source, compression_options)
|
7
|
+
elsif defined?(YUI) and defined?(YUI::CssCompressor)
|
8
|
+
YUI::CssCompressor.new(compression_options).compress(source)
|
9
|
+
else
|
10
|
+
source
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
def compression_options(defaults = {})
|
17
|
+
return defaults unless Pack.options
|
18
|
+
defaults.merge Pack.options[:css_compression]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/rack-pack.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/rack/pack/version', __FILE__)
|
3
|
+
require 'bundler'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'rack-pack'
|
7
|
+
s.version = Rack::Pack::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = 'Pete Browne'
|
10
|
+
s.email = 'me@petebrowne.com'
|
11
|
+
s.homepage = 'http://rubygems.org/gems/rack-pack'
|
12
|
+
s.summary = 'Rack Middleware for packaging assets such as javascripts and stylesheets.'
|
13
|
+
s.description = 'Packages assets such as javascripts and stylesheets using a method inspired by Sass::Plugin. In development mode, the assets are packaged on each request. In production mode, the assets are packaged only one time.'
|
14
|
+
|
15
|
+
s.required_rubygems_version = '>= 1.3.6'
|
16
|
+
s.rubyforge_project = 'rack-pack'
|
17
|
+
|
18
|
+
s.add_dependency 'rack', '~> 1.2.1'
|
19
|
+
s.add_development_dependency 'rspec', '~> 2.0.0.beta.20'
|
20
|
+
s.add_development_dependency 'activesupport', '~> 3.0.0.rc2'
|
21
|
+
s.add_development_dependency 'test-construct', '~> 1.2.0'
|
22
|
+
s.add_development_dependency 'jsmin', '~> 1.0.1'
|
23
|
+
s.add_development_dependency 'packr', '~> 3.1.0'
|
24
|
+
s.add_development_dependency 'yui-compressor', '~> 0.9.1'
|
25
|
+
s.add_development_dependency 'closure-compiler', '~> 0.3.2'
|
26
|
+
s.add_development_dependency 'rainpress', '~> 1.0.0'
|
27
|
+
|
28
|
+
s.files = `git ls-files`.split("\n")
|
29
|
+
s.executables = `git ls-files`.split("\n").map{ |f| f =~ /^bin\/(.*)/ ? $1 : nil }.compact
|
30
|
+
s.require_path = 'lib'
|
31
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rack::Pack::Javascript do
|
4
|
+
describe '#compile' do
|
5
|
+
it 'should by default strip the concatenated output' do
|
6
|
+
within_construct do |c|
|
7
|
+
c.file 'input-1.js', ' 1'
|
8
|
+
c.file 'input-2.js', '2 '
|
9
|
+
|
10
|
+
package = Rack::Pack::Javascript.new('output.js', 'input-*.js')
|
11
|
+
package.compile.should == '12'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'with compression' do
|
16
|
+
before do
|
17
|
+
Rack::Pack.stub(:production? => true)
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when JSMin is required' do
|
21
|
+
it 'should compress using JSMin' do
|
22
|
+
reveal_const :JSMin do
|
23
|
+
within_construct do |c|
|
24
|
+
c.file 'input.js', 'function(number) { return number + 2; }'
|
25
|
+
|
26
|
+
package = Rack::Pack::Javascript.new('output.js', 'input.js')
|
27
|
+
package.compile.should == 'function(number){return number+2;}'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'when packr is required' do
|
34
|
+
it 'should compress using Packr' do
|
35
|
+
reveal_const :Packr do
|
36
|
+
within_construct do |c|
|
37
|
+
c.file 'input.js', '1'
|
38
|
+
|
39
|
+
Packr.should_receive(:pack).with('1', :shrink_vars => true).and_return('1')
|
40
|
+
Rack::Pack::Javascript.new('output.js', 'input.js').compile
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'when yui/compressor is required' do
|
47
|
+
it 'should compress using YUI::JavaScriptCompressor' do
|
48
|
+
reveal_const :YUI do
|
49
|
+
within_construct do |c|
|
50
|
+
c.file 'input.js', '1'
|
51
|
+
|
52
|
+
compressor = double(:yui_compressor)
|
53
|
+
compressor.should_receive(:compress).with('1').and_return('1')
|
54
|
+
YUI::JavaScriptCompressor.should_receive(:new).with(:munge => true).and_return(compressor)
|
55
|
+
Rack::Pack::Javascript.new('output.js', 'input.js').compile
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'when closure-compiler is required' do
|
62
|
+
it 'should compress using Closure::Compiler' do
|
63
|
+
reveal_const :Closure do
|
64
|
+
within_construct do |c|
|
65
|
+
c.file 'input.js', '1'
|
66
|
+
|
67
|
+
compressor = double(:closure_compiler)
|
68
|
+
compressor.should_receive(:compile).with('1').and_return('1')
|
69
|
+
Closure::Compiler.should_receive(:new).with({}).and_return(compressor)
|
70
|
+
Rack::Pack::Javascript.new('output.js', 'input.js').compile
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rack::Pack::Package do
|
4
|
+
class MockPackage
|
5
|
+
attr_accessor :output_file, :source_files
|
6
|
+
def initialize(output_file, source_files)
|
7
|
+
@output_file = output_file
|
8
|
+
@source_files = source_files
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def file_double(modified_at)
|
13
|
+
double(:file, :mtime => modified_at, :exist? => true, :is_a? => true)
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '.register' do
|
17
|
+
it 'will store the package class for the given extension' do
|
18
|
+
Rack::Pack::Package.register :mock, MockPackage
|
19
|
+
Rack::Pack::Package.mappings['mock'].should == MockPackage
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '.mappings' do
|
24
|
+
it 'should by default have a Javascript mapping' do
|
25
|
+
Rack::Pack::Package.mappings['js'].should == Rack::Pack::Javascript
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should by default have a Stylesheet mapping' do
|
29
|
+
Rack::Pack::Package.mappings['css'].should == Rack::Pack::Stylesheet
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '.[]' do
|
34
|
+
it 'should find the correct package class for the given file' do
|
35
|
+
Rack::Pack::Package['some/javascript.js'].should == Rack::Pack::Javascript
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should default to the base Package' do
|
39
|
+
Rack::Pack::Package['missing.ext'].should == Rack::Pack::Package
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#file' do
|
44
|
+
context 'when initialized with a string' do
|
45
|
+
it 'should convert it to a pathname' do
|
46
|
+
package = Rack::Pack::Package.new('hello', [])
|
47
|
+
package.file.should == Pathname.new('hello')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#source_files'
|
52
|
+
context 'when initialized with an array of strings' do
|
53
|
+
it 'should convert them to pathnames' do
|
54
|
+
package = Rack::Pack::Package.new('', %w(file-1 file-2))
|
55
|
+
package.source_files.should =~ [ Pathname.new('file-1'), Pathname.new('file-2') ]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when initialized with a string' do
|
60
|
+
it 'should treat it as a Dir glob' do
|
61
|
+
within_construct do |c|
|
62
|
+
c.file 'dir/file-1.js'
|
63
|
+
c.file 'dir/file-2.js'
|
64
|
+
|
65
|
+
package = Rack::Pack::Package.new('', 'dir/*.js')
|
66
|
+
package.source_files.should =~ [ Pathname.new('dir/file-1.js'), Pathname.new('dir/file-2.js') ]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#stale?' do
|
73
|
+
context 'if the packed file is current' do
|
74
|
+
subject do
|
75
|
+
now = Time.now
|
76
|
+
package = Rack::Pack::Package.new('', [
|
77
|
+
file_double(now),
|
78
|
+
file_double(1.week.ago),
|
79
|
+
file_double(2.weeks.ago)
|
80
|
+
])
|
81
|
+
package.stub(:file => file_double(now))
|
82
|
+
package
|
83
|
+
end
|
84
|
+
|
85
|
+
it { should_not be_stale }
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'if the packed file is old' do
|
89
|
+
subject do
|
90
|
+
package = Rack::Pack::Package.new('', [
|
91
|
+
file_double(Time.now),
|
92
|
+
file_double(1.week.ago),
|
93
|
+
file_double(2.weeks.ago)
|
94
|
+
])
|
95
|
+
package.stub(:file => file_double(1.week.ago))
|
96
|
+
package
|
97
|
+
end
|
98
|
+
|
99
|
+
it { should be_stale }
|
100
|
+
end
|
101
|
+
|
102
|
+
context "if the packed file doesn't exist" do
|
103
|
+
subject do
|
104
|
+
Rack::Pack::Package.new(
|
105
|
+
'missing/file',
|
106
|
+
[
|
107
|
+
file_double(Time.now),
|
108
|
+
file_double(1.week.ago),
|
109
|
+
file_double(2.weeks.ago)
|
110
|
+
]
|
111
|
+
)
|
112
|
+
end
|
113
|
+
|
114
|
+
it { should be_stale }
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'when given a glob string' do
|
118
|
+
it 'should check for new files' do
|
119
|
+
within_construct do |c|
|
120
|
+
c.file 'directory/file-1'
|
121
|
+
|
122
|
+
package = Rack::Pack::Package.new(
|
123
|
+
file_double(2.weeks.ago),
|
124
|
+
'directory/**/*'
|
125
|
+
)
|
126
|
+
package.stale?
|
127
|
+
|
128
|
+
c.file 'directory/file-2'
|
129
|
+
package.should be_stale
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe '#update' do
|
136
|
+
it 'should combine the files and write it to the output file' do
|
137
|
+
within_construct do |c|
|
138
|
+
to_file = c.file('packed-file', 'Stale Content')
|
139
|
+
package = Rack::Pack::Package.new(
|
140
|
+
to_file,
|
141
|
+
[
|
142
|
+
c.file('file-1', '1'),
|
143
|
+
c.file('file-2', '2'),
|
144
|
+
c.file('file-3', '3')
|
145
|
+
]
|
146
|
+
)
|
147
|
+
package.update
|
148
|
+
to_file.read.should == '123'
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe '#compress?' do
|
154
|
+
subject { Rack::Pack::Package.new('', '') }
|
155
|
+
it { should_not be_compress }
|
156
|
+
|
157
|
+
context 'in a production environment' do
|
158
|
+
before { Rack::Pack.stub(:production? => true) }
|
159
|
+
it { should be_compress }
|
160
|
+
end
|
161
|
+
|
162
|
+
context 'with the :always_compress option' do
|
163
|
+
before { Rack::Pack.stub(:options => double(:options, :[] => true)) }
|
164
|
+
it { should be_compress }
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rack::Pack::Stylesheet do
|
4
|
+
describe '#compile' do
|
5
|
+
it 'should by default strip the concatenated output' do
|
6
|
+
within_construct do |c|
|
7
|
+
c.file 'input-1.css', ' 1'
|
8
|
+
c.file 'input-2.css', '2 '
|
9
|
+
|
10
|
+
package = Rack::Pack::Stylesheet.new('output.css', 'input-*.css')
|
11
|
+
package.compile.should == '12'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'with compression' do
|
16
|
+
before do
|
17
|
+
Rack::Pack.stub(:production? => true)
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when yui/compressor is required' do
|
21
|
+
it 'should compress using YUI::JavaScriptCompressor' do
|
22
|
+
reveal_const :YUI do
|
23
|
+
within_construct do |c|
|
24
|
+
c.file 'input.css', '1'
|
25
|
+
|
26
|
+
compressor = double(:yui_compressor)
|
27
|
+
compressor.should_receive(:compress).with('1').and_return('1')
|
28
|
+
YUI::CssCompressor.should_receive(:new).with({}).and_return(compressor)
|
29
|
+
Rack::Pack::Stylesheet.new('output.css', 'input.css').compile
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'when rainpress is required' do
|
36
|
+
it 'should compress using Rainpress' do
|
37
|
+
reveal_const :Rainpress do
|
38
|
+
within_construct do |c|
|
39
|
+
c.file 'input.css', '1'
|
40
|
+
|
41
|
+
Rainpress.should_receive(:compress).with('1', {}).and_return('')
|
42
|
+
Rack::Pack::Stylesheet.new('output.css', 'input.css').compile
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,185 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rack::Pack do
|
4
|
+
def build_app(*args)
|
5
|
+
Rack::Builder.app do
|
6
|
+
use Rack::Lint
|
7
|
+
use Rack::Pack, *args
|
8
|
+
run lambda { |env| [ 200, { 'Content-Type' => 'text/html' }, [ 'Hello World!' ] ] }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def request_for(url = '/')
|
13
|
+
Rack::MockRequest.env_for(url)
|
14
|
+
end
|
15
|
+
alias_method :request, :request_for
|
16
|
+
|
17
|
+
context 'with default settings' do
|
18
|
+
it 'should pack javascripts' do
|
19
|
+
within_construct do |c|
|
20
|
+
c.file 'vendor/javascripts/file-1.js', '1'
|
21
|
+
c.file 'javascripts/file-2.js', '2'
|
22
|
+
c.file 'javascripts/file-3.js', '3'
|
23
|
+
|
24
|
+
@app = build_app
|
25
|
+
@app.call(request)
|
26
|
+
File.read('public/javascripts/application.js').should == '123'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should pack stylesheets' do
|
31
|
+
within_construct do |c|
|
32
|
+
c.file 'vendor/stylesheets/file-1.css', '1'
|
33
|
+
c.file 'stylesheets/file-2.css', '2'
|
34
|
+
c.file 'stylesheets/file-3.css', '3'
|
35
|
+
|
36
|
+
@app = build_app
|
37
|
+
@app.call(request)
|
38
|
+
File.read('public/stylesheets/application.css').should == '123'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should not compress the packages' do
|
43
|
+
reveal_const :JSMin do
|
44
|
+
within_construct do |c|
|
45
|
+
c.file 'app/javascripts/file.js', '1'
|
46
|
+
|
47
|
+
JSMin.should_not_receive(:minify)
|
48
|
+
@app = build_app
|
49
|
+
@app.call(request)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'on next request' do
|
55
|
+
context 'with updates' do
|
56
|
+
it 'should re-pack the package' do
|
57
|
+
within_construct do |c|
|
58
|
+
c.file 'app/stylesheets/file-1.css', '1'
|
59
|
+
c.file 'app/stylesheets/file-2.css', '2'
|
60
|
+
|
61
|
+
@app = build_app
|
62
|
+
@app.call(request)
|
63
|
+
File.read('public/stylesheets/application.css').should == '12'
|
64
|
+
|
65
|
+
sleep 1
|
66
|
+
c.file 'app/stylesheets/file-2.css', '3'
|
67
|
+
@app.call(request)
|
68
|
+
File.read('public/stylesheets/application.css').should == '13'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'without updates' do
|
74
|
+
it 'should not re-pack the package' do
|
75
|
+
within_construct do |c|
|
76
|
+
c.file 'app/stylesheets/file-1.css', '1'
|
77
|
+
c.file 'app/stylesheets/file-2.css', '2'
|
78
|
+
|
79
|
+
@app = build_app
|
80
|
+
@app.call(request)
|
81
|
+
File.read('public/stylesheets/application.css').should == '12'
|
82
|
+
original_mtime = File.mtime('public/stylesheets/application.css')
|
83
|
+
|
84
|
+
sleep 1
|
85
|
+
@app.call(request)
|
86
|
+
File.mtime('public/stylesheets/application.css').should == original_mtime
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'with some custom packages' do
|
94
|
+
it 'should pack the files' do
|
95
|
+
within_construct do |c|
|
96
|
+
c.file 'vendor/javascripts/file-1.js', '1'
|
97
|
+
c.file 'app/javascripts/file-2.js', '2'
|
98
|
+
|
99
|
+
@app = build_app 'main.js' => %w(vendor/javascripts/file-1.js app/javascripts/file-2.js)
|
100
|
+
@app.call(request)
|
101
|
+
File.read('public/main.js').should == '12'
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'with :always_compress on' do
|
107
|
+
it 'should compress the packages' do
|
108
|
+
reveal_const :JSMin do
|
109
|
+
within_construct do |c|
|
110
|
+
c.file 'app/javascripts/file.js', '1'
|
111
|
+
|
112
|
+
JSMin.should_receive(:minify).with('1').and_return('1')
|
113
|
+
@app = build_app :always_compress => true
|
114
|
+
@app.call(request)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'with a default package set to nil' do
|
121
|
+
it 'should not pack the files' do
|
122
|
+
within_construct do |c|
|
123
|
+
c.file 'vendor/javascripts/file-1.js', '1'
|
124
|
+
|
125
|
+
@app = build_app 'javascripts/application.js' => nil
|
126
|
+
@app.call(request)
|
127
|
+
File.exist?('public/javascripts/application.js').should_not be_true
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'in a production environment' do
|
133
|
+
before do
|
134
|
+
Rails = double('rails', :env => double('env', :to_s => 'production'))
|
135
|
+
end
|
136
|
+
|
137
|
+
after do
|
138
|
+
Object.send(:remove_const, :Rails)
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'should pack files only one time' do
|
142
|
+
within_construct do |c|
|
143
|
+
c.file 'app/javascripts/file.js', '1'
|
144
|
+
|
145
|
+
@app = build_app
|
146
|
+
@app.call(request)
|
147
|
+
|
148
|
+
sleep 1
|
149
|
+
c.file 'app/javascripts/file.js', '2'
|
150
|
+
@app.call(request)
|
151
|
+
File.read('public/javascripts/application.js').should == '1'
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'with always_update option as true' do
|
156
|
+
it 'should pack the files on each request' do
|
157
|
+
within_construct do |c|
|
158
|
+
c.file 'app/javascripts/file.js', '1'
|
159
|
+
|
160
|
+
@app = build_app :always_update => true
|
161
|
+
@app.call(request)
|
162
|
+
|
163
|
+
sleep 1
|
164
|
+
c.file 'app/javascripts/file.js', '2'
|
165
|
+
@app.call(request)
|
166
|
+
File.read('public/javascripts/application.js').should == '2'
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context 'with javascript compression options' do
|
172
|
+
it 'should pass the options to the javascript compressor' do
|
173
|
+
reveal_const :Packr do
|
174
|
+
within_construct do |c|
|
175
|
+
c.file 'app/javascripts/file.js', '1'
|
176
|
+
|
177
|
+
Packr.should_receive(:pack).with('1', :shrink_vars => false).and_return('1')
|
178
|
+
@app = build_app :js_compression => { :shrink_vars => false }
|
179
|
+
@app.call(request)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
lib = File.expand_path('../../lib', __FILE__)
|
2
|
+
$:.unshift(lib) unless $:.include?(lib)
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'rspec'
|
6
|
+
require 'construct'
|
7
|
+
# To get 2.weeks.ago syntax...
|
8
|
+
require 'active_support/core_ext/time/acts_like'
|
9
|
+
require 'active_support/core_ext/time/calculations'
|
10
|
+
require 'active_support/core_ext/numeric/time'
|
11
|
+
require 'jsmin'
|
12
|
+
require 'packr'
|
13
|
+
require 'yui/compressor'
|
14
|
+
require 'closure-compiler'
|
15
|
+
require 'rainpress'
|
16
|
+
require 'rack/pack'
|
17
|
+
|
18
|
+
$hidden_consts = {}
|
19
|
+
[ :JSMin, :Packr, :YUI, :Closure, :Rainpress ].each do |const|
|
20
|
+
$hidden_consts[const] = Object.const_get(const)
|
21
|
+
Object.send :remove_const, const
|
22
|
+
end
|
23
|
+
|
24
|
+
RSpec.configure do |config|
|
25
|
+
config.include Construct::Helpers
|
26
|
+
|
27
|
+
config.after do
|
28
|
+
Rack::Pack.packages = nil
|
29
|
+
Rack::Pack.options = nil
|
30
|
+
Rack::Pack.environment = nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def reveal_const(const)
|
34
|
+
begin
|
35
|
+
Object.const_set const, $hidden_consts[const]
|
36
|
+
yield
|
37
|
+
ensure
|
38
|
+
Object.send :remove_const, const
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
metadata
ADDED
@@ -0,0 +1,232 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rack-pack
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 21
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
- 1
|
10
|
+
version: 0.2.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Pete Browne
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-08-29 00:00:00 -05:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
hash: 29
|
28
|
+
segments:
|
29
|
+
- 1
|
30
|
+
- 2
|
31
|
+
- 1
|
32
|
+
version: 1.2.1
|
33
|
+
requirement: *id001
|
34
|
+
name: rack
|
35
|
+
prerelease: false
|
36
|
+
type: :runtime
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 62196427
|
44
|
+
segments:
|
45
|
+
- 2
|
46
|
+
- 0
|
47
|
+
- 0
|
48
|
+
- beta
|
49
|
+
- 20
|
50
|
+
version: 2.0.0.beta.20
|
51
|
+
requirement: *id002
|
52
|
+
name: rspec
|
53
|
+
prerelease: false
|
54
|
+
type: :development
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 977940607
|
62
|
+
segments:
|
63
|
+
- 3
|
64
|
+
- 0
|
65
|
+
- 0
|
66
|
+
- rc2
|
67
|
+
version: 3.0.0.rc2
|
68
|
+
requirement: *id003
|
69
|
+
name: activesupport
|
70
|
+
prerelease: false
|
71
|
+
type: :development
|
72
|
+
- !ruby/object:Gem::Dependency
|
73
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ~>
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
hash: 31
|
79
|
+
segments:
|
80
|
+
- 1
|
81
|
+
- 2
|
82
|
+
- 0
|
83
|
+
version: 1.2.0
|
84
|
+
requirement: *id004
|
85
|
+
name: test-construct
|
86
|
+
prerelease: false
|
87
|
+
type: :development
|
88
|
+
- !ruby/object:Gem::Dependency
|
89
|
+
version_requirements: &id005 !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ~>
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
hash: 21
|
95
|
+
segments:
|
96
|
+
- 1
|
97
|
+
- 0
|
98
|
+
- 1
|
99
|
+
version: 1.0.1
|
100
|
+
requirement: *id005
|
101
|
+
name: jsmin
|
102
|
+
prerelease: false
|
103
|
+
type: :development
|
104
|
+
- !ruby/object:Gem::Dependency
|
105
|
+
version_requirements: &id006 !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
hash: 3
|
111
|
+
segments:
|
112
|
+
- 3
|
113
|
+
- 1
|
114
|
+
- 0
|
115
|
+
version: 3.1.0
|
116
|
+
requirement: *id006
|
117
|
+
name: packr
|
118
|
+
prerelease: false
|
119
|
+
type: :development
|
120
|
+
- !ruby/object:Gem::Dependency
|
121
|
+
version_requirements: &id007 !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ~>
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
hash: 57
|
127
|
+
segments:
|
128
|
+
- 0
|
129
|
+
- 9
|
130
|
+
- 1
|
131
|
+
version: 0.9.1
|
132
|
+
requirement: *id007
|
133
|
+
name: yui-compressor
|
134
|
+
prerelease: false
|
135
|
+
type: :development
|
136
|
+
- !ruby/object:Gem::Dependency
|
137
|
+
version_requirements: &id008 !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ~>
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
hash: 23
|
143
|
+
segments:
|
144
|
+
- 0
|
145
|
+
- 3
|
146
|
+
- 2
|
147
|
+
version: 0.3.2
|
148
|
+
requirement: *id008
|
149
|
+
name: closure-compiler
|
150
|
+
prerelease: false
|
151
|
+
type: :development
|
152
|
+
- !ruby/object:Gem::Dependency
|
153
|
+
version_requirements: &id009 !ruby/object:Gem::Requirement
|
154
|
+
none: false
|
155
|
+
requirements:
|
156
|
+
- - ~>
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
hash: 23
|
159
|
+
segments:
|
160
|
+
- 1
|
161
|
+
- 0
|
162
|
+
- 0
|
163
|
+
version: 1.0.0
|
164
|
+
requirement: *id009
|
165
|
+
name: rainpress
|
166
|
+
prerelease: false
|
167
|
+
type: :development
|
168
|
+
description: Packages assets such as javascripts and stylesheets using a method inspired by Sass::Plugin. In development mode, the assets are packaged on each request. In production mode, the assets are packaged only one time.
|
169
|
+
email: me@petebrowne.com
|
170
|
+
executables: []
|
171
|
+
|
172
|
+
extensions: []
|
173
|
+
|
174
|
+
extra_rdoc_files: []
|
175
|
+
|
176
|
+
files:
|
177
|
+
- .gitignore
|
178
|
+
- .rspec
|
179
|
+
- Gemfile
|
180
|
+
- LICENSE
|
181
|
+
- README.md
|
182
|
+
- Rakefile
|
183
|
+
- lib/rack-pack.rb
|
184
|
+
- lib/rack/pack.rb
|
185
|
+
- lib/rack/pack/javascript.rb
|
186
|
+
- lib/rack/pack/package.rb
|
187
|
+
- lib/rack/pack/stylesheet.rb
|
188
|
+
- lib/rack/pack/version.rb
|
189
|
+
- rack-pack.gemspec
|
190
|
+
- spec/rack/pack/javascript_spec.rb
|
191
|
+
- spec/rack/pack/package_spec.rb
|
192
|
+
- spec/rack/pack/stylesheet_spec.rb
|
193
|
+
- spec/rack/pack_spec.rb
|
194
|
+
- spec/spec_helper.rb
|
195
|
+
has_rdoc: true
|
196
|
+
homepage: http://rubygems.org/gems/rack-pack
|
197
|
+
licenses: []
|
198
|
+
|
199
|
+
post_install_message:
|
200
|
+
rdoc_options: []
|
201
|
+
|
202
|
+
require_paths:
|
203
|
+
- lib
|
204
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
205
|
+
none: false
|
206
|
+
requirements:
|
207
|
+
- - ">="
|
208
|
+
- !ruby/object:Gem::Version
|
209
|
+
hash: 3
|
210
|
+
segments:
|
211
|
+
- 0
|
212
|
+
version: "0"
|
213
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
214
|
+
none: false
|
215
|
+
requirements:
|
216
|
+
- - ">="
|
217
|
+
- !ruby/object:Gem::Version
|
218
|
+
hash: 23
|
219
|
+
segments:
|
220
|
+
- 1
|
221
|
+
- 3
|
222
|
+
- 6
|
223
|
+
version: 1.3.6
|
224
|
+
requirements: []
|
225
|
+
|
226
|
+
rubyforge_project: rack-pack
|
227
|
+
rubygems_version: 1.3.7
|
228
|
+
signing_key:
|
229
|
+
specification_version: 3
|
230
|
+
summary: Rack Middleware for packaging assets such as javascripts and stylesheets.
|
231
|
+
test_files: []
|
232
|
+
|