rack-sprockets 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +116 -0
- data/Rakefile +61 -0
- data/lib/rack/sprockets.rb +51 -0
- data/lib/rack/sprockets/base.rb +67 -0
- data/lib/rack/sprockets/config.rb +40 -0
- data/lib/rack/sprockets/options.rb +131 -0
- data/lib/rack/sprockets/request.rb +78 -0
- data/lib/rack/sprockets/response.rb +45 -0
- data/lib/rack/sprockets/source.rb +118 -0
- data/lib/rack/sprockets/version.rb +13 -0
- metadata +124 -0
data/README.rdoc
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
= Rack::Sprockets
|
2
|
+
|
3
|
+
== Description
|
4
|
+
|
5
|
+
Sprockets javascript preprocessing for Rack apps.
|
6
|
+
|
7
|
+
== Installation
|
8
|
+
|
9
|
+
gem install rack-sprockets
|
10
|
+
|
11
|
+
# optional, for compression
|
12
|
+
gem install yui-compressor
|
13
|
+
|
14
|
+
== Basic Usage
|
15
|
+
|
16
|
+
Rack::Sprockets is implemented as a piece of Rack middleware and can be used with
|
17
|
+
any Rack-based application. If your application includes a rackup (`.ru`) file
|
18
|
+
or uses Rack::Builder to construct the application pipeline, simply require
|
19
|
+
and use as follows:
|
20
|
+
|
21
|
+
require 'rack/sprockets'
|
22
|
+
|
23
|
+
# optional - use as necessary
|
24
|
+
Rack::Sprockets.configure do |config|
|
25
|
+
config.compress = true
|
26
|
+
# other configs ...
|
27
|
+
end
|
28
|
+
|
29
|
+
use Rack::Sprockets,
|
30
|
+
:load_path => 'app/scripts',
|
31
|
+
:hosted_at => '/'
|
32
|
+
# additional options ...
|
33
|
+
|
34
|
+
run app
|
35
|
+
|
36
|
+
== Using with Rails
|
37
|
+
|
38
|
+
Add this to your `config/environment.rb`:
|
39
|
+
|
40
|
+
config.middleware.use "Rack::Sprockets"
|
41
|
+
|
42
|
+
Add any configs in an initializer (optional - use as necessary):
|
43
|
+
|
44
|
+
Rack::Sprockets.configure do |config|
|
45
|
+
config.cache = true
|
46
|
+
# additional configs ...
|
47
|
+
end
|
48
|
+
|
49
|
+
You should now see `Rack::Sprockets` listed in the middleware pipeline:
|
50
|
+
|
51
|
+
rake middleware
|
52
|
+
|
53
|
+
== Available Options
|
54
|
+
These are similar to sprockets options and, where applicable, map directly to a corresponding Sprockets option.
|
55
|
+
|
56
|
+
* :*root* ['.']
|
57
|
+
- The app root. The reference point for the source and public options. Maps to the `:root` Sprockets option.
|
58
|
+
|
59
|
+
* :*public* ['public']
|
60
|
+
- The path where static files are located. Maps to the `:asset_root` Sprockets option.
|
61
|
+
|
62
|
+
* :*source* ["app/javascripts"]
|
63
|
+
- The path where Sprockets source files are located. Notice this does not map to the `:source_files` Sprockets option. It is assumed that any requested resource found in `:source` be treated as a Sprockets source file.
|
64
|
+
|
65
|
+
* :*hosted_at* ["/javascripts"]
|
66
|
+
- The public hosted HTTP path for static javascripts files.
|
67
|
+
|
68
|
+
* :*load_path* [["app/javascripts/", "vendor/javascripts/"]]
|
69
|
+
- An ordered array of directory names to search for dependencies in. Maps to the `:load_path` Sprockets option.
|
70
|
+
|
71
|
+
* :*expand_paths* [true]
|
72
|
+
- Whether or not to expand filenames according to shell glob rules. Maps to the `:expand_paths` Sprockets option.
|
73
|
+
|
74
|
+
== Available Configurations
|
75
|
+
* .*cache* [false]
|
76
|
+
- Whether or not to cache the concatenation output to a corresponding static file.
|
77
|
+
|
78
|
+
* .*compress* [false]
|
79
|
+
- Whether or not to apply compression to the concatenation output - uses YUI Compressor if available or will remove extraneous whitespace if not.
|
80
|
+
|
81
|
+
== Links
|
82
|
+
|
83
|
+
* *GitHub*
|
84
|
+
- http://github.com/kelredd/rack-sprockets
|
85
|
+
|
86
|
+
* *Sprockets*
|
87
|
+
- http://getsprockets.org
|
88
|
+
|
89
|
+
* *Yui* *Compressor*
|
90
|
+
- http://github.com/sstephenson/ruby-yui-compressor
|
91
|
+
- http://developer.yahoo.com/yui/compressor
|
92
|
+
|
93
|
+
== License
|
94
|
+
|
95
|
+
Copyright (c) 2010 Kelly Redding (mailto:kelly@kelredd.com)
|
96
|
+
|
97
|
+
Permission is hereby granted, free of charge, to any person
|
98
|
+
obtaining a copy of this software and associated documentation
|
99
|
+
files (the "Software"), to deal in the Software without
|
100
|
+
restriction, including without limitation the rights to use,
|
101
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
102
|
+
copies of the Software, and to permit persons to whom the
|
103
|
+
Software is furnished to do so, subject to the following
|
104
|
+
conditions:
|
105
|
+
|
106
|
+
The above copyright notice and this permission notice shall be
|
107
|
+
included in all copies or substantial portions of the Software.
|
108
|
+
|
109
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
110
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
111
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
112
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
113
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
114
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
115
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
116
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
require 'lib/rack/sprockets/version'
|
6
|
+
|
7
|
+
spec = Gem::Specification.new do |s|
|
8
|
+
s.name = 'rack-sprockets'
|
9
|
+
s.version = RackSprockets::Version.to_s
|
10
|
+
s.has_rdoc = true
|
11
|
+
s.extra_rdoc_files = %w(README.rdoc)
|
12
|
+
s.rdoc_options = %w(--main README.rdoc)
|
13
|
+
s.summary = "Sprockets javascript preprocessing for Rack apps."
|
14
|
+
s.author = 'Kelly Redding'
|
15
|
+
s.email = 'kelly@kelredd.com'
|
16
|
+
s.homepage = 'http://github.com/kelredd/rack-sprockets'
|
17
|
+
s.files = %w(README.rdoc Rakefile) + Dir.glob("{lib}/**/*")
|
18
|
+
# s.executables = ['rack-sprockets']
|
19
|
+
|
20
|
+
s.add_development_dependency("shoulda", [">= 2.10.0"])
|
21
|
+
s.add_development_dependency("sinatra", [">= 0.9.4"])
|
22
|
+
s.add_development_dependency("rack-test", [">= 0.5.3"])
|
23
|
+
s.add_development_dependency("webrat", [">= 0.6.0"])
|
24
|
+
|
25
|
+
s.add_dependency("rack", [">= 0.4"])
|
26
|
+
s.add_dependency("sprockets", [">= 1.0.0"])
|
27
|
+
end
|
28
|
+
|
29
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
30
|
+
pkg.gem_spec = spec
|
31
|
+
end
|
32
|
+
|
33
|
+
Rake::TestTask.new do |t|
|
34
|
+
t.libs << 'test'
|
35
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
36
|
+
t.verbose = true
|
37
|
+
end
|
38
|
+
|
39
|
+
begin
|
40
|
+
require 'rcov/rcovtask'
|
41
|
+
|
42
|
+
Rcov::RcovTask.new(:coverage) do |t|
|
43
|
+
t.libs = ['test']
|
44
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
45
|
+
t.verbose = true
|
46
|
+
t.rcov_opts = ['--text-report', "-x #{Gem.path}", '-x /Library/Ruby', '-x /usr/lib/ruby']
|
47
|
+
end
|
48
|
+
|
49
|
+
task :default => :coverage
|
50
|
+
|
51
|
+
rescue LoadError
|
52
|
+
warn "\n**** Install rcov (sudo gem install relevance-rcov) to get coverage stats ****\n"
|
53
|
+
task :default => :test
|
54
|
+
end
|
55
|
+
|
56
|
+
desc 'Generate the gemspec to serve this gem'
|
57
|
+
task :gemspec do
|
58
|
+
file = File.dirname(__FILE__) + "/#{spec.name}.gemspec"
|
59
|
+
File.open(file, 'w') {|f| f << spec.to_ruby }
|
60
|
+
puts "Created gemspec: #{file}"
|
61
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'rack/sprockets/config'
|
3
|
+
require 'rack/sprockets/options'
|
4
|
+
require 'rack/sprockets/source'
|
5
|
+
require 'rack/sprockets/base'
|
6
|
+
require 'rack/sprockets/request'
|
7
|
+
require 'rack/sprockets/response'
|
8
|
+
|
9
|
+
# === Usage
|
10
|
+
#
|
11
|
+
# Create with default configs:
|
12
|
+
# require 'rack/sprockets'
|
13
|
+
# Rack::Sprockets.new(app, :compress => true)
|
14
|
+
#
|
15
|
+
# Within a rackup file (or with Rack::Builder):
|
16
|
+
# require 'rack/sprockets'
|
17
|
+
#
|
18
|
+
# use Rack::Sprockets,
|
19
|
+
# :source => 'app/scripts'
|
20
|
+
# :compress => true
|
21
|
+
#
|
22
|
+
# run app
|
23
|
+
|
24
|
+
module Rack::Sprockets
|
25
|
+
MIME_TYPE = "text/javascript"
|
26
|
+
@@config = Config.new
|
27
|
+
|
28
|
+
class << self
|
29
|
+
|
30
|
+
# Configuration accessors for Rack::Sprockets
|
31
|
+
# (see config.rb for details)
|
32
|
+
def configure
|
33
|
+
yield @@config if block_given?
|
34
|
+
end
|
35
|
+
def config
|
36
|
+
@@config
|
37
|
+
end
|
38
|
+
def config=(value)
|
39
|
+
@@config = value
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
# Create a new Rack::Sprockets middleware component
|
45
|
+
# => the +options+ Hash can be used to specify default option values
|
46
|
+
# => (see Rack::Sprockets::Options for possible key/values)
|
47
|
+
def self.new(app, options={}, &block)
|
48
|
+
Base.new(app, options, &block)
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'rack/sprockets/options'
|
2
|
+
require 'rack/sprockets/request'
|
3
|
+
require 'rack/sprockets/response'
|
4
|
+
|
5
|
+
module Rack::Sprockets
|
6
|
+
class Base
|
7
|
+
include Rack::Sprockets::Options
|
8
|
+
|
9
|
+
def initialize(app, options={})
|
10
|
+
@app = app
|
11
|
+
initialize_options options
|
12
|
+
yield self if block_given?
|
13
|
+
validate_options
|
14
|
+
end
|
15
|
+
|
16
|
+
# The Rack call interface. The receiver acts as a prototype and runs
|
17
|
+
# each request in a clone object unless the +rack.run_once+ variable is
|
18
|
+
# set in the environment.
|
19
|
+
def call(env)
|
20
|
+
if env['rack.run_once']
|
21
|
+
call! env
|
22
|
+
else
|
23
|
+
clone.call! env
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# The real Rack call interface.
|
28
|
+
# if Sprockets JS is being requested, this is an endpoint:
|
29
|
+
# => generate the compiled javascripts
|
30
|
+
# => respond appropriately
|
31
|
+
# Otherwise, call on up to the app as normal
|
32
|
+
def call!(env)
|
33
|
+
@default_options.each { |k,v| env[k] ||= v }
|
34
|
+
@env = env
|
35
|
+
|
36
|
+
if (@request = Request.new(@env.dup.freeze)).for_sprockets?
|
37
|
+
Response.new(@env.dup.freeze, @request.source.to_js).to_rack
|
38
|
+
else
|
39
|
+
@app.call(env)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def validate_options
|
46
|
+
# ensure a root path is specified and does exists
|
47
|
+
unless options.has_key?(option_name(:root)) and !options(:root).nil?
|
48
|
+
raise(ArgumentError, "no :root option set")
|
49
|
+
end
|
50
|
+
unless File.exists?(options(:root))
|
51
|
+
raise(ArgumentError, "the :root path ('#{options(:root)}') does not exist")
|
52
|
+
end
|
53
|
+
|
54
|
+
set :root, File.expand_path(options(:root))
|
55
|
+
|
56
|
+
# ensure a source path is specified and does exists
|
57
|
+
unless options.has_key?(option_name(:source)) and !options(:source).nil?
|
58
|
+
raise(ArgumentError, "no :source option set")
|
59
|
+
end
|
60
|
+
source_path = File.join(options(:root), options(:source))
|
61
|
+
unless File.exists?(source_path)
|
62
|
+
raise(ArgumentError, "the :source path ('#{source_path}') does not exist")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Rack::Sprockets
|
2
|
+
|
3
|
+
# Handles configuration for Rack::Sprockets
|
4
|
+
# Available config settings:
|
5
|
+
# :cache
|
6
|
+
# whether to cache the compilation output to
|
7
|
+
# a corresponding static file. Also determines
|
8
|
+
# what value config#combinations(:key) returns
|
9
|
+
# :compress
|
10
|
+
# Whether or not to apply compression to the
|
11
|
+
# concatenation output - uses YUI Compressor
|
12
|
+
# if available or will remove extraneous
|
13
|
+
# whitespace if not.
|
14
|
+
|
15
|
+
class Config
|
16
|
+
|
17
|
+
ATTRIBUTES = [:cache, :compress]
|
18
|
+
attr_accessor *ATTRIBUTES
|
19
|
+
|
20
|
+
DEFAULTS = {
|
21
|
+
:cache => false,
|
22
|
+
:compress => false
|
23
|
+
}
|
24
|
+
|
25
|
+
def initialize(settings={})
|
26
|
+
ATTRIBUTES.each do |a|
|
27
|
+
instance_variable_set("@#{a}", settings[a] || DEFAULTS[a])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def cache?
|
32
|
+
!!@cache
|
33
|
+
end
|
34
|
+
|
35
|
+
def compress?
|
36
|
+
!!@compress
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
module Rack::Sprockets
|
2
|
+
module Options
|
3
|
+
|
4
|
+
# Handles options for Rack::Sprockets
|
5
|
+
# Available options:
|
6
|
+
# => root
|
7
|
+
# The app root. The reference point for
|
8
|
+
# the source and public options. Maps to
|
9
|
+
# the `:root` Sprockets option.
|
10
|
+
# => public
|
11
|
+
# The path where static files are located.
|
12
|
+
# Maps to the `:asset_root` Sprockets option.
|
13
|
+
# => source
|
14
|
+
# The path where Sprockets source files are
|
15
|
+
# located. Notice this does not map to the
|
16
|
+
# `:source_files` Sprockets option. It is
|
17
|
+
# assumed that any requested resource found
|
18
|
+
# in `:source` be treated as a Sprockets
|
19
|
+
# source file.
|
20
|
+
# => hosted_at
|
21
|
+
# The public hosted HTTP path for static
|
22
|
+
# javascripts files.
|
23
|
+
# => load_path
|
24
|
+
# An ordered array of directory names to
|
25
|
+
# search for dependencies in. Maps to the
|
26
|
+
# `:load_path` Sprockets option.
|
27
|
+
# => expand_paths
|
28
|
+
# Whether or not to expand filenames according
|
29
|
+
# to shell glob rules. Maps to the
|
30
|
+
# `:expand_paths` Sprockets option.
|
31
|
+
|
32
|
+
RACK_ENV_NS = "rack-sprockets"
|
33
|
+
COLLECTION_OPTS = ["#{RACK_ENV_NS}.load_path"]
|
34
|
+
|
35
|
+
module ClassMethods
|
36
|
+
|
37
|
+
def defaults
|
38
|
+
{
|
39
|
+
option_name(:root) => ".",
|
40
|
+
option_name(:public) => 'public',
|
41
|
+
option_name(:source) => 'app/javascripts',
|
42
|
+
option_name(:hosted_at) => '/javascripts',
|
43
|
+
option_name(:load_path) => [
|
44
|
+
"app/javascripts/",
|
45
|
+
"vendor/javascripts/"
|
46
|
+
],
|
47
|
+
option_name(:expand_paths) => true
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
# Rack::Sprockets uses the Rack Environment to store option values. All options
|
52
|
+
# are stored in the Rack Environment as "<RACK_ENV_PREFIX>.<option>", where
|
53
|
+
# <option> is the option name.
|
54
|
+
def option_name(key)
|
55
|
+
case key
|
56
|
+
when Symbol ; "#{RACK_ENV_NS}.#{key}"
|
57
|
+
when String ; key
|
58
|
+
else raise ArgumentError
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
module InstanceMethods
|
65
|
+
|
66
|
+
# Rack::Sprockets uses the Rack Environment to store option values. All options
|
67
|
+
# are stored in the Rack Environment as "<RACK_ENV_PREFIX>.<option>", where
|
68
|
+
# <option> is the option name.
|
69
|
+
def option_name(key)
|
70
|
+
self.class.option_name(key)
|
71
|
+
end
|
72
|
+
|
73
|
+
# The underlying options Hash. During initialization (or outside of a
|
74
|
+
# request), this is a default values Hash. During a request, this is the
|
75
|
+
# Rack environment Hash. The default values Hash is merged in underneath
|
76
|
+
# the Rack environment before each request is processed.
|
77
|
+
# => if a key is passed, the option value for the key is returned
|
78
|
+
def options(key=nil)
|
79
|
+
if key
|
80
|
+
(@env || @default_options)[option_name(key)]
|
81
|
+
else
|
82
|
+
@env || @default_options
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Set multiple options at once.
|
87
|
+
def options=(hash={})
|
88
|
+
hash.each { |key,value| write_option(key, value) }
|
89
|
+
end
|
90
|
+
|
91
|
+
# Set an option. When +option+ is a Symbol, it is set in the Rack
|
92
|
+
# Environment as "rack-cache.option". When +option+ is a String, it
|
93
|
+
# exactly as specified. The +option+ argument may also be a Hash in
|
94
|
+
# which case each key/value pair is merged into the environment as if
|
95
|
+
# the #set method were called on each.
|
96
|
+
def set(option, value=nil)
|
97
|
+
if value.nil?
|
98
|
+
self.options = option.to_hash
|
99
|
+
else
|
100
|
+
write_option option, value
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
def initialize_options(options={})
|
107
|
+
@default_options = self.class.defaults
|
108
|
+
self.options = options
|
109
|
+
end
|
110
|
+
|
111
|
+
def read_option(key)
|
112
|
+
options[option_name(key)]
|
113
|
+
end
|
114
|
+
|
115
|
+
def write_option(key, value)
|
116
|
+
if COLLECTION_OPTS.include?(opt_name = option_name(key))
|
117
|
+
options[opt_name] = [*value]
|
118
|
+
else
|
119
|
+
options[opt_name] = value
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.included(receiver)
|
126
|
+
receiver.extend ClassMethods
|
127
|
+
receiver.send :include, InstanceMethods
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'rack/request'
|
2
|
+
require 'rack/sprockets'
|
3
|
+
require 'rack/sprockets/options'
|
4
|
+
require 'rack/sprockets/source'
|
5
|
+
|
6
|
+
module Rack::Sprockets
|
7
|
+
|
8
|
+
# Provides access to the HTTP request.
|
9
|
+
# Request objects respond to everything defined by Rack::Request
|
10
|
+
# as well as some additional convenience methods defined here
|
11
|
+
|
12
|
+
class Request < Rack::Request
|
13
|
+
include Rack::Sprockets::Options
|
14
|
+
|
15
|
+
JS_PATH_FORMATS = ['.js']
|
16
|
+
|
17
|
+
# The HTTP request method. This is the standard implementation of this
|
18
|
+
# method but is respecified here due to libraries that attempt to modify
|
19
|
+
# the behavior to respect POST tunnel method specifiers. We always want
|
20
|
+
# the real request method.
|
21
|
+
def request_method
|
22
|
+
@env['REQUEST_METHOD']
|
23
|
+
end
|
24
|
+
|
25
|
+
def path_info
|
26
|
+
@env['PATH_INFO']
|
27
|
+
end
|
28
|
+
|
29
|
+
def http_accept
|
30
|
+
@env['HTTP_ACCEPT']
|
31
|
+
end
|
32
|
+
|
33
|
+
def path_resource_name
|
34
|
+
File.basename(path_info, path_resource_format)
|
35
|
+
end
|
36
|
+
|
37
|
+
def path_resource_format
|
38
|
+
File.extname(path_info)
|
39
|
+
end
|
40
|
+
|
41
|
+
# The Rack::Sprockets::Source that the request is for
|
42
|
+
def source
|
43
|
+
@source ||= begin
|
44
|
+
cache = if Rack::Sprockets.config.cache?
|
45
|
+
File.join(options(:root), options(:public), options(:hosted_at))
|
46
|
+
else
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
source_opts = {
|
50
|
+
:folder => File.join(options(:root), options(:source)),
|
51
|
+
:cache => cache,
|
52
|
+
:compress => Rack::Sprockets.config.compress,
|
53
|
+
:secretary => {
|
54
|
+
:root => options(:root),
|
55
|
+
:load_path => options(:load_path),
|
56
|
+
:expand_paths => options(:expand_paths)
|
57
|
+
}
|
58
|
+
}
|
59
|
+
Source.new(path_resource_name, source_opts)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def for_js?
|
64
|
+
(http_accept && http_accept.include?(Rack::Sprockets::MIME_TYPE)) ||
|
65
|
+
(media_type && media_type.include?(Rack::Sprockets::MIME_TYPE )) ||
|
66
|
+
JS_PATH_FORMATS.include?(path_resource_format)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Determine if the request is for an existing Sprockets source file
|
70
|
+
# This will be called on every request so speed is an issue
|
71
|
+
# => first check if the request is a GET on a js resource (fast)
|
72
|
+
# => then check for sprockets source files that match the request (slow)
|
73
|
+
def for_sprockets?
|
74
|
+
get? && for_js? && !source.files.empty?
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rack/response'
|
2
|
+
require 'rack/utils'
|
3
|
+
|
4
|
+
module Rack::Sprockets
|
5
|
+
|
6
|
+
# Given some generated js, mimicks a Rack::Response
|
7
|
+
# => call to_rack to build standard rack response parameters
|
8
|
+
class Response
|
9
|
+
include Rack::Sprockets::Options
|
10
|
+
include Rack::Response::Helpers
|
11
|
+
|
12
|
+
# Rack response tuple accessors.
|
13
|
+
attr_accessor :status, :headers, :body
|
14
|
+
|
15
|
+
class << self
|
16
|
+
|
17
|
+
# Calculate appropriate content_length
|
18
|
+
def content_length(body)
|
19
|
+
if body.respond_to?(:bytesize)
|
20
|
+
body.bytesize
|
21
|
+
else
|
22
|
+
body.size
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
# Create a Response instance given the env
|
29
|
+
# and some generated js.
|
30
|
+
def initialize(env, js)
|
31
|
+
@env = env
|
32
|
+
@body = js
|
33
|
+
@status = 200 # OK
|
34
|
+
@headers = Rack::Utils::HeaderHash.new
|
35
|
+
|
36
|
+
headers["Content-Type"] = Rack::Sprockets::MIME_TYPE
|
37
|
+
headers["Content-Length"] = self.class.content_length(body).to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_rack
|
41
|
+
[status, headers.to_hash, body]
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'sprockets'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require "yui/compressor"
|
5
|
+
rescue LoadError
|
6
|
+
# only error about missing yui compressor if
|
7
|
+
# :yui compression is requested
|
8
|
+
end
|
9
|
+
|
10
|
+
module Rack::Sprockets
|
11
|
+
|
12
|
+
class Source
|
13
|
+
|
14
|
+
PREFERRED_EXTENSIONS = [:js]
|
15
|
+
SECRETARY_DEFAULTS = {
|
16
|
+
:expand_paths => true
|
17
|
+
}
|
18
|
+
YUI_OPTS = {
|
19
|
+
:munge => true
|
20
|
+
}
|
21
|
+
|
22
|
+
attr_reader :js_name
|
23
|
+
|
24
|
+
def initialize(js_name, options={})
|
25
|
+
@js_name = js_name
|
26
|
+
@compress = options[:compress]
|
27
|
+
@cache = options[:cache]
|
28
|
+
|
29
|
+
@folder = get_required_path(options, :folder)
|
30
|
+
@secretary = SECRETARY_DEFAULTS.merge(options[:secretary] || {})
|
31
|
+
end
|
32
|
+
|
33
|
+
def compress?
|
34
|
+
!!@compress
|
35
|
+
end
|
36
|
+
def cache?
|
37
|
+
!@cache.nil?
|
38
|
+
end
|
39
|
+
def cache
|
40
|
+
@cache
|
41
|
+
end
|
42
|
+
|
43
|
+
def files
|
44
|
+
@files ||= js_sources
|
45
|
+
end
|
46
|
+
|
47
|
+
def secretary
|
48
|
+
@secretary_obj ||= Sprockets::Secretary.new(@secretary.merge({
|
49
|
+
:source_files => files
|
50
|
+
}))
|
51
|
+
end
|
52
|
+
|
53
|
+
def compiled
|
54
|
+
@compiled ||= begin
|
55
|
+
compiled_js = secretary.concatenation.to_s
|
56
|
+
|
57
|
+
compiled_js = case @compress
|
58
|
+
when :whitespace
|
59
|
+
compiled_js.delete("\n")
|
60
|
+
when :yui
|
61
|
+
if defined?(YUI::JavaScriptCompressor)
|
62
|
+
YUI::JavaScriptCompressor.new(YUI_OPTS).compress(compiled_js)
|
63
|
+
else
|
64
|
+
raise LoadError, "YUI::JavaScriptCompressor is not available. Install it with: gem install yui-compressor"
|
65
|
+
end
|
66
|
+
else
|
67
|
+
compiled_js
|
68
|
+
end
|
69
|
+
|
70
|
+
if cache? && !File.exists?(cf = File.join(@cache, "#{@js_name}.js"))
|
71
|
+
FileUtils.mkdir_p(@cache)
|
72
|
+
File.open(cf, "w") do |file|
|
73
|
+
file.write(compiled_js)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
compiled_js
|
78
|
+
end
|
79
|
+
end
|
80
|
+
alias_method :to_js, :compiled
|
81
|
+
alias_method :js, :compiled
|
82
|
+
|
83
|
+
protected
|
84
|
+
|
85
|
+
# Source files matching the js name
|
86
|
+
def js_sources
|
87
|
+
@js_sources ||= preferred_sources([*@js_name])
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
# Given a list of file names, return a list of
|
93
|
+
# existing source files with the corresponding names
|
94
|
+
# honoring the preferred extension list
|
95
|
+
def preferred_sources(file_names)
|
96
|
+
file_names.collect do |name|
|
97
|
+
PREFERRED_EXTENSIONS.inject(nil) do |source_file, extension|
|
98
|
+
source_file || begin
|
99
|
+
path = File.join(@folder, "#{name}.#{extension}")
|
100
|
+
File.exists?(path) ? path : nil
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end.compact
|
104
|
+
end
|
105
|
+
|
106
|
+
def get_required_path(options, path_key)
|
107
|
+
unless options.has_key?(path_key)
|
108
|
+
raise(ArgumentError, "no :#{path_key} option specified")
|
109
|
+
end
|
110
|
+
unless File.exists?(options[path_key])
|
111
|
+
raise(ArgumentError, "the :#{path_key} ('#{options[path_key]}') does not exist")
|
112
|
+
end
|
113
|
+
options[path_key]
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
metadata
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rack-sprockets
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kelly Redding
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-02-14 00:00:00 -06:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: shoulda
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.10.0
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: sinatra
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.9.4
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: rack-test
|
37
|
+
type: :development
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.5.3
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: webrat
|
47
|
+
type: :development
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.6.0
|
54
|
+
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rack
|
57
|
+
type: :runtime
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0.4"
|
64
|
+
version:
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: sprockets
|
67
|
+
type: :runtime
|
68
|
+
version_requirement:
|
69
|
+
version_requirements: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 1.0.0
|
74
|
+
version:
|
75
|
+
description:
|
76
|
+
email: kelly@kelredd.com
|
77
|
+
executables: []
|
78
|
+
|
79
|
+
extensions: []
|
80
|
+
|
81
|
+
extra_rdoc_files:
|
82
|
+
- README.rdoc
|
83
|
+
files:
|
84
|
+
- README.rdoc
|
85
|
+
- Rakefile
|
86
|
+
- lib/rack/sprockets/base.rb
|
87
|
+
- lib/rack/sprockets/config.rb
|
88
|
+
- lib/rack/sprockets/options.rb
|
89
|
+
- lib/rack/sprockets/request.rb
|
90
|
+
- lib/rack/sprockets/response.rb
|
91
|
+
- lib/rack/sprockets/source.rb
|
92
|
+
- lib/rack/sprockets/version.rb
|
93
|
+
- lib/rack/sprockets.rb
|
94
|
+
has_rdoc: true
|
95
|
+
homepage: http://github.com/kelredd/rack-sprockets
|
96
|
+
licenses: []
|
97
|
+
|
98
|
+
post_install_message:
|
99
|
+
rdoc_options:
|
100
|
+
- --main
|
101
|
+
- README.rdoc
|
102
|
+
require_paths:
|
103
|
+
- lib
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: "0"
|
109
|
+
version:
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: "0"
|
115
|
+
version:
|
116
|
+
requirements: []
|
117
|
+
|
118
|
+
rubyforge_project:
|
119
|
+
rubygems_version: 1.3.5
|
120
|
+
signing_key:
|
121
|
+
specification_version: 3
|
122
|
+
summary: Sprockets javascript preprocessing for Rack apps.
|
123
|
+
test_files: []
|
124
|
+
|