No more bundle-fu

Using Rails 2's built-in bundling instead

I believe this closes #978
This commit is contained in:
Eric Allen 2010-03-14 16:07:26 -04:00
parent b35b48f2bf
commit a0d12c95e9
24 changed files with 9 additions and 1007 deletions

3
.gitignore vendored
View file

@ -15,3 +15,6 @@ public/stylesheets/cache
tmp
vendor/plugins/query_trace/
rerun.txt
public/javascripts/jquery-all.js
public/javascripts/tracks.js
public/stylesheets/all.css

View file

@ -2,23 +2,13 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<% bundle :name => "tracks_css" do %>
<%= stylesheet_link_tag *%w[ standard superfish niftyCorners jquery-ui jquery.autocomplete] %>
<% end %>
<%= stylesheet_link_tag 'standard','superfish','niftyCorners','jquery-ui',
'jquery.autocomplete', :cache => true %>
<%= stylesheet_link_tag "print", :media => "print" %>
<% bundle :name => "jquery" do %>
<%= javascript_include_tag 'jquery' %>
<%= javascript_include_tag 'jquery-ui' %>
<%= javascript_include_tag 'jquery.cookie' %>
<%= javascript_include_tag 'jquery.blockUI' %>
<%= javascript_include_tag 'jquery.jeditable' %>
<%= javascript_include_tag 'jquery.autocomplete' %>
<% end %>
<% bundle :name => "tracks_js" do %>
<%= javascript_include_tag *%w[
hoverIntent superfish application
accesskey-hints niftycube flashobject ] %>
<% end %>
<%= javascript_include_tag 'jquery','jquery-ui','jquery.cookie',
'jquery.blockUI','jquery.jeditable','jquery.autocomplete', :cache => 'jquery-all' %>
<%= javascript_include_tag 'hoverIntent','superfish','application',
'accesskey-hints','niftycube','flashobject', :cache => 'tracks' %>
<%= javascript_tag "var AUTH_TOKEN = #{form_authenticity_token.inspect};" if protect_against_forgery? %>
<%= javascript_tag "var SOURCE_VIEW = '#{@source_view}';" %>
<%= javascript_tag "var TAG_NAME = '#{@tag_name}';" if @tag_name %>

View file

@ -1,20 +0,0 @@
Copyright (c) 2007 Timothy Harper
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,35 +0,0 @@
h1. Bundle fu
-------------
Each css / js you load causes your site to load slower! You can speed things up
exponentially by simply combining all your css/js files into one file each.
Bundle_fu makes it easy to do. It's as easy as 1, 2!
h2. USAGE / INSTALLATION
------------------------
h3. Step 1
Install this plugin
script/plugin install git://github.com/timcharper/bundle-fu.git
h3. Step 2
Put the following around your stylesheets/javascripts (note it works with any method of including assets!):
<pre><code>
<% bundle do %>
...
<%= javascript_include_tag "prototype" %>
<%= stylesheet_link_tag "basic.css" %>
<%= calendar_date_select_includes params[:style] %>
<script src="javascripts/application.js" type="text/javascript"></script>
...
<% end %>
</code></pre>
That's it!
"More info":http://code.google.com/p/bundle-fu/

View file

@ -1,4 +0,0 @@
# load all files
for file in ["/lib/bundle_fu.rb", "/lib/bundle_fu/js_minimizer.rb", "/lib/bundle_fu/css_url_rewriter.rb", "/lib/bundle_fu/file_list.rb"]
require File.expand_path(File.join(File.dirname(__FILE__), file))
end

View file

@ -1,6 +0,0 @@
# EZ Bundle
for file in ["/lib/bundle_fu.rb", "/lib/js_minimizer.rb", "/lib/bundle_fu/file_list.rb"]
end
require File.expand_path(File.join(File.dirname(__FILE__), "environment.rb"))
ActionView::Base.send(:include, BundleFu::InstanceMethods)

View file

@ -1,147 +0,0 @@
class BundleFu
class << self
attr_accessor :content_store
def init
@content_store = {}
end
def bundle_files(filenames=[])
output = ""
filenames.each{ |filename|
filename_no_root = filename.sub(/^#{ActionController::Base.relative_url_root}/, '')
output << "/* --------- #{filename} - #{filename_no_root} --- ------ */ "
output << "\n"
begin
content = (File.read(File.join(RAILS_ROOT, "public", filename_no_root)))
rescue
output << "/* FILE READ ERROR! */"
next
end
output << (yield(filename, content)||"")
}
output
end
def bundle_js_files(filenames=[], options={})
output =
bundle_files(filenames) { |filename, content|
if options[:compress]
if Object.const_defined?("Packr")
content
else
JSMinimizer.minimize_content(content)
end
else
content
end
}
if Object.const_defined?("Packr")
# use Packr plugin (http://blog.jcoglan.com/packr/)
Packr.new.pack(output, options[:packr_options] || {:shrink_vars => false, :base62 => false})
else
output
end
end
def bundle_css_files(filenames=[], options = {})
bundle_files(filenames) { |filename, content|
BundleFu::CSSUrlRewriter.rewrite_urls(filename, content)
}
end
end
self.init
module InstanceMethods
# valid options:
# :name - The name of the css and js files you wish to output
# returns true if a regen occured. False if not.
def bundle(options={}, &block)
# allow bypassing via the querystring
session[:bundle_fu] = (params[:bundle_fu]=="true") if params.has_key?(:bundle_fu)
options = {
:css_path => ($bundle_css_path || "/stylesheets/cache"),
:js_path => ($bundle_js_path || "/javascripts/cache"),
:name => ($bundle_default_name || "bundle"),
:compress => true,
:bundle_fu => ( session[:bundle_fu].nil? ? ($bundle_fu.nil? ? true : $bundle_fu) : session[:bundle_fu] )
}.merge(options)
# allow them to bypass via parameter
options[:bundle_fu] = false if options[:bypass]
paths = { :css => options[:css_path], :js => options[:js_path] }
content = capture(&block)
content_changed = false
new_files = nil
abs_filelist_paths = [:css, :js].inject({}) { | hash, filetype | hash[filetype] = File.join(RAILS_ROOT, "public", paths[filetype], "#{options[:name]}.#{filetype}.filelist"); hash }
# only rescan file list if content_changed, or if a filelist cache file is missing
unless content == BundleFu.content_store[options[:name]] && File.exists?(abs_filelist_paths[:css]) && File.exists?(abs_filelist_paths[:js])
BundleFu.content_store[options[:name]] = content
new_files = {:js => [], :css => []}
content.scan(/(href|src) *= *["']([^"^'^\?]+)/i).each{ |property, value|
case property
when "src"
new_files[:js] << value
when "href"
new_files[:css] << value
end
}
end
[:css, :js].each { |filetype|
output_filename = File.join(paths[filetype], "#{options[:name]}.#{filetype}")
abs_path = File.join(RAILS_ROOT, "public", output_filename)
abs_filelist_path = abs_filelist_paths[filetype]
filelist = FileList.open( abs_filelist_path )
# check against newly parsed filelist. If we didn't parse the filelist from the output, then check against the updated mtimes.
new_filelist = new_files ? BundleFu::FileList.new(new_files[filetype]) : filelist.clone.update_mtimes
unless new_filelist == filelist
FileUtils.mkdir_p(File.join(RAILS_ROOT, "public", paths[filetype]))
# regenerate everything
if new_filelist.filenames.empty?
# delete the javascript/css bundle file if it's empty, but keep the filelist cache
FileUtils.rm_f(abs_path)
else
# call bundle_css_files or bundle_js_files to bundle all files listed. output it's contents to a file
output = BundleFu.send("bundle_#{filetype}_files", new_filelist.filenames, options)
File.open( abs_path, "w") {|f| f.puts output } if output
end
new_filelist.save_as(abs_filelist_path)
end
if File.exists?(abs_path) && options[:bundle_fu]
tag = filetype==:css ? stylesheet_link_tag(output_filename) : javascript_include_tag(output_filename)
if Rails::version < "2.2.0"
concat( tag , block.binding)
else
#concat doesn't need block.binding in Rails >= 2.2.0
concat( tag )
end
end
}
unless options[:bundle_fu]
if Rails::version < "2.2.0"
concat( content, block.binding )
else
#concat doesn't need block.binding in Rails >= 2.2.0
concat( content )
end
end
end
end
end

View file

@ -1,48 +0,0 @@
class BundleFu::CSSUrlRewriter
class << self
# rewrites a relative path to an absolute path, removing excess "../" and "./"
# rewrite_relative_path("stylesheets/default/global.css", "../image.gif") => "#{rails_relative_root}/stylesheets/image.gif"
def rewrite_relative_path(source_filename, relative_url)
relative_url = relative_url.to_s.strip.gsub(/["']/, "")
return relative_url if relative_url.include?("://")
if ( relative_url.first == "/" )
return relative_url unless ActionController::Base.relative_url_root
return "#{ActionController::Base.relative_url_root}#{relative_url}"
end
elements = File.join("/", File.dirname(source_filename)).gsub(/\/+/, '/').split("/")
elements += relative_url.gsub(/\/+/, '/').split("/")
index = 0
while(elements[index])
if (elements[index]==".")
elements.delete_at(index)
elsif (elements[index]=="..")
next if index==0
index-=1
2.times { elements.delete_at(index)}
else
index+=1
end
end
path = elements * "/"
return path unless ActionController::Base.relative_url_root
"#{ActionController::Base.relative_url_root}#{path}"
end
# rewrite the URL reference paths
# url(../../../images/active_scaffold/default/add.gif);
# url(/stylesheets/active_scaffold/default/../../../images/active_scaffold/default/add.gif);
# url(/stylesheets/active_scaffold/../../images/active_scaffold/default/add.gif);
# url(/stylesheets/../images/active_scaffold/default/add.gif);
# url('/images/active_scaffold/default/add.gif');
def rewrite_urls(filename, content)
content.gsub!(/url *\(([^\)]+)\)/) { "url(#{rewrite_relative_path(filename, $1)})" }
content
end
end
end

View file

@ -1,64 +0,0 @@
require 'fileutils.rb'
class BundleFu::FileList
attr_accessor :filelist
def initialize(filenames=[])
self.filelist = []
self.add_files(filenames)
end
def initialize_copy(from)
self.filelist = from.filelist.collect{|entry| entry.clone}
end
def filenames
self.filelist.collect{ |entry| entry[0] }
end
def update_mtimes
old_filenames = self.filenames
self.filelist = []
# readding the files will effectively update the mtimes
self.add_files(old_filenames)
self
end
def self.open(filename)
return nil unless File.exists?(filename)
b = new
File.open(filename, "rb") {|f|
b.filelist = Marshal.load(f) # rescue [])
}
b
rescue
nil
end
# compares to see if one file list is exactly the same as another
def ==(compare)
return false if compare.nil?
throw "cant compare with #{compare.class}" unless self.class===compare
self.filelist == compare.filelist
end
def add_files(filenames=[])
filenames.each{|filename|
self.filelist << [ extract_filename_from_url(filename), (File.mtime(abs_location(filename)).to_i rescue 0) ]
}
end
def extract_filename_from_url(url)
url.gsub(/^https?:\/\/[^\/]+/i, '')
end
def save_as(filename)
File.open(filename, "wb") {|f| f.puts Marshal.dump(self.filelist)}
end
protected
def abs_location(filename)
File.join(RAILS_ROOT, "public", filename)
end
end

View file

@ -1,217 +0,0 @@
#!/usr/bin/ruby
# jsmin.rb 2007-07-20
# Author: Uladzislau Latynski
# This work is a translation from C to Ruby of jsmin.c published by
# Douglas Crockford. Permission is hereby granted to use the Ruby
# version under the same conditions as the jsmin.c on which it is
# based.
#
# /* jsmin.c
# 2003-04-21
#
# Copyright (c) 2002 Douglas Crockford (www.crockford.com)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# The Software shall be used for Good, not Evil.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
require 'stringio'
class BundleFu::JSMinimizer
attr_accessor :input
attr_accessor :output
EOF = -1
@theA = ""
@theB = ""
# isAlphanum -- return true if the character is a letter, digit, underscore,
# dollar sign, or non-ASCII character
def isAlphanum(c)
return false if !c || c == EOF
return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') || c == '_' || c == '$' ||
c == '\\' || c[0] > 126)
end
# get -- return the next character from input. Watch out for lookahead. If
# the character is a control character, translate it to a space or linefeed.
def get()
c = @input.getc
return EOF if(!c)
c = c.chr
return c if (c >= " " || c == "\n" || c.unpack("c") == EOF)
return "\n" if (c == "\r")
return " "
end
# Get the next character without getting it.
def peek()
lookaheadChar = @input.getc
@input.ungetc(lookaheadChar)
return lookaheadChar.chr
end
# mynext -- get the next character, excluding comments.
# peek() is used to see if a '/' is followed by a '/' or '*'.
def mynext()
c = get
if (c == "/")
if(peek == "/")
while(true)
c = get
if (c <= "\n")
return c
end
end
end
if(peek == "*")
get
while(true)
case get
when "*"
if (peek == "/")
get
return " "
end
when EOF
raise "Unterminated comment"
end
end
end
end
return c
end
# action -- do something! What you do is determined by the argument: 1
# Output A. Copy B to A. Get the next B. 2 Copy B to A. Get the next B.
# (Delete A). 3 Get the next B. (Delete B). action treats a string as a
# single character. Wow! action recognizes a regular expression if it is
# preceded by ( or , or =.
def action(a)
if(a==1)
@output.write @theA
end
if(a==1 || a==2)
@theA = @theB
if (@theA == "\'" || @theA == "\"")
while (true)
@output.write @theA
@theA = get
break if (@theA == @theB)
raise "Unterminated string literal" if (@theA <= "\n")
if (@theA == "\\")
@output.write @theA
@theA = get
end
end
end
end
if(a==1 || a==2 || a==3)
@theB = mynext
if (@theB == "/" && (@theA == "(" || @theA == "," || @theA == "=" ||
@theA == ":" || @theA == "[" || @theA == "!" ||
@theA == "&" || @theA == "|" || @theA == "?" ||
@theA == "{" || @theA == "}" || @theA == ";" ||
@theA == "\n"))
@output.write @theA
@output.write @theB
while (true)
@theA = get
if (@theA == "/")
break
elsif (@theA == "\\")
@output.write @theA
@theA = get
elsif (@theA <= "\n")
raise "Unterminated RegExp Literal"
end
@output.write @theA
end
@theB = mynext
end
end
end
# jsmin -- Copy the input to the output, deleting the characters which are
# insignificant to JavaScript. Comments will be removed. Tabs will be
# replaced with spaces. Carriage returns will be replaced with linefeeds.
# Most spaces and linefeeds will be removed.
def jsmin
@theA = "\n"
action(3)
while (@theA != EOF)
case @theA
when " "
if (isAlphanum(@theB))
action(1)
else
action(2)
end
when "\n"
case (@theB)
when "{","[","(","+","-"
action(1)
when " "
action(3)
else
if (isAlphanum(@theB))
action(1)
else
action(2)
end
end
else
case (@theB)
when " "
if (isAlphanum(@theA))
action(1)
else
action(3)
end
when "\n"
case (@theA)
when "}","]",")","+","-","\"","\\", "'", '"'
action(1)
else
if (isAlphanum(@theA))
action(1)
else
action(3)
end
end
else
action(1)
end
end
end
end
def self.minimize_content(content)
js_minimizer = new
js_minimizer.input = StringIO.new(content)
js_minimizer.output = StringIO.new
js_minimizer.jsmin
js_minimizer.output.string
end
end

View file

@ -1,12 +0,0 @@
function js_1() { alert('hi')};
// this is a function
function func() {
alert('hi')
return true
}
function func() {
alert('hi')
return true
}

View file

@ -1 +0,0 @@
function js_2() { alert('hi');};

View file

@ -1 +0,0 @@
function js_3() { alert('hi')};

View file

@ -1 +0,0 @@
css_1 { }

View file

@ -1,7 +0,0 @@
.relative_image_bg {
background-image: url(../images/background.gif )
}
.relative_image_bg_2 {
background-image: url( ../images/groovy/background_2.gif )
}

View file

@ -1,228 +0,0 @@
require File.join(File.dirname(__FILE__), '../test_helper.rb')
require "test/unit"
# require "library_file_name"
class BundleFuTest < Test::Unit::TestCase
def setup
@mock_view = MockView.new
BundleFu.init # resets BundleFu
end
def teardown
purge_cache
end
def test__bundle_js_files__should_include_js_content
@mock_view.bundle { @@content_include_all }
assert_public_files_match("/javascripts/cache/bundle.js", "function js_1()")
end
def test__bundle_js_files_with_asset_server_url
@mock_view.bundle { %(<script src="https://assets.server.com/javascripts/js_1.js?1000" type="text/javascript"></script>) }
assert_public_files_match("/javascripts/cache/bundle.js", "function js_1()")
end
def test__bundle_js_files__should_use_packr
Object.send :class_eval, <<EOF
class ::Object::Packr
def initialize
end
def pack(content, options={})
"PACKR!" + options.inspect
end
end
EOF
@mock_view.bundle() { @@content_include_all }
assert_public_files_match("/javascripts/cache/bundle.js", "PACKR")
purge_cache
@mock_view.bundle(:packr_options => {:packr_options_here => "hi_packr"}) { @@content_include_all }
assert_public_files_match("/javascripts/cache/bundle.js", "packr_options_here", "Should include packr_options")
Object.send :remove_const, "Packr"
end
def test__bundle_js_files__should_default_to_not_compressed_and_include_override_option
@mock_view.bundle() { @@content_include_all }
default_content = File.read(public_file("/javascripts/cache/bundle.js"))
purge_cache
@mock_view.bundle(:compress => false) { @@content_include_all }
uncompressed_content = File.read(public_file("/javascripts/cache/bundle.js"))
purge_cache
@mock_view.bundle(:compress => true) { @@content_include_all }
compressed_content = File.read(public_file("/javascripts/cache/bundle.js"))
purge_cache
assert default_content.length == compressed_content.length, "Should default to compressed"
assert uncompressed_content.length > compressed_content.length, "Didn't compress the content. (:compress => true) #{compressed_content.length}. (:compress => false) #{uncompressed_content.length}"
end
def test__content_remains_same__shouldnt_refresh_cache
@mock_view.bundle { @@content_include_some }
# check to see each bundle file exists and append some text to the bottom of each file
append_to_public_files(cache_files("bundle"), "BOGUS")
assert_public_files_match("/javascripts/cache/bundle.js", "BOGUS")
assert_public_files_match("/stylesheets/cache/bundle.css", "BOGUS")
@mock_view.bundle { @@content_include_some }
assert_public_files_match("/javascripts/cache/bundle.js", "BOGUS")
assert_public_files_match("/stylesheets/cache/bundle.css", "BOGUS")
end
def test__content_changes__should_refresh_cache
@mock_view.bundle { @@content_include_some }
# check to see each bundle file exists and append some text to the bottom of each file
append_to_public_files(cache_files("bundle"), "BOGUS")
assert_public_files_match(cache_files("bundle"), "BOGUS")
# now, pass in some new content. Make sure that the css/js files are regenerated
@mock_view.bundle { @@content_include_all }
assert_public_files_no_match(cache_files("bundle"), "BOGUS")
assert_public_files_no_match(cache_files("bundle"), "BOGUS")
end
def test__modified_time_differs_from_file__should_refresh_cache
@mock_view.bundle { @@content_include_some }
# we're gonna hack each of them and set all the modified times to 0
cache_files("bundle").each{|filename|
abs_filelist_path = public_file(filename + ".filelist")
b = BundleFu::FileList.open(abs_filelist_path)
b.filelist.each{|entry| entry[1] = entry[1] - 100 }
b.save_as(abs_filelist_path)
}
append_to_public_files(cache_files("bundle"), "BOGUS")
end
def test__content_remains_same_but_cache_files_dont_match_whats_in_content__shouldnt_refresh_cache
# it shouldnt parse the content unless if it differed from the last request. This scenario should never exist, and if it did it would be fixed when the server reboots.
@mock_view.bundle { @@content_include_some }
abs_filelist_path = public_file("/stylesheets/cache/bundle.css.filelist")
b = BundleFu::FileList.open(abs_filelist_path)
@mock_view.bundle { @@content_include_all }
b.save_as(abs_filelist_path)
append_to_public_files(cache_files("bundle"), "BOGUS")
@mock_view.bundle { @@content_include_all }
assert_public_files_match(cache_files("bundle"), "BOGUS")
end
def test__content_differs_slightly_but_cache_files_match__shouldnt_refresh_cache
@mock_view.bundle { @@content_include_all }
append_to_public_files(cache_files("bundle"), "BOGUS")
@mock_view.bundle { @@content_include_all + " " }
assert_public_files_match(cache_files("bundle"), "BOGUS")
end
def test__bundle__js_only__should_output_js_include_statement
@mock_view.bundle { @@content_include_some.split("\n").first }
lines = @mock_view.output.split("\n")
assert_equal(1, lines.length)
assert_match(/javascripts/, lines.first)
end
def test__bundle__css_only__should_output_css_include_statement
@mock_view.bundle { @@content_include_some.split("\n")[2] }
lines = @mock_view.output.split("\n")
assert_equal(1, lines.length)
assert_match(/stylesheets/, lines.first)
end
def test__nonexisting_file__should_use_blank_file_created_at_0_mtime
# dbg
@mock_view.bundle { %q{<script src="/javascripts/non_existing_file.js?1000" type="text/javascript"></script>} }
assert_public_files_match(cache_files("bundle").grep(/javascripts/), "FILE READ ERROR")
filelist = BundleFu::FileList.open(public_file("/javascripts/cache/bundle.js.filelist"))
assert_equal(0, filelist.filelist[0][1], "mtime for first file should be 0")
end
def test__missing_cache_filelist__should_regenerate
@mock_view.bundle { @@content_include_some }
append_to_public_files(cache_files("bundle"), "BOGUS")
# now delete the cache files
Dir[ public_file("**/*.filelist")].each{|filename| FileUtils.rm_f filename }
@mock_view.bundle { @@content_include_some }
assert_public_files_no_match(cache_files("bundle"), "BOGUS", "Should have regenerated the file, but it didn't")
end
def test__bypass__should_generate_files_but_render_normal_output
@mock_view.bundle(:bypass => true) { @@content_include_some }
assert_public_file_exists("/stylesheets/cache/bundle.css")
assert_public_file_exists("/stylesheets/cache/bundle.css.filelist")
assert_equal(@@content_include_some, @mock_view.output)
end
def test__bypass_param_set__should_honor_and_store_in_session
@mock_view.params[:bundle_fu] = "false"
@mock_view.bundle { @@content_include_some }
assert_equal(@@content_include_some, @mock_view.output)
@mock_view.params.delete(:bundle_bypass)
@mock_view.bundle { @@content_include_some }
assert_equal(@@content_include_some*2, @mock_view.output)
end
private
def purge_cache
# remove all fixtures named "bundle*"
Dir[ public_file("**/cache") ].each{|filename| FileUtils.rm_rf filename }
end
def assert_public_file_exists(filename, message=nil)
assert_file_exists(public_file(filename), message)
end
def assert_file_exists(filename, message=nil)
assert(File.exists?(filename), message || "File #{filename} expected to exist, but didnt.")
end
def assert_public_files_match(filenames, needle, message=nil)
filenames.each{|filename|
assert_public_file_exists(filename)
assert_match(needle.to_regexp, File.read(public_file(filename)), message || "expected #{filename} to match #{needle}, but doesn't.")
}
end
def assert_public_files_no_match(filenames, needle, message=nil)
filenames.each{ |filename|
assert_public_file_exists(filename)
assert_no_match(needle.to_regexp, File.read(public_file(filename)), message || "expected #{filename} to not match #{needle}, but does.")
}
end
def cache_files(name)
["/javascripts/cache/#{name}.js", "/stylesheets/cache/#{name}.css"]
end
def append_to_public_files(filenames, content)
for filename in filenames
assert_public_file_exists(filename)
File.open(public_file(filename), "a") {|f|
f.puts(content)
}
end
end
end

View file

@ -1,55 +0,0 @@
require File.join(File.dirname(__FILE__), '../test_helper.rb')
class CSSBundleTest < Test::Unit::TestCase
def test__rewrite_relative_path__should_rewrite
assert_rewrites("/stylesheets/active_scaffold/default/stylesheet.css",
"../../../images/spinner.gif" => "/images/spinner.gif",
"../../../images/./../images/goober/../spinner.gif" => "/images/spinner.gif"
)
assert_rewrites("stylesheets/active_scaffold/default/./stylesheet.css",
"../../../images/spinner.gif" => "/images/spinner.gif")
assert_rewrites("stylesheets/main.css",
"image.gif" => "/stylesheets/image.gif")
assert_rewrites("/stylesheets////default/main.css",
"..//image.gif" => "/stylesheets/image.gif")
assert_rewrites("/stylesheets/default/main.css",
"/images/image.gif" => "/images/image.gif")
end
def test__rewrite_relative_path__should_strip_spaces_and_quotes
assert_rewrites("stylesheets/main.css",
"'image.gif'" => "/stylesheets/image.gif",
" image.gif " => "/stylesheets/image.gif"
)
end
def test__rewrite_relative_path__shouldnt_rewrite_if_absolute_url
assert_rewrites("stylesheets/main.css",
" 'http://www.url.com/images/image.gif' " => "http://www.url.com/images/image.gif",
"http://www.url.com/images/image.gif" => "http://www.url.com/images/image.gif",
"ftp://www.url.com/images/image.gif" => "ftp://www.url.com/images/image.gif"
)
end
def test__bundle_css_file__should_rewrite_relatiave_path
bundled_css = BundleFu.bundle_css_files(["/stylesheets/css_3.css"])
assert_match("background-image: url(/images/background.gif)", bundled_css)
assert_match("background-image: url(/images/groovy/background_2.gif)", bundled_css)
end
def test__bundle_css_files__no_images__should_return_content
bundled_css = BundleFu.bundle_css_files(["/stylesheets/css_1.css"])
assert_match("css_1 { }", bundled_css)
end
def assert_rewrites(source_filename, rewrite_map)
rewrite_map.each_pair{|source, dest|
assert_equal(dest, BundleFu::CSSUrlRewriter.rewrite_relative_path(source_filename, source))
}
end
end

View file

@ -1,46 +0,0 @@
require File.join(File.dirname(__FILE__), '../test_helper.rb')
require "test/unit"
# require "library_file_name"
class FileListTest < Test::Unit::TestCase
def setup
end
def test__new_files__should_get_mtimes
filename = "/javascripts/js_1.js"
filelist = BundleFu::FileList.new([filename])
assert_equal(File.mtime(File.join(RAILS_ROOT, "public", filename)).to_i,filelist.filelist[0][1])
end
def test__serialization
filelist_filename = File.join(RAILS_ROOT, "public", "temp")
filelist = BundleFu::FileList.new("/javascripts/js_1.js")
filelist.save_as(filelist_filename)
filelist2 = BundleFu::FileList.open(filelist_filename)
assert(filelist == filelist2, "expected to be same, but differed.\n#{filelist.to_yaml}\n\n#{filelist2.to_yaml}")
ensure
FileUtils.rm_f(filelist_filename)
end
def test__equality__same_file_and_mtime__should_equate
filename = "/javascripts/js_1.js"
assert BundleFu::FileList.new(filename) == BundleFu::FileList.new(filename)
end
def test__equality__dif_file_and_mtime__shouldnt_equate
filename1 = "/javascripts/js_1.js"
filename2 = "/javascripts/js_2.js"
assert BundleFu::FileList.new(filename1) != BundleFu::FileList.new(filename2)
end
def test__clone_item
b = BundleFu::FileList.new("/javascripts/js_1.js")
assert b == b.clone
end
end

View file

@ -1,14 +0,0 @@
require File.join(File.dirname(__FILE__), '../test_helper.rb')
class JSBundleTest < Test::Unit::TestCase
def test__bundle_js_files__bypass_bundle__should_bypass
BundleFu.bundle_js_files
end
def test__bundle_js_files__should_include_contents
bundled_js = BundleFu.bundle_js_files(["/javascripts/js_1.js"])
# puts bundled_js
# function js_1
assert_match("function js_1", bundled_js)
end
end

View file

@ -1,12 +0,0 @@
require File.join(File.dirname(__FILE__), '../test_helper.rb')
class BundleFu::JSMinimizerTest < Test::Unit::TestCase
def test_minimize_content__should_be_less
test_content = File.read(public_file("javascripts/js_1.js"))
content_size = test_content.length
minimized_size = BundleFu::JSMinimizer.minimize_content(test_content).length
assert(minimized_size > 0)
assert(content_size > minimized_size)
end
end

View file

@ -1,31 +0,0 @@
class MockView
# set RAILS_ROOT to fixtures dir so we use those files
include BundleFu::InstanceMethods
::RAILS_ROOT = File.join(File.dirname(__FILE__), 'fixtures')
attr_accessor :output
attr_accessor :session
attr_accessor :params
def initialize
@output = ""
@session = {}
@params = {}
end
def capture(&block)
yield
end
def concat(output, *args)
@output << output
end
def stylesheet_link_tag(*args)
args.collect{|arg| "<link href=\"#{arg}?#{File.mtime(File.join(RAILS_ROOT, 'public', arg)).to_i}\" media=\"screen\" rel=\"Stylesheet\" type=\"text/css\" />" } * "\n"
end
def javascript_include_tag(*args)
args.collect{|arg| "<script src=\"#{arg}?#{File.mtime(File.join(RAILS_ROOT, 'public', arg)).to_i}\" type=\"text/javascript\"></script>" } * "\n"
end
end

View file

@ -1,3 +0,0 @@
Dir[File.join(File.dirname(__FILE__), "functional/*.rb")].each{|filename|
require filename
}

View file

@ -1,38 +0,0 @@
require 'test/unit'
require "rubygems"
require 'active_support'
for file in ["../environment.rb", "mock_view.rb"]
require File.expand_path(File.join(File.dirname(__FILE__), file))
end
def dbg
require 'ruby-debug'
Debugger.start
debugger
end
class Object
def to_regexp
is_a?(Regexp) ? self : Regexp.new(Regexp.escape(self.to_s))
end
end
class Test::Unit::TestCase
@@content_include_some = <<-EOF
<script src="/javascripts/js_1.js?1000" type="text/javascript"></script>
<script src="/javascripts/js_2.js?1000" type="text/javascript"></script>
<link href="/stylesheets/css_1.css?1000" media="screen" rel="Stylesheet" type="text/css" />
<link href="/stylesheets/css_2.css?1000" media="screen" rel="Stylesheet" type="text/css" />
EOF
# the same content, slightly changed
@@content_include_all = @@content_include_some + <<-EOF
<script src="/javascripts/js_3.js?1000" type="text/javascript"></script>
<link href="/stylesheets/css_3.css?1000" media="screen" rel="Stylesheet" type="text/css" />
EOF
def public_file(filename)
File.join(::RAILS_ROOT, "public", filename)
end
end