rack-asset-compiler 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE.txt +19 -0
- data/Rakefile +9 -0
- data/Readme.md +76 -0
- data/examples/jasmine_config.rb +42 -0
- data/lib/rack/asset_compiler.rb +95 -0
- data/lib/rack/coffee_compiler.rb +43 -0
- data/lib/rack/sass_compiler.rb +31 -0
- data/rack-asset-compiler.gemspec +18 -0
- data/spec/asset_compiler_spec.rb +123 -0
- data/spec/coffee_compiler_spec.rb +62 -0
- data/spec/fixtures/coffeescripts/application.coffee +1 -0
- data/spec/fixtures/coffeescripts/syntax_error.coffee +1 -0
- data/spec/fixtures/eggscripts/application.eggscript +1 -0
- data/spec/fixtures/eggscripts/subdir/application.eggscript +1 -0
- data/spec/fixtures/sass/style.sass +2 -0
- data/spec/fixtures/sass/style.scss +3 -0
- data/spec/sass_compiler_spec.rb +41 -0
- metadata +100 -0
data/LICENSE.txt
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright 2011 Jonathan Baudanza
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/Rakefile
ADDED
data/Readme.md
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
# rack-asset-compiler
|
2
|
+
|
3
|
+
rack-asset-compiler is a Rack middleware that provides a generic interface for compiling static files, such as Sass or CoffeeScript files.
|
4
|
+
|
5
|
+
rack-asset-compiler does not use any local file storage and makes use of caching headers such as "Cache-Control" and "If-Modified-Since". This makes it ideal for running on read-only filesystem systems such as Heroku.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
gem install rack-asset-compiler
|
10
|
+
|
11
|
+
## Generic form
|
12
|
+
|
13
|
+
In this example, we have a set of text files with the extension .lower in the 'lowercase' directory, and
|
14
|
+
we want to server .uppercase files out of http://yourhost.com/uppercase
|
15
|
+
|
16
|
+
The compilation step is given in the form of a lambda passed as the `:compiler` option. This lambda will
|
17
|
+
be invoked whenever a client requests a file that needs to be compiled. The source filename will be passed
|
18
|
+
in and the compiled output is expected to be returned.
|
19
|
+
|
20
|
+
require 'rack/asset_compiler'
|
21
|
+
|
22
|
+
use Rack::AssetCompiler(
|
23
|
+
:source_dir => 'lowercase',
|
24
|
+
:url => '/uppercase',
|
25
|
+
:content_type => 'text/plain',
|
26
|
+
:source_extension => 'lower',
|
27
|
+
:compiler => lamba { |source_file|
|
28
|
+
File.read(source_file).upcase
|
29
|
+
}
|
30
|
+
)
|
31
|
+
|
32
|
+
## Subclassing
|
33
|
+
An alternative to passing in a lambda to the :compiler option is to subclass Rack::AssetCompiler and
|
34
|
+
override the `compile` method.
|
35
|
+
|
36
|
+
This gem comes with two subclasses: one for compiling CoffeeScript and one for Sass.
|
37
|
+
|
38
|
+
## Compiling CoffeeScript
|
39
|
+
|
40
|
+
config.ru
|
41
|
+
require 'rack/coffee_compiler'
|
42
|
+
|
43
|
+
use Rack::CoffeeCompiler,
|
44
|
+
:source_dir => 'app/coffeescripts'),
|
45
|
+
:url => '/javascripts',
|
46
|
+
:alert_on_error => true # Generates a window.alert on compile error. Defaults to (RACK_ENV != 'production')
|
47
|
+
|
48
|
+
Gemfile
|
49
|
+
gem 'therubyracer'
|
50
|
+
gem 'coffee-script'
|
51
|
+
|
52
|
+
# On heroku, use this gem instead of therubyracer
|
53
|
+
gem 'therubyracer-heroku', '0.8.1.pre3'
|
54
|
+
|
55
|
+
See [examples/jasmine_config.rb](https://github.com/jbaudanza/rack-asset-compiler/tree/master/examples/jasmine_config.rb) for an example of how to use CoffeeScript with your jasmine specs.
|
56
|
+
|
57
|
+
## Compiling Sass
|
58
|
+
|
59
|
+
On Rails
|
60
|
+
|
61
|
+
require 'rack/sass_compiler'
|
62
|
+
|
63
|
+
# Disable the standard Sass plugin which will write to the filesystem
|
64
|
+
Rails.application.config.middleware.delete(Sass::Plugin::Rack)
|
65
|
+
|
66
|
+
# Insert the new middleware
|
67
|
+
Rails.application.config.middleware.use Rack::SassCompiler,
|
68
|
+
:source_dir => 'app/sass',
|
69
|
+
:url => '/javascripts',
|
70
|
+
:syntax => :scss # :sass or :scss, defaults to :scss
|
71
|
+
|
72
|
+
## Thanks
|
73
|
+
asset-compiler was inspired by [rack-coffee] by [Matthew Lyon][mattly]
|
74
|
+
|
75
|
+
[rack-coffee]: https://github.com/mattly/rack-coffee
|
76
|
+
[mattly]: https://github.com/mattly/rack-coffee
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#
|
2
|
+
# spec/javascripts/support/jasmine_config.rb
|
3
|
+
#
|
4
|
+
require 'rack/coffee_compiler'
|
5
|
+
|
6
|
+
module Jasmine
|
7
|
+
class Config
|
8
|
+
|
9
|
+
alias_method :old_js_files, :js_files
|
10
|
+
|
11
|
+
def js_files(spec_filter = nil)
|
12
|
+
# Convert all .coffee files into .js files before putting them in a script tag
|
13
|
+
old_js_files(spec_filter).map do |filename|
|
14
|
+
filename.sub(/\.coffee/, '.js')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def start_server(port=8888)
|
19
|
+
# We can't access the RAILS_ROOT constant from here
|
20
|
+
root = File.expand_path(File.join(File.dirname(__FILE__), '../../..'))
|
21
|
+
|
22
|
+
config = self
|
23
|
+
|
24
|
+
app = Rack::Builder.new do
|
25
|
+
# Compiler for your specs
|
26
|
+
use Rack::CoffeeCompiler,
|
27
|
+
:source_dir => File.join(root, 'spec/javascripts'),
|
28
|
+
:url => config.spec_path
|
29
|
+
|
30
|
+
# Compiler for your app files
|
31
|
+
use Rack::CoffeeCompiler,
|
32
|
+
:source_dir => File.join(root, 'public/javascripts'),
|
33
|
+
:url => '/public/javascripts'
|
34
|
+
|
35
|
+
run Jasmine.app(config)
|
36
|
+
end
|
37
|
+
|
38
|
+
handler = Rack::Handler.default
|
39
|
+
handler.run app, :Port => port, :AccessLog => []
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Rack
|
2
|
+
class AssetCompiler
|
3
|
+
attr_accessor :url, :source_dir, :source_extension
|
4
|
+
|
5
|
+
F = ::File
|
6
|
+
|
7
|
+
def initialize(app, options={}, &block)
|
8
|
+
@app = app
|
9
|
+
|
10
|
+
options = {
|
11
|
+
:compiler => block,
|
12
|
+
:source_dir => Dir.pwd,
|
13
|
+
:url => '/',
|
14
|
+
:cache => ENV['RACK_ENV'] == 'production'
|
15
|
+
}.merge(options)
|
16
|
+
|
17
|
+
%w(source_extension content_type).each do |field|
|
18
|
+
raise "Missing required option :#{field}" unless options.has_key?(field.to_sym)
|
19
|
+
end
|
20
|
+
|
21
|
+
@compiler = options[:compiler]
|
22
|
+
@source_dir = options[:source_dir]
|
23
|
+
@url = options[:url]
|
24
|
+
@source_extension = options[:source_extension]
|
25
|
+
@content_type = options[:content_type]
|
26
|
+
|
27
|
+
@cache_ttl = options[:cache]
|
28
|
+
|
29
|
+
# Default cache duration is 1 week
|
30
|
+
if(@cache_ttl && !@cache_ttl.kind_of?(Integer))
|
31
|
+
@cache_ttl = 60 * 60 * 24 * 7
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def response(status, body)
|
36
|
+
body += "\r\n"
|
37
|
+
[status, {"Content-Type" => 'text/plain',
|
38
|
+
"Content-Length" => body.size.to_s},
|
39
|
+
[body]]
|
40
|
+
end
|
41
|
+
|
42
|
+
def compile(source_file)
|
43
|
+
if @compiler
|
44
|
+
@compiler.call(source_file)
|
45
|
+
else
|
46
|
+
raise "Missing compiler"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def call(env)
|
51
|
+
request_path = Utils.unescape(env["PATH_INFO"])
|
52
|
+
return response( 403, 'Forbidden') if request_path.include? ".."
|
53
|
+
|
54
|
+
match_parts = url.split('/').select{ |str| str.length > 0 }
|
55
|
+
request_parts = request_path.split('/').select{ |str| str.length > 0 }
|
56
|
+
|
57
|
+
if(request_parts.take(match_parts.length) == match_parts)
|
58
|
+
request_base = request_parts[match_parts.length..-1]
|
59
|
+
|
60
|
+
# Swap in the source file extension
|
61
|
+
request_base[-1].sub!(/\.\w+$/, '.' + source_extension)
|
62
|
+
|
63
|
+
source_file = F.join(source_dir, request_base)
|
64
|
+
|
65
|
+
if F.exists?(source_file)
|
66
|
+
last_modified_time = F.mtime(source_file)
|
67
|
+
|
68
|
+
if env['HTTP_IF_MODIFIED_SINCE']
|
69
|
+
cached_time = Time.parse(env['HTTP_IF_MODIFIED_SINCE'])
|
70
|
+
if last_modified_time <= cached_time
|
71
|
+
return [304, {}, "Not modified\r\n"]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
body = compile(source_file)
|
76
|
+
|
77
|
+
headers = {
|
78
|
+
'Content-Type' => @content_type,
|
79
|
+
'Content-Length' => body.length.to_s,
|
80
|
+
'Last-Modified' => last_modified_time.httpdate
|
81
|
+
}
|
82
|
+
|
83
|
+
if @cache_ttl
|
84
|
+
headers['Expires'] = (Time.now + @cache_ttl).strftime('%a, %d %b %Y %H:%M:%S GMT')
|
85
|
+
headers['Cache-Control'] = "public,max-age=#{@cache_ttl}"
|
86
|
+
end
|
87
|
+
|
88
|
+
return [200, headers, body]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
@app.call(env)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rack/asset_compiler'
|
2
|
+
require 'coffee-script'
|
3
|
+
|
4
|
+
module Rack
|
5
|
+
class CoffeeCompiler < AssetCompiler
|
6
|
+
LOCK = Mutex.new
|
7
|
+
|
8
|
+
def initialize(app, options={})
|
9
|
+
options = {
|
10
|
+
:url => '/javascripts',
|
11
|
+
:content_type => 'text/javascript',
|
12
|
+
:source_extension => 'coffee',
|
13
|
+
:alert_on_error => ENV['RACK_ENV'] != 'production',
|
14
|
+
:lock => LOCK
|
15
|
+
}.merge(options)
|
16
|
+
|
17
|
+
@alert_on_error = options[:alert_on_error]
|
18
|
+
@lock = options[:lock]
|
19
|
+
super
|
20
|
+
end
|
21
|
+
|
22
|
+
def compile(source_file)
|
23
|
+
if @lock
|
24
|
+
@lock.synchronize{ unsynchronized_compile(source_file) }
|
25
|
+
else
|
26
|
+
unsynchronized_compile(source_file)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def unsynchronized_compile(source_file)
|
31
|
+
begin
|
32
|
+
CoffeeScript.compile(::File.read(source_file))
|
33
|
+
rescue CoffeeScript::CompilationError => e
|
34
|
+
if @alert_on_error
|
35
|
+
error_msg = "CoffeeScript compilation error in #{source_file}.coffee:\n\n #{e.to_s}"
|
36
|
+
"window.alert(#{error_msg.to_json});"
|
37
|
+
else
|
38
|
+
raise e
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rack/asset_compiler'
|
2
|
+
require 'sass'
|
3
|
+
|
4
|
+
module Rack
|
5
|
+
class SassCompiler < AssetCompiler
|
6
|
+
attr_accessor :syntax
|
7
|
+
|
8
|
+
def initialize(app, options={})
|
9
|
+
options
|
10
|
+
|
11
|
+
options = {
|
12
|
+
:url => '/stylesheets',
|
13
|
+
:content_type => 'text/css',
|
14
|
+
:syntax => :scss
|
15
|
+
}.merge(options)
|
16
|
+
|
17
|
+
@syntax = options[:syntax]
|
18
|
+
options[:source_extension] ||= syntax.to_s
|
19
|
+
super
|
20
|
+
end
|
21
|
+
|
22
|
+
def compile(source_file)
|
23
|
+
sass_options = {
|
24
|
+
:syntax => syntax,
|
25
|
+
:cache => false,
|
26
|
+
:load_paths => [source_dir]
|
27
|
+
}
|
28
|
+
Sass::Engine.new(::File.read(source_file), sass_options).render
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'rack-asset-compiler'
|
3
|
+
s.version = "0.0.2"
|
4
|
+
s.author = 'Jonathan Baudanza'
|
5
|
+
s.email = 'jon@jonb.org'
|
6
|
+
s.summary = 'Rack Middleware to facilitate the generic compiling static assets.'
|
7
|
+
s.homepage = 'http://www.github.com/jbaudanza/rack-asset-compiler'
|
8
|
+
s.add_dependency 'rack'
|
9
|
+
s.files = [ "rack-asset-compiler.gemspec", "Rakefile", "Readme.md", "LICENSE.txt" ]
|
10
|
+
s.files += Dir['lib/rack/*.rb'] + Dir['spec/**/*']
|
11
|
+
s.files += [ "examples/jasmine_config.rb" ]
|
12
|
+
|
13
|
+
s.description = <<END
|
14
|
+
rack-asset-compiler is a Rack middleware that provides a generic interface for compiling static files, such as Sass or CoffeeScript files.
|
15
|
+
|
16
|
+
rack-asset-compiler does not use any local file storage and makes use of caching headers such as "Cache-Control" and "If-Modified-Since". This makes it ideal for running on read-only filesystem systems such as Heroku.
|
17
|
+
END
|
18
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'rack/asset_compiler'
|
2
|
+
require 'rack/lobster'
|
3
|
+
require "rack/test"
|
4
|
+
|
5
|
+
include Rack::Test::Methods
|
6
|
+
|
7
|
+
describe "AssetCompiler" do
|
8
|
+
before do
|
9
|
+
@compiler = lambda do |source_file|
|
10
|
+
@source_file = source_file
|
11
|
+
'chickenscript'
|
12
|
+
end
|
13
|
+
|
14
|
+
@source_dir = File.join(File.dirname(__FILE__), 'fixtures/eggscripts')
|
15
|
+
|
16
|
+
@options = {
|
17
|
+
:url => '/chickenscripts/',
|
18
|
+
:source_dir => @source_dir,
|
19
|
+
:source_extension => 'eggscript',
|
20
|
+
:content_type => 'text/chicken-script',
|
21
|
+
:compiler => @compiler
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def app
|
26
|
+
options = @options
|
27
|
+
Rack::Builder.new {
|
28
|
+
use Rack::Lint
|
29
|
+
use Rack::AssetCompiler, options
|
30
|
+
run Rack::Lobster.new
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should raise an error if required options are missing" do
|
35
|
+
lambda {
|
36
|
+
@options.delete(:content_type)
|
37
|
+
get '/oops'
|
38
|
+
}.should raise_error
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should match files directly beneath the URL" do
|
42
|
+
get '/chickenscripts/application.chickenscript'
|
43
|
+
@source_file.should == "#{@source_dir}/application.eggscript"
|
44
|
+
last_response.body.should == 'chickenscript'
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should match files underneath a subdirectry" do
|
48
|
+
get '/chickenscripts/subdir/application.chickenscript'
|
49
|
+
@source_file.should == "#{@source_dir}/subdir/application.eggscript"
|
50
|
+
last_response.body.should == 'chickenscript'
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should not call the compiler for missing files" do
|
54
|
+
get '/chickenscripts/missing.chickenscript'
|
55
|
+
@source_file.should be_nil
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should use the correct content-type" do
|
59
|
+
get '/chickenscripts/application.chickenscript'
|
60
|
+
last_response.content_type.should == 'text/chicken-script'
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should not match files outside the URL parameter" do
|
64
|
+
get '/lobster'
|
65
|
+
last_response.body.should include('Lobstericious')
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should include a last-modified header" do
|
69
|
+
get '/chickenscripts/application.chickenscript'
|
70
|
+
last_response.headers["Last-Modified"].should == File.mtime("#{@source_dir}/application.eggscript").httpdate
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should respond with a 304 on a last-modified hit" do
|
74
|
+
last_modified_time = File.mtime("#{@source_dir}/application.eggscript").httpdate
|
75
|
+
get '/chickenscripts/application.chickenscript', {}, {'HTTP_IF_MODIFIED_SINCE' => last_modified_time}
|
76
|
+
last_response.status.should == 304
|
77
|
+
last_response.body.should == "Not modified\r\n"
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should return the compiled code on a last-modified miss" do
|
81
|
+
last_modified_time = (File.mtime("#{@source_dir}/application.eggscript") - 10).httpdate
|
82
|
+
get '/chickenscripts/application.chickenscript', {}, {'HTTP_IF_MODIFIED_SINCE' => last_modified_time}
|
83
|
+
last_response.status.should == 200
|
84
|
+
last_response.body.should == "chickenscript"
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should reject requests with a .." do
|
88
|
+
get '/chickenscript/../somethingbad'
|
89
|
+
last_response.status.should == 403
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "Caching" do
|
93
|
+
it "should not cache by default" do
|
94
|
+
@options.delete(:cache)
|
95
|
+
get '/chickenscripts/application.chickenscript'
|
96
|
+
last_response.headers.should_not include('Cache-Control')
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should cache by default on production" do
|
100
|
+
@options.delete(:cache)
|
101
|
+
old_rack_env = ENV['RACK_ENV']
|
102
|
+
ENV['RACK_ENV'] = 'production'
|
103
|
+
get '/chickenscripts/application.chickenscript'
|
104
|
+
ENV['RACK_ENV'] = old_rack_env
|
105
|
+
|
106
|
+
last_response.headers.should include('Cache-Control')
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should set not the cache header when the cache options is false" do
|
110
|
+
@options[:cache] = false
|
111
|
+
get '/chickenscripts/application.chickenscript'
|
112
|
+
last_response.headers.should_not include('Cache-Control')
|
113
|
+
last_response.headers.should_not include('Expires')
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should set the cache header to a duration of one week when the cache options is true" do
|
117
|
+
@options[:cache] = true
|
118
|
+
get '/chickenscripts/application.chickenscript'
|
119
|
+
last_response.headers['Cache-Control'].should == "public,max-age=604800"
|
120
|
+
last_response.headers.should include('Expires')
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'rack/coffee_compiler'
|
2
|
+
require 'rack/lobster'
|
3
|
+
require "rack/test"
|
4
|
+
|
5
|
+
include Rack::Test::Methods
|
6
|
+
|
7
|
+
describe "CoffeeCompiler" do
|
8
|
+
before do
|
9
|
+
@source_dir = File.join(File.dirname(__FILE__), 'fixtures/coffeescripts')
|
10
|
+
|
11
|
+
@options = {
|
12
|
+
:source_dir => @source_dir
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def app
|
17
|
+
options = @options
|
18
|
+
Rack::Builder.new {
|
19
|
+
use Rack::Lint
|
20
|
+
use Rack::CoffeeCompiler, options
|
21
|
+
run Rack::Lobster.new
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should compile the coffeescript" do
|
26
|
+
get '/javascripts/application.js'
|
27
|
+
last_response.body.should == CoffeeScript.compile(File.read("#{@source_dir}/application.coffee"))
|
28
|
+
last_response.status.should == 200
|
29
|
+
last_response.content_type.should == 'text/javascript'
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "when compiling a file with a syntax error" do
|
33
|
+
def do_get
|
34
|
+
get '/javascripts/syntax_error.js'
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should render a window.alert by default" do
|
38
|
+
@options.delete(:alert_on_error)
|
39
|
+
do_get
|
40
|
+
last_response.body.should include('window.alert')
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should not render a window.alert by default on production" do
|
44
|
+
@options.delete(:alert_on_error)
|
45
|
+
old_rack_env = ENV['RACK_ENV']
|
46
|
+
ENV['RACK_ENV'] = 'production'
|
47
|
+
lambda { do_get }.should raise_error(CoffeeScript::CompilationError)
|
48
|
+
ENV['RACK_ENV'] = old_rack_env
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should not render a window.alert if alert_on_error is false" do
|
52
|
+
@options[:alert_on_error] = false
|
53
|
+
lambda { do_get }.should raise_error(CoffeeScript::CompilationError)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should render a window.alert if alert_on_error is true" do
|
57
|
+
@options[:alert_on_error] = true
|
58
|
+
do_get
|
59
|
+
last_response.body.should include('window.alert')
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
console.log('hello world')
|
@@ -0,0 +1 @@
|
|
1
|
+
almost_called_a_function(1,2
|
@@ -0,0 +1 @@
|
|
1
|
+
EggScript is an imaginary language that can be compiled into ChickenScript
|
@@ -0,0 +1 @@
|
|
1
|
+
EggScript is an imaginary language that can be compiled into ChickenScript
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'rack/sass_compiler'
|
2
|
+
require 'rack/lobster'
|
3
|
+
require "rack/test"
|
4
|
+
|
5
|
+
include Rack::Test::Methods
|
6
|
+
|
7
|
+
describe "SassCompiler" do
|
8
|
+
before do
|
9
|
+
@source_dir = File.join(File.dirname(__FILE__), 'fixtures/sass')
|
10
|
+
|
11
|
+
@options = {
|
12
|
+
:source_dir => @source_dir
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def app
|
17
|
+
options = @options
|
18
|
+
Rack::Builder.new {
|
19
|
+
use Rack::Lint
|
20
|
+
use Rack::SassCompiler, options
|
21
|
+
run Rack::Lobster.new
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should compile scss" do
|
26
|
+
get '/stylesheets/style.css'
|
27
|
+
last_response.body.should ==
|
28
|
+
Sass::Engine.new(File.read("#{@source_dir}/style.scss"), :syntax => :scss).render
|
29
|
+
last_response.status.should == 200
|
30
|
+
last_response.content_type.should == 'text/css'
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should compile sass" do
|
34
|
+
@options[:syntax] = :sass
|
35
|
+
get '/stylesheets/style.css'
|
36
|
+
last_response.body.should ==
|
37
|
+
Sass::Engine.new(File.read("#{@source_dir}/style.sass"), :syntax => :sass).render
|
38
|
+
last_response.status.should == 200
|
39
|
+
last_response.content_type.should == 'text/css'
|
40
|
+
end
|
41
|
+
end
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rack-asset-compiler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Jonathan Baudanza
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-02-25 00:00:00 -08:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rack
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
description: |
|
36
|
+
rack-asset-compiler is a Rack middleware that provides a generic interface for compiling static files, such as Sass or CoffeeScript files.
|
37
|
+
|
38
|
+
rack-asset-compiler does not use any local file storage and makes use of caching headers such as "Cache-Control" and "If-Modified-Since". This makes it ideal for running on read-only filesystem systems such as Heroku.
|
39
|
+
|
40
|
+
email: jon@jonb.org
|
41
|
+
executables: []
|
42
|
+
|
43
|
+
extensions: []
|
44
|
+
|
45
|
+
extra_rdoc_files: []
|
46
|
+
|
47
|
+
files:
|
48
|
+
- rack-asset-compiler.gemspec
|
49
|
+
- Rakefile
|
50
|
+
- Readme.md
|
51
|
+
- LICENSE.txt
|
52
|
+
- lib/rack/asset_compiler.rb
|
53
|
+
- lib/rack/coffee_compiler.rb
|
54
|
+
- lib/rack/sass_compiler.rb
|
55
|
+
- spec/asset_compiler_spec.rb
|
56
|
+
- spec/coffee_compiler_spec.rb
|
57
|
+
- spec/fixtures/coffeescripts/application.coffee
|
58
|
+
- spec/fixtures/coffeescripts/syntax_error.coffee
|
59
|
+
- spec/fixtures/eggscripts/application.eggscript
|
60
|
+
- spec/fixtures/eggscripts/subdir/application.eggscript
|
61
|
+
- spec/fixtures/sass/style.sass
|
62
|
+
- spec/fixtures/sass/style.scss
|
63
|
+
- spec/sass_compiler_spec.rb
|
64
|
+
- examples/jasmine_config.rb
|
65
|
+
has_rdoc: true
|
66
|
+
homepage: http://www.github.com/jbaudanza/rack-asset-compiler
|
67
|
+
licenses: []
|
68
|
+
|
69
|
+
post_install_message:
|
70
|
+
rdoc_options: []
|
71
|
+
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
hash: 3
|
80
|
+
segments:
|
81
|
+
- 0
|
82
|
+
version: "0"
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
hash: 3
|
89
|
+
segments:
|
90
|
+
- 0
|
91
|
+
version: "0"
|
92
|
+
requirements: []
|
93
|
+
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 1.5.0
|
96
|
+
signing_key:
|
97
|
+
specification_version: 3
|
98
|
+
summary: Rack Middleware to facilitate the generic compiling static assets.
|
99
|
+
test_files: []
|
100
|
+
|