asset-trip 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/.gitignore
ADDED
data/History.txt
ADDED
data/MIT-LICENSE.txt
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2008-2009 Bryan Helmkamp
|
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/README.rdoc
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
= Asset Trip
|
2
|
+
|
3
|
+
Asset Trip bundles JavaScript and CSS files at deploy time. The assets are
|
4
|
+
then served from a Git-esque object store in the application's public
|
5
|
+
directory.
|
6
|
+
|
7
|
+
Development of Asset Trip was kindly sponsored by Weplay[http://www.weplay.com]
|
8
|
+
|
9
|
+
== Features and Benefits
|
10
|
+
|
11
|
+
* Reliable cache busting strategy, even during graceful deploys
|
12
|
+
* Develop in app/, deploy to public/
|
13
|
+
* Efficient compression of JavaScript and CSS from the YUI Compressor
|
14
|
+
* Fast at runtime. No bundling or File mtime checking slowing down your
|
15
|
+
production requests
|
16
|
+
* Simple, powerful all-Ruby configuration files
|
17
|
+
|
18
|
+
== Hat tips
|
19
|
+
|
20
|
+
* bundle_fu
|
21
|
+
* asset_packager
|
22
|
+
* bundler
|
23
|
+
* sprockets
|
24
|
+
* git
|
25
|
+
* asset-hosting-with-minimum-ssl
|
26
|
+
* http://carsonified.com/blog/features/webapps/serving-javascript-fast/
|
27
|
+
|
data/Rakefile
ADDED
data/Thorfile
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
module GemHelpers
|
2
|
+
|
3
|
+
def generate_gemspec
|
4
|
+
$LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), "lib")))
|
5
|
+
require "asset_trip"
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = "asset-trip"
|
9
|
+
s.version = AssetTrip::VERSION
|
10
|
+
s.author = "Bryan Helmkamp"
|
11
|
+
s.email = "bryan@brynary.com"
|
12
|
+
s.homepage = "http://github.com/brynary/asset-trip"
|
13
|
+
s.summary = "Rails asset bundling plugin that will expand your mind"
|
14
|
+
s.description = <<-EOS.strip
|
15
|
+
Asset Trip bundles JavaScript and CSS files at deploy time. The assets are
|
16
|
+
then served from a Git-esque object store in the application's public
|
17
|
+
directory.
|
18
|
+
EOS
|
19
|
+
|
20
|
+
require "git"
|
21
|
+
repo = Git.open(".")
|
22
|
+
|
23
|
+
s.files = normalize_files(repo.ls_files.keys - repo.lib.ignored_files)
|
24
|
+
s.test_files = normalize_files(Dir['spec/**/*.rb'] - repo.lib.ignored_files)
|
25
|
+
|
26
|
+
s.has_rdoc = true
|
27
|
+
s.extra_rdoc_files = %w[History.txt README.rdoc MIT-LICENSE.txt]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def normalize_files(array)
|
32
|
+
# only keep files, no directories, and sort
|
33
|
+
array.select do |path|
|
34
|
+
File.file?(path)
|
35
|
+
end.sort
|
36
|
+
end
|
37
|
+
|
38
|
+
# Adds extra space when outputting an array. This helps create better version
|
39
|
+
# control diffs, because otherwise it is all on the same line.
|
40
|
+
def prettyify_array(gemspec_ruby, array_name)
|
41
|
+
gemspec_ruby.gsub(/s\.#{array_name.to_s} = \[.+?\]/) do |match|
|
42
|
+
leadin, files = match[0..-2].split("[")
|
43
|
+
leadin + "[\n #{files.split(",").join(",\n ")}\n ]"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def read_gemspec
|
48
|
+
@read_gemspec ||= eval(File.read("asset-trip.gemspec"))
|
49
|
+
end
|
50
|
+
|
51
|
+
def sh(command)
|
52
|
+
puts command
|
53
|
+
system command
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class Default < Thor
|
58
|
+
include GemHelpers
|
59
|
+
|
60
|
+
desc "gemspec", "Regenerate asset-trip.gemspec"
|
61
|
+
def gemspec
|
62
|
+
File.open("asset-trip.gemspec", "w") do |file|
|
63
|
+
gemspec_ruby = generate_gemspec.to_ruby
|
64
|
+
gemspec_ruby = prettyify_array(gemspec_ruby, :files)
|
65
|
+
gemspec_ruby = prettyify_array(gemspec_ruby, :test_files)
|
66
|
+
gemspec_ruby = prettyify_array(gemspec_ruby, :extra_rdoc_files)
|
67
|
+
|
68
|
+
file.write gemspec_ruby
|
69
|
+
end
|
70
|
+
|
71
|
+
puts "Wrote gemspec to asset-trip.gemspec"
|
72
|
+
read_gemspec.validate
|
73
|
+
end
|
74
|
+
|
75
|
+
desc "build", "Build a asset-trip gem"
|
76
|
+
def build
|
77
|
+
sh "gem build asset-trip.gemspec"
|
78
|
+
FileUtils.mkdir_p "pkg"
|
79
|
+
FileUtils.mv read_gemspec.file_name, "pkg"
|
80
|
+
end
|
81
|
+
|
82
|
+
desc "install", "Install the latest built gem"
|
83
|
+
def install
|
84
|
+
sh "gem install --local pkg/#{read_gemspec.file_name}"
|
85
|
+
end
|
86
|
+
|
87
|
+
desc "release", "Release the current branch to GitHub and Gemcutter"
|
88
|
+
def release
|
89
|
+
gemspec
|
90
|
+
build
|
91
|
+
Release.new.tag
|
92
|
+
Release.new.gem
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class Release < Thor
|
97
|
+
include GemHelpers
|
98
|
+
|
99
|
+
desc "tag", "Tag the gem on the origin server"
|
100
|
+
def tag
|
101
|
+
release_tag = "v#{read_gemspec.version}"
|
102
|
+
sh "git tag -a #{release_tag} -m 'Tagging #{release_tag}'"
|
103
|
+
sh "git push origin #{release_tag}"
|
104
|
+
end
|
105
|
+
|
106
|
+
desc "gem", "Push the gem to Gemcutter"
|
107
|
+
def gem
|
108
|
+
sh "gem push pkg/#{read_gemspec.file_name}"
|
109
|
+
end
|
110
|
+
end
|
data/asset-trip.gemspec
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{asset-trip}
|
5
|
+
s.version = "0.1.0"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Bryan Helmkamp"]
|
9
|
+
s.date = %q{2009-11-05}
|
10
|
+
s.description = %q{Asset Trip bundles JavaScript and CSS files at deploy time. The assets are
|
11
|
+
then served from a Git-esque object store in the application's public
|
12
|
+
directory.}
|
13
|
+
s.email = %q{bryan@brynary.com}
|
14
|
+
s.extra_rdoc_files = [
|
15
|
+
"History.txt",
|
16
|
+
"README.rdoc",
|
17
|
+
"MIT-LICENSE.txt"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".gitignore",
|
21
|
+
"History.txt",
|
22
|
+
"MIT-LICENSE.txt",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"Thorfile",
|
26
|
+
"asset-trip.gemspec",
|
27
|
+
"init.rb",
|
28
|
+
"lib/asset_trip.rb",
|
29
|
+
"lib/asset_trip/asset.rb",
|
30
|
+
"lib/asset_trip/compressor.rb",
|
31
|
+
"lib/asset_trip/config.rb",
|
32
|
+
"lib/asset_trip/file_writer.rb",
|
33
|
+
"lib/asset_trip/helper.rb",
|
34
|
+
"lib/asset_trip/javascript.rb",
|
35
|
+
"lib/asset_trip/load_path.rb",
|
36
|
+
"lib/asset_trip/manifest.rb",
|
37
|
+
"lib/asset_trip/manifest_writer.rb",
|
38
|
+
"lib/asset_trip/memoizable.rb",
|
39
|
+
"lib/asset_trip/middleware.rb",
|
40
|
+
"lib/asset_trip/ssl_stylesheet.rb",
|
41
|
+
"lib/asset_trip/stylesheet.rb",
|
42
|
+
"lib/asset_trip/url_rewriter.rb",
|
43
|
+
"spec/asset_trip/asset_spec.rb",
|
44
|
+
"spec/asset_trip/compressor_spec.rb",
|
45
|
+
"spec/asset_trip/config_spec.rb",
|
46
|
+
"spec/asset_trip/helper_spec.rb",
|
47
|
+
"spec/asset_trip/javascript_spec.rb",
|
48
|
+
"spec/asset_trip/load_path_spec.rb",
|
49
|
+
"spec/asset_trip/manifest_writer_spec.rb",
|
50
|
+
"spec/asset_trip/middleware_spec.rb",
|
51
|
+
"spec/asset_trip/stylesheet_spec.rb",
|
52
|
+
"spec/asset_trip/url_rewriter_spec.rb",
|
53
|
+
"spec/asset_trip_spec.rb",
|
54
|
+
"spec/fixtures/app/javascripts/main.js",
|
55
|
+
"spec/fixtures/app/javascripts/main/new.js",
|
56
|
+
"spec/fixtures/app/javascripts/signup.js",
|
57
|
+
"spec/fixtures/app/stylesheets/new.css",
|
58
|
+
"spec/fixtures/config/asset_trip/assets.rb",
|
59
|
+
"spec/integration/bundle_spec.rb",
|
60
|
+
"spec/integration/prune_spec.rb",
|
61
|
+
"spec/spec.opts",
|
62
|
+
"spec/spec_helper.rb",
|
63
|
+
"spec/support/core_extensions.rb",
|
64
|
+
"spec/support/helpers.rb",
|
65
|
+
"spec/support/matchers.rb",
|
66
|
+
"spec/support/path_utils.rb",
|
67
|
+
"spec/support/sandbox_helper.rb",
|
68
|
+
"tasks/asset_trip.rake",
|
69
|
+
"vendor/yuicompressor-2.4.2.jar"
|
70
|
+
]
|
71
|
+
s.homepage = %q{http://github.com/brynary/asset-trip}
|
72
|
+
s.require_paths = ["lib"]
|
73
|
+
s.rubygems_version = %q{1.3.5}
|
74
|
+
s.summary = %q{Rails asset bundling plugin that will expand your mind}
|
75
|
+
s.test_files = [
|
76
|
+
"spec/asset_trip/asset_spec.rb",
|
77
|
+
"spec/asset_trip/compressor_spec.rb",
|
78
|
+
"spec/asset_trip/config_spec.rb",
|
79
|
+
"spec/asset_trip/helper_spec.rb",
|
80
|
+
"spec/asset_trip/javascript_spec.rb",
|
81
|
+
"spec/asset_trip/load_path_spec.rb",
|
82
|
+
"spec/asset_trip/manifest_writer_spec.rb",
|
83
|
+
"spec/asset_trip/middleware_spec.rb",
|
84
|
+
"spec/asset_trip/stylesheet_spec.rb",
|
85
|
+
"spec/asset_trip/url_rewriter_spec.rb",
|
86
|
+
"spec/asset_trip_spec.rb",
|
87
|
+
"spec/fixtures/config/asset_trip/assets.rb",
|
88
|
+
"spec/integration/bundle_spec.rb",
|
89
|
+
"spec/integration/prune_spec.rb",
|
90
|
+
"spec/spec_helper.rb",
|
91
|
+
"spec/support/core_extensions.rb",
|
92
|
+
"spec/support/helpers.rb",
|
93
|
+
"spec/support/matchers.rb",
|
94
|
+
"spec/support/path_utils.rb",
|
95
|
+
"spec/support/sandbox_helper.rb"
|
96
|
+
]
|
97
|
+
|
98
|
+
if s.respond_to? :specification_version then
|
99
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
100
|
+
s.specification_version = 3
|
101
|
+
|
102
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
103
|
+
else
|
104
|
+
end
|
105
|
+
else
|
106
|
+
end
|
107
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require "digest"
|
2
|
+
|
3
|
+
module AssetTrip
|
4
|
+
class Asset
|
5
|
+
extend Memoizable
|
6
|
+
|
7
|
+
attr_reader :files
|
8
|
+
|
9
|
+
def initialize(config, name, files = [], &block)
|
10
|
+
@config = config
|
11
|
+
@name = name
|
12
|
+
@files = files
|
13
|
+
|
14
|
+
instance_eval(&block) if block_given?
|
15
|
+
end
|
16
|
+
|
17
|
+
def contents
|
18
|
+
compressor.compress(joined_contents)
|
19
|
+
end
|
20
|
+
|
21
|
+
def paths
|
22
|
+
files.map do |file|
|
23
|
+
@config.resolve_file(asset_type, file)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def bundle!
|
28
|
+
if expired?
|
29
|
+
FileWriter.new(path).write!(contents)
|
30
|
+
else
|
31
|
+
last_package = packaged_files.sort_by { |path| File.mtime(path) }.last
|
32
|
+
@md5sum = File.dirname(last_package).last(12).gsub(/\//, '')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def md5sum
|
37
|
+
@md5sum ||= Digest::MD5.hexdigest(contents)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def expired?
|
43
|
+
packaged_files.empty? || generated_at <= last_change_at
|
44
|
+
end
|
45
|
+
|
46
|
+
def generated_at
|
47
|
+
packaged_file_mtimes.last
|
48
|
+
end
|
49
|
+
|
50
|
+
def packaged_file_mtimes
|
51
|
+
@packaged_file_mtimes ||= packaged_files.map { |path| File.mtime(path) }.sort
|
52
|
+
end
|
53
|
+
|
54
|
+
def packaged_files
|
55
|
+
Dir[AssetTrip.assets_path.join("**", name)]
|
56
|
+
end
|
57
|
+
|
58
|
+
def last_change_at
|
59
|
+
mtimes.last
|
60
|
+
end
|
61
|
+
|
62
|
+
def mtimes
|
63
|
+
@mtimes ||= paths.map { |path| File.mtime(path) }.sort
|
64
|
+
end
|
65
|
+
|
66
|
+
def include(name)
|
67
|
+
name += extension unless name.ends_with?(extension)
|
68
|
+
files << name
|
69
|
+
end
|
70
|
+
|
71
|
+
def path
|
72
|
+
dir.join(name)
|
73
|
+
end
|
74
|
+
|
75
|
+
def dir
|
76
|
+
part1 = md5sum[0..1]
|
77
|
+
part2 = md5sum[2..10]
|
78
|
+
AssetTrip.assets_path.join(part1, part2)
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'popen4'
|
2
|
+
|
3
|
+
module AssetTrip
|
4
|
+
class Compressor
|
5
|
+
|
6
|
+
def initialize(type)
|
7
|
+
@type = type
|
8
|
+
end
|
9
|
+
|
10
|
+
def compress(contents)
|
11
|
+
out = nil
|
12
|
+
err = nil
|
13
|
+
|
14
|
+
status = POpen4.popen4(command) do |stdout, stderr, stdin, pid|
|
15
|
+
stdin.puts contents
|
16
|
+
stdin.close
|
17
|
+
out = stdout.read.strip
|
18
|
+
err = stderr.read.strip
|
19
|
+
end
|
20
|
+
|
21
|
+
raise CompressorError.new(err) unless status.success?
|
22
|
+
return out
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def command
|
28
|
+
"java -jar #{jar_path} --type #{@type}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def jar_path
|
32
|
+
AssetTrip.root.join("vendor", "yuicompressor-2.4.2.jar")
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module AssetTrip
|
2
|
+
class Config
|
3
|
+
|
4
|
+
def self.from_file(dir)
|
5
|
+
source = File.read(dir.join("assets.rb"))
|
6
|
+
eval "self.new {( " + source + "\n )}"
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :assets_hash
|
10
|
+
attr_reader :load_paths
|
11
|
+
|
12
|
+
def initialize(&block)
|
13
|
+
@load_paths = Hash.new { LoadPath.new }
|
14
|
+
@load_paths[:javascripts] = LoadPath.new(["app/javascripts"])
|
15
|
+
@load_paths[:stylesheets] = LoadPath.new(["app/stylesheets"])
|
16
|
+
|
17
|
+
@assets_hash = {}
|
18
|
+
instance_eval(&block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def bundle!
|
22
|
+
assets.each do |asset|
|
23
|
+
asset.bundle!
|
24
|
+
end
|
25
|
+
|
26
|
+
ManifestWriter.new(assets).write!
|
27
|
+
end
|
28
|
+
|
29
|
+
def resolve_file(asset_type, file)
|
30
|
+
@load_paths[asset_type].resolve(file)
|
31
|
+
end
|
32
|
+
|
33
|
+
def assets
|
34
|
+
@assets_hash.values
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def js_asset(name, &block)
|
40
|
+
asset = Javascript.new(self, name, &block)
|
41
|
+
@assets_hash[asset.name] = asset
|
42
|
+
end
|
43
|
+
|
44
|
+
def css_asset(name, &block)
|
45
|
+
asset = Stylesheet.new(self, name, &block)
|
46
|
+
@assets_hash[asset.name] = asset
|
47
|
+
|
48
|
+
ssl_asset = asset.ssl_stylesheet
|
49
|
+
@assets_hash[ssl_asset.name] = ssl_asset
|
50
|
+
end
|
51
|
+
|
52
|
+
def load(filename)
|
53
|
+
dirname = File.dirname(filename.to_s)
|
54
|
+
filename = File.basename(filename.to_s, ".rb") + ".rb"
|
55
|
+
source = File.read(AssetTrip.app_root.join(dirname, filename))
|
56
|
+
instance_eval(source)
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module AssetTrip
|
2
|
+
module Helper
|
3
|
+
|
4
|
+
def javascript_include_asset(*sources)
|
5
|
+
_javascripts_for_sources(sources).map do |javascript|
|
6
|
+
javascript_include_tag(javascript)
|
7
|
+
end.join("\n")
|
8
|
+
end
|
9
|
+
|
10
|
+
def stylesheet_link_asset(*sources)
|
11
|
+
options = sources.extract_options!
|
12
|
+
|
13
|
+
_stylesheets_for_sources(sources).map do |stylesheet|
|
14
|
+
stylesheet_link_tag(stylesheet, options)
|
15
|
+
end.join("\n")
|
16
|
+
end
|
17
|
+
|
18
|
+
def rewrite_asset_path(source)
|
19
|
+
if source =~ /assets/
|
20
|
+
source
|
21
|
+
else
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def _stylesheets_for_sources(sources)
|
29
|
+
sources.map { |source| _stylesheets_for_source(source) }.flatten
|
30
|
+
end
|
31
|
+
|
32
|
+
def _javascripts_for_sources(sources)
|
33
|
+
sources.map { |source| _javascripts_for_source(source) }.flatten
|
34
|
+
end
|
35
|
+
|
36
|
+
def _stylesheets_for_source(source)
|
37
|
+
if AssetTrip.bundle
|
38
|
+
_stylesheet_manifest_url(source)
|
39
|
+
else
|
40
|
+
_unbundled_stylesheet_urls(source)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def _javascripts_for_source(source)
|
45
|
+
if AssetTrip.bundle
|
46
|
+
AssetTrip.manifest.path_for(_source_with_extension(source, ".js"))
|
47
|
+
else
|
48
|
+
_unbundled_javascript_urls(source)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def _unbundled_stylesheet_urls(source)
|
53
|
+
asset = AssetTrip.config.assets_hash[_source_with_extension(source, ".css")]
|
54
|
+
|
55
|
+
asset.files.map do |file|
|
56
|
+
_unbundled_asset_url(:stylesheets, file)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def _unbundled_javascript_urls(source)
|
61
|
+
asset = AssetTrip.config.assets_hash[_source_with_extension(source, ".js")]
|
62
|
+
|
63
|
+
asset.files.map do |file|
|
64
|
+
_unbundled_asset_url(:javascripts, file)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def _unbundled_asset_url(asset_type, file)
|
69
|
+
"#{request.protocol}#{request.host}:#{request.port}/__asset_trip__/#{asset_type}/#{file}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def _stylesheet_manifest_url(source)
|
73
|
+
source_with_extension = _source_with_extension(source, ".css")
|
74
|
+
source_with_extension.gsub!(/.css$/, ".ssl.css") if request.ssl?
|
75
|
+
AssetTrip.manifest.path_for(source_with_extension)
|
76
|
+
end
|
77
|
+
|
78
|
+
def _source_with_extension(source, extension)
|
79
|
+
File.basename(source.to_s, extension) + extension
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module AssetTrip
|
2
|
+
class Javascript < Asset
|
3
|
+
|
4
|
+
def name
|
5
|
+
"#{@name}.js"
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def joined_contents
|
11
|
+
paths.map do |path|
|
12
|
+
File.read(path)
|
13
|
+
end.join("\n\n")
|
14
|
+
end
|
15
|
+
|
16
|
+
def compressor
|
17
|
+
Compressor.new("js")
|
18
|
+
end
|
19
|
+
|
20
|
+
def asset_type
|
21
|
+
:javascripts
|
22
|
+
end
|
23
|
+
|
24
|
+
def extension
|
25
|
+
".js"
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module AssetTrip
|
2
|
+
class LoadPath
|
3
|
+
|
4
|
+
attr_reader :paths
|
5
|
+
|
6
|
+
def initialize(paths = [])
|
7
|
+
@paths = paths.map { |path| Pathname.new(path) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def ==(other)
|
11
|
+
self.class == other.class &&
|
12
|
+
@paths == other.paths
|
13
|
+
end
|
14
|
+
|
15
|
+
def <<(path)
|
16
|
+
@paths << Pathname.new(path)
|
17
|
+
end
|
18
|
+
|
19
|
+
# TODO: Refactor
|
20
|
+
def resolve(file)
|
21
|
+
raise UnknownAssetError.new("Could not find #{file} in paths: #{@paths.inspect}") if file.nil?
|
22
|
+
|
23
|
+
file_paths = @paths.map do |path|
|
24
|
+
path.join(file).expand_path
|
25
|
+
end
|
26
|
+
|
27
|
+
result = file_paths.detect do |file_path|
|
28
|
+
File.exist?(file_path)
|
29
|
+
end
|
30
|
+
|
31
|
+
if result
|
32
|
+
return result
|
33
|
+
else
|
34
|
+
raise UnknownAssetError.new("Could not find #{file} in paths: #{@paths.inspect}")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module AssetTrip
|
2
|
+
class Manifest
|
3
|
+
|
4
|
+
def initialize(md5sums = {})
|
5
|
+
@md5sums = md5sums
|
6
|
+
end
|
7
|
+
|
8
|
+
def path_for(key)
|
9
|
+
md5sum = self[key]
|
10
|
+
"/" + File.join("assets", md5sum[0..1], md5sum[2..10], key)
|
11
|
+
end
|
12
|
+
|
13
|
+
def []=(key, value)
|
14
|
+
@md5sums[key] = value
|
15
|
+
end
|
16
|
+
|
17
|
+
def [](key)
|
18
|
+
unless @md5sums.has_key?(key)
|
19
|
+
raise UnknownAssetError.new("Can't find #{key} in the manifest")
|
20
|
+
end
|
21
|
+
|
22
|
+
@md5sums[key]
|
23
|
+
end
|
24
|
+
|
25
|
+
def prune!
|
26
|
+
Pathname.glob(AssetTrip.assets_path.join("**", "*.*")).each do |file|
|
27
|
+
part2 = file.dirname.split.last.to_s
|
28
|
+
part1 = file.dirname.split.first.split.last.to_s
|
29
|
+
|
30
|
+
md5sum = part1 + part2
|
31
|
+
|
32
|
+
if !@md5sums.has_key?(file.basename.to_s) || @md5sums[file.basename.to_s][0..10] != md5sum
|
33
|
+
File.unlink(file)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|