asset-trip 0.1.0
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/.gitignore +2 -0
- data/History.txt +6 -0
- data/MIT-LICENSE.txt +19 -0
- data/README.rdoc +27 -0
- data/Rakefile +12 -0
- data/Thorfile +110 -0
- data/asset-trip.gemspec +107 -0
- data/init.rb +3 -0
- data/lib/asset_trip/asset.rb +82 -0
- data/lib/asset_trip/compressor.rb +36 -0
- data/lib/asset_trip/config.rb +60 -0
- data/lib/asset_trip/file_writer.rb +17 -0
- data/lib/asset_trip/helper.rb +83 -0
- data/lib/asset_trip/javascript.rb +29 -0
- data/lib/asset_trip/load_path.rb +39 -0
- data/lib/asset_trip/manifest.rb +40 -0
- data/lib/asset_trip/manifest_writer.rb +35 -0
- data/lib/asset_trip/memoizable.rb +28 -0
- data/lib/asset_trip/middleware.rb +109 -0
- data/lib/asset_trip/ssl_stylesheet.rb +15 -0
- data/lib/asset_trip/stylesheet.rb +44 -0
- data/lib/asset_trip/url_rewriter.rb +82 -0
- data/lib/asset_trip.rb +66 -0
- data/spec/asset_trip/asset_spec.rb +47 -0
- data/spec/asset_trip/compressor_spec.rb +46 -0
- data/spec/asset_trip/config_spec.rb +61 -0
- data/spec/asset_trip/helper_spec.rb +221 -0
- data/spec/asset_trip/javascript_spec.rb +24 -0
- data/spec/asset_trip/load_path_spec.rb +61 -0
- data/spec/asset_trip/manifest_writer_spec.rb +32 -0
- data/spec/asset_trip/middleware_spec.rb +72 -0
- data/spec/asset_trip/stylesheet_spec.rb +51 -0
- data/spec/asset_trip/url_rewriter_spec.rb +166 -0
- data/spec/asset_trip_spec.rb +13 -0
- data/spec/fixtures/app/javascripts/main/new.js +1 -0
- data/spec/fixtures/app/javascripts/main.js +1 -0
- data/spec/fixtures/app/javascripts/signup.js +1 -0
- data/spec/fixtures/app/stylesheets/new.css +0 -0
- data/spec/fixtures/config/asset_trip/assets.rb +0 -0
- data/spec/integration/bundle_spec.rb +243 -0
- data/spec/integration/prune_spec.rb +53 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/support/core_extensions.rb +13 -0
- data/spec/support/helpers.rb +33 -0
- data/spec/support/matchers.rb +67 -0
- data/spec/support/path_utils.rb +45 -0
- data/spec/support/sandbox_helper.rb +19 -0
- data/tasks/asset_trip.rake +11 -0
- data/vendor/yuicompressor-2.4.2.jar +0 -0
- metadata +128 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
module AssetTrip
|
2
|
+
class ManifestWriter
|
3
|
+
|
4
|
+
def initialize(assets)
|
5
|
+
@assets = assets
|
6
|
+
end
|
7
|
+
|
8
|
+
def write!
|
9
|
+
FileWriter.new(path).write!(contents)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def contents
|
15
|
+
source = StringIO.new
|
16
|
+
|
17
|
+
source.puts "module AssetTrip"
|
18
|
+
source.puts " @manifest = Manifest.new"
|
19
|
+
|
20
|
+
@assets.each do |asset|
|
21
|
+
source.puts " @manifest[#{asset.name.inspect}] = #{asset.md5sum.first(11).inspect}"
|
22
|
+
end
|
23
|
+
|
24
|
+
source.puts "end"
|
25
|
+
|
26
|
+
return source.string
|
27
|
+
end
|
28
|
+
|
29
|
+
def path
|
30
|
+
AssetTrip.app_root.join("config", "asset_trip", "manifest.rb")
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module AssetTrip
|
2
|
+
module Memoizable
|
3
|
+
|
4
|
+
def self.memoized_ivar_for(symbol)
|
5
|
+
"@_memoized_#{symbol.to_s.sub(/\?\Z/, '_query').sub(/!\Z/, '_bang')}".to_sym
|
6
|
+
end
|
7
|
+
|
8
|
+
def memoize(symbol)
|
9
|
+
original_method = :"_unmemoized_#{symbol}"
|
10
|
+
memoized_ivar = AssetTrip::Memoizable.memoized_ivar_for(symbol)
|
11
|
+
|
12
|
+
raise "Already memoized #{symbol}" if method_defined?(original_method)
|
13
|
+
alias_method original_method, symbol
|
14
|
+
|
15
|
+
class_eval <<-EOS, __FILE__, __LINE__
|
16
|
+
def #{symbol}(*args) # def mime_type(*args)
|
17
|
+
if !defined?(#{memoized_ivar}) # if !defined?(@_memoized_mime_type)
|
18
|
+
#{memoized_ivar} = #{original_method}(*args) # @_memoized_mime_type = _unmemoized_mime_type(*args)
|
19
|
+
end # end
|
20
|
+
#{memoized_ivar} # @_memoized_mime_type
|
21
|
+
end # end
|
22
|
+
EOS
|
23
|
+
|
24
|
+
private symbol if private_method_defined?(original_method)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# This is based on Rack::Static and Rack::File
|
2
|
+
module AssetTrip
|
3
|
+
class Middleware
|
4
|
+
URL_PREFIX = "/__asset_trip__"
|
5
|
+
|
6
|
+
def initialize(app)
|
7
|
+
@app = app
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
dup._call(env)
|
12
|
+
end
|
13
|
+
|
14
|
+
def _call(env)
|
15
|
+
@env = env
|
16
|
+
|
17
|
+
if matches_url_prefix?
|
18
|
+
process
|
19
|
+
else
|
20
|
+
pass
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def each
|
25
|
+
File.open(path, "rb") do |file|
|
26
|
+
while part = file.read(8192)
|
27
|
+
yield part
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def matches_url_prefix?
|
35
|
+
path_info.index(URL_PREFIX) == 0
|
36
|
+
end
|
37
|
+
|
38
|
+
def process
|
39
|
+
return forbidden if path_info.include?("..")
|
40
|
+
|
41
|
+
if path.file? && path.readable?
|
42
|
+
serve_file
|
43
|
+
else
|
44
|
+
not_found
|
45
|
+
end
|
46
|
+
rescue UnknownAssetError
|
47
|
+
return not_found
|
48
|
+
end
|
49
|
+
|
50
|
+
def pass
|
51
|
+
@app.call(@env)
|
52
|
+
end
|
53
|
+
|
54
|
+
def path
|
55
|
+
@path ||= AssetTrip.config.resolve_file(asset_type.to_sym, filename)
|
56
|
+
end
|
57
|
+
|
58
|
+
def filename
|
59
|
+
@filename ||= path_info[("/#{URL_PREFIX}/#{asset_type}".size)..-1]
|
60
|
+
end
|
61
|
+
|
62
|
+
def path_info
|
63
|
+
@path_info ||= Rack::Utils.unescape(@env["PATH_INFO"])
|
64
|
+
end
|
65
|
+
|
66
|
+
def asset_type
|
67
|
+
path_parts[2]
|
68
|
+
end
|
69
|
+
|
70
|
+
def path_parts
|
71
|
+
path_info.split("/")
|
72
|
+
end
|
73
|
+
|
74
|
+
def serve_file
|
75
|
+
# NOTE:
|
76
|
+
# We check via File::size? whether this file provides size info
|
77
|
+
# via stat (e.g. /proc files often don't), otherwise we have to
|
78
|
+
# figure it out by reading the whole file into memory. And while
|
79
|
+
# we're at it we also use this as body then.
|
80
|
+
if size = File.size?(@path)
|
81
|
+
body = self
|
82
|
+
else
|
83
|
+
body = [File.read(@path)]
|
84
|
+
size = Rack::Utils.bytesize(body.first)
|
85
|
+
end
|
86
|
+
|
87
|
+
[200, {
|
88
|
+
"Last-Modified" => File.mtime(@path).httpdate,
|
89
|
+
"Content-Type" => Rack::Mime.mime_type(File.extname(@path), 'text/plain'),
|
90
|
+
"Content-Length" => size.to_s
|
91
|
+
}, body]
|
92
|
+
end
|
93
|
+
|
94
|
+
def forbidden
|
95
|
+
body = "Forbidden\n"
|
96
|
+
[403, {"Content-Type" => "text/plain",
|
97
|
+
"Content-Length" => body.size.to_s},
|
98
|
+
[body]]
|
99
|
+
end
|
100
|
+
|
101
|
+
def not_found
|
102
|
+
body = "File not found: #{@path_info}\n"
|
103
|
+
[404, {"Content-Type" => "text/plain",
|
104
|
+
"Content-Length" => body.size.to_s},
|
105
|
+
[body]]
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module AssetTrip
|
2
|
+
class Stylesheet < Asset
|
3
|
+
|
4
|
+
def name
|
5
|
+
"#{@name}.css"
|
6
|
+
end
|
7
|
+
|
8
|
+
def ssl_stylesheet
|
9
|
+
SSLStylesheet.new(@config, @name, @files)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def joined_contents
|
15
|
+
paths.map do |path|
|
16
|
+
url_rewriter(path).rewrite(File.read(path))
|
17
|
+
end.join("\n\n")
|
18
|
+
end
|
19
|
+
|
20
|
+
def compressor
|
21
|
+
Compressor.new("css")
|
22
|
+
end
|
23
|
+
|
24
|
+
def url_rewriter(filesystem_path)
|
25
|
+
public_path = AssetTrip.app_root.join("public")
|
26
|
+
|
27
|
+
if filesystem_path.to_s.starts_with?(public_path)
|
28
|
+
foo = Pathname.new("/").join(filesystem_path.relative_path_from(public_path))
|
29
|
+
UrlRewriter.new("http", foo)
|
30
|
+
else
|
31
|
+
UrlRewriter.new("http")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def asset_type
|
36
|
+
:stylesheets
|
37
|
+
end
|
38
|
+
|
39
|
+
def extension
|
40
|
+
".css"
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require "action_controller"
|
2
|
+
require "action_view"
|
3
|
+
require "ostruct"
|
4
|
+
require "uri"
|
5
|
+
|
6
|
+
module AssetTrip
|
7
|
+
class UrlRewriter
|
8
|
+
include ActionView::Helpers::AssetTagHelper
|
9
|
+
|
10
|
+
def initialize(scheme, stylesheet_path = nil)
|
11
|
+
@scheme = scheme
|
12
|
+
@stylesheet_path = stylesheet_path
|
13
|
+
|
14
|
+
setup_fake_controller_for_asset_host_computation
|
15
|
+
end
|
16
|
+
|
17
|
+
def rewrite(contents)
|
18
|
+
contents.gsub(/url *\(([^\)]+)\)/) do
|
19
|
+
"url(#{add_asset_host_to_path($1)})"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def setup_fake_controller_for_asset_host_computation
|
26
|
+
environment = {}
|
27
|
+
environment["HTTPS"] = "on" if @scheme == "https"
|
28
|
+
@controller = OpenStruct.new(:request => ActionController::Request.new(environment)) # Used by Rails compute_asset_host method from ActionView::Helpers::AssetTagHelper
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_asset_host_to_path(path)
|
32
|
+
strip_quotes!(path)
|
33
|
+
|
34
|
+
if prepend_asset_host?(path)
|
35
|
+
path = rewrite_relative_path(path) unless @stylesheet_path.blank?
|
36
|
+
URI::Generic.build(uri_components(path)).to_s
|
37
|
+
else
|
38
|
+
path
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def uri_components(path)
|
43
|
+
opts = { :path => path }
|
44
|
+
|
45
|
+
if (asset_id = rails_asset_id(path)).present?
|
46
|
+
opts[:query] = asset_id
|
47
|
+
end
|
48
|
+
|
49
|
+
if (host = compute_asset_host(path)).present?
|
50
|
+
opts[:host] = strip_scheme(host)
|
51
|
+
opts[:scheme] = @scheme
|
52
|
+
end
|
53
|
+
|
54
|
+
return opts
|
55
|
+
end
|
56
|
+
|
57
|
+
def rewrite_relative_path(relative_url)
|
58
|
+
if relative_url.starts_with?("/")
|
59
|
+
return relative_url
|
60
|
+
else
|
61
|
+
Pathname.new(File.join(@stylesheet_path.dirname, relative_url)).cleanpath
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def prepend_asset_host?(path)
|
66
|
+
uri = URI.parse(path)
|
67
|
+
|
68
|
+
uri.relative? &&
|
69
|
+
File.extname(uri.path) != '.htc'
|
70
|
+
end
|
71
|
+
|
72
|
+
def strip_scheme(host)
|
73
|
+
host.gsub(/^[a-z]+:\/\//, '')
|
74
|
+
end
|
75
|
+
|
76
|
+
def strip_quotes!(path)
|
77
|
+
path.gsub!(/^\s*['"]*/, "")
|
78
|
+
path.gsub!(/['"]*\s*$/, "")
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
data/lib/asset_trip.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require "active_support"
|
2
|
+
|
3
|
+
module AssetTrip
|
4
|
+
autoload :Asset, "asset_trip/asset"
|
5
|
+
autoload :Compressor, "asset_trip/compressor"
|
6
|
+
autoload :Config, "asset_trip/config"
|
7
|
+
autoload :FileWriter, "asset_trip/file_writer"
|
8
|
+
autoload :Helper, "asset_trip/helper"
|
9
|
+
autoload :Javascript, "asset_trip/javascript"
|
10
|
+
autoload :LoadPath, "asset_trip/load_path"
|
11
|
+
autoload :Manifest, "asset_trip/manifest"
|
12
|
+
autoload :ManifestWriter, "asset_trip/manifest_writer"
|
13
|
+
autoload :Middleware, "asset_trip/middleware"
|
14
|
+
autoload :Memoizable, "asset_trip/memoizable"
|
15
|
+
autoload :SSLStylesheet, "asset_trip/ssl_stylesheet"
|
16
|
+
autoload :Stylesheet, "asset_trip/stylesheet"
|
17
|
+
autoload :UrlRewriter, "asset_trip/url_rewriter"
|
18
|
+
|
19
|
+
class CompressorError < StandardError
|
20
|
+
end
|
21
|
+
|
22
|
+
class UnknownAssetError < StandardError
|
23
|
+
end
|
24
|
+
|
25
|
+
class NoManifestError < StandardError
|
26
|
+
end
|
27
|
+
|
28
|
+
VERSION = "0.1.0"
|
29
|
+
|
30
|
+
mattr_accessor :bundle
|
31
|
+
self.bundle = true
|
32
|
+
|
33
|
+
def self.bundle!
|
34
|
+
config.bundle!
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.prune!
|
38
|
+
manifest.prune!
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.config
|
42
|
+
@config ||= Config.from_file(config_path)
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.manifest
|
46
|
+
raise NoManifestError if @manifest.nil?
|
47
|
+
@manifest
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.app_root
|
51
|
+
Pathname.new(".").expand_path
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.root
|
55
|
+
Pathname.new(__FILE__).dirname.join("..").expand_path
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.assets_path
|
59
|
+
app_root.join("public", "assets")
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.config_path
|
63
|
+
app_root.join("config", "asset_trip")
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe AssetTrip::Asset do
|
4
|
+
before do
|
5
|
+
AssetTrip::Compressor.stub!(:new => DummyCompressor.new)
|
6
|
+
File.stub!(:read => "contents")
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#bundle!" do
|
10
|
+
it "splits the MD5 into two nested directories" do
|
11
|
+
path = AssetTrip.assets_path.join("d4", "1d8cd98f0", "asset.js")
|
12
|
+
AssetTrip::FileWriter.should_receive(:new).with(path).and_return(stub(:write! => nil))
|
13
|
+
asset = AssetTrip::Javascript.new(stub, "asset")
|
14
|
+
asset.bundle!
|
15
|
+
end
|
16
|
+
|
17
|
+
it "writes the contents to the file" do
|
18
|
+
writer = stub
|
19
|
+
writer.should_receive(:write!).with("contents")
|
20
|
+
AssetTrip::FileWriter.stub!(:new => writer)
|
21
|
+
asset = AssetTrip::Javascript.new(stub(:resolve_file => "foo.js"), "asset", [Pathname.new("foo.js")])
|
22
|
+
asset.bundle!
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#md5sum" do
|
27
|
+
it "calculates the MD5 if there are no files" do
|
28
|
+
asset = AssetTrip::Javascript.new(stub, "asset")
|
29
|
+
asset.md5sum.should == "d41d8cd98f00b204e9800998ecf8427e"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "calculates the MD5 for one file" do
|
33
|
+
asset = AssetTrip::Javascript.new(stub(:resolve_file => "foo"), "asset") do
|
34
|
+
include "foo"
|
35
|
+
end
|
36
|
+
asset.md5sum.should == "98bf7d8c15784f0a3d63204441e1e2aa"
|
37
|
+
end
|
38
|
+
|
39
|
+
it "calculates the MD5 for multiple file" do
|
40
|
+
asset = AssetTrip::Javascript.new(stub(:resolve_file => "foo"), "asset") do
|
41
|
+
include "foo"
|
42
|
+
include "bar"
|
43
|
+
end
|
44
|
+
asset.md5sum.should == "237c43254a0799392cac71f795d9250e"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe AssetTrip::Compressor do
|
4
|
+
let(:compressor) do
|
5
|
+
AssetTrip::Compressor.new(Pathname.new("css"))
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#compress" do
|
9
|
+
it "builds a command with the proper --type option" do
|
10
|
+
POpen4.should_receive(:popen4).with(/--type css/).and_return(stub(:success? => true))
|
11
|
+
compressor.compress("a { color: red }")
|
12
|
+
end
|
13
|
+
|
14
|
+
it "builds a command to run the vendored jar file" do
|
15
|
+
POpen4.should_receive(:popen4).with(/java -jar .*vendor\/yuicompressor-2.4.2.jar/).and_return(stub(:success? => true))
|
16
|
+
compressor.compress("a { color: red }")
|
17
|
+
end
|
18
|
+
|
19
|
+
it "sends the uncompressed contents via STDIN" do
|
20
|
+
stdin = stub(:close => nil)
|
21
|
+
|
22
|
+
POpen4.stub!(:popen4) do |command, block|
|
23
|
+
block.call(stub(:read => "STDOUT"), stub(:read => "STDERR"), stdin)
|
24
|
+
stub(:success? => true)
|
25
|
+
end
|
26
|
+
|
27
|
+
stdin.should_receive(:puts).with("a { color: red }")
|
28
|
+
compressor.compress("a { color: red }").should == "STDOUT"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "returns the STDOUT from the java process" do
|
32
|
+
POpen4.stub!(:popen4) do |command, block|
|
33
|
+
block.call(stub(:read => "STDOUT"), stub(:read => "STDERR"), stub(:puts => nil, :close => nil))
|
34
|
+
stub(:success? => true)
|
35
|
+
end
|
36
|
+
compressor.compress("a { color: red }").should == "STDOUT"
|
37
|
+
end
|
38
|
+
|
39
|
+
it "raises a CompressorError if the java process is not successful" do
|
40
|
+
POpen4.stub!(:popen4 => stub(:success? => false))
|
41
|
+
lambda {
|
42
|
+
compressor.compress("a { color: red }")
|
43
|
+
}.should raise_error(AssetTrip::CompressorError)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe AssetTrip::Config do
|
4
|
+
# TODO: it would be great to avoid needing this for these specs
|
5
|
+
setup_sandbox_app!
|
6
|
+
|
7
|
+
it "can bundle files included with the file extension" do
|
8
|
+
config = AssetTrip::Config.new do
|
9
|
+
js_asset "signup" do
|
10
|
+
include "main.js"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
asset_config = config.assets.first
|
15
|
+
asset_config.paths.should == [app_javascript("main.js")]
|
16
|
+
end
|
17
|
+
|
18
|
+
it "can bundle files in subdirectories of the load path" do
|
19
|
+
config = AssetTrip::Config.new do
|
20
|
+
js_asset "signup" do
|
21
|
+
include "main/new"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
asset_config = config.assets.first
|
26
|
+
asset_config.paths.should == [app_javascript("main", "new.js")]
|
27
|
+
end
|
28
|
+
|
29
|
+
it "supports writing an asset to a subdirectory" do
|
30
|
+
config = AssetTrip::Config.new do
|
31
|
+
js_asset "signup/foo" do
|
32
|
+
include "main.js"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
asset_config = config.assets.first
|
37
|
+
asset_config.name.should == "signup/foo.js"
|
38
|
+
end
|
39
|
+
|
40
|
+
it "supports adding to the JS load paths" do
|
41
|
+
config = AssetTrip::Config.new do
|
42
|
+
load_paths[:javascripts] << "foo"
|
43
|
+
end
|
44
|
+
|
45
|
+
config.load_paths[:javascripts].should == AssetTrip::LoadPath.new([
|
46
|
+
Pathname.new("app/javascripts"),
|
47
|
+
Pathname.new("foo")
|
48
|
+
])
|
49
|
+
end
|
50
|
+
|
51
|
+
it "supports adding to the CSS load paths" do
|
52
|
+
config = AssetTrip::Config.new do
|
53
|
+
load_paths[:stylesheets] << "foo"
|
54
|
+
end
|
55
|
+
|
56
|
+
config.load_paths[:stylesheets].should == AssetTrip::LoadPath.new([
|
57
|
+
Pathname.new("app/stylesheets"),
|
58
|
+
Pathname.new("foo")
|
59
|
+
])
|
60
|
+
end
|
61
|
+
end
|