juicer 0.2.6 → 1.0.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/History.txt +28 -0
- data/Rakefile +84 -36
- data/Readme.rdoc +192 -23
- data/VERSION +1 -0
- data/bin/juicer +2 -4
- data/lib/juicer.rb +9 -10
- data/lib/juicer/asset/path.rb +275 -0
- data/lib/juicer/asset/path_resolver.rb +79 -0
- data/lib/juicer/binary.rb +3 -5
- data/lib/juicer/cache_buster.rb +112 -27
- data/lib/juicer/command/install.rb +4 -2
- data/lib/juicer/command/list.rb +16 -9
- data/lib/juicer/command/merge.rb +30 -14
- data/lib/juicer/command/verify.rb +1 -1
- data/lib/juicer/css_cache_buster.rb +31 -47
- data/lib/juicer/datafy/datafy.rb +20 -0
- data/lib/juicer/dependency_resolver/css_dependency_resolver.rb +29 -0
- data/lib/juicer/dependency_resolver/dependency_resolver.rb +101 -0
- data/lib/juicer/dependency_resolver/javascript_dependency_resolver.rb +23 -0
- data/lib/juicer/ext/logger.rb +5 -0
- data/lib/juicer/ext/string.rb +47 -0
- data/lib/juicer/ext/symbol.rb +15 -0
- data/lib/juicer/image_embed.rb +129 -0
- data/lib/juicer/install/base.rb +2 -2
- data/lib/juicer/install/closure_compiler_installer.rb +69 -0
- data/lib/juicer/install/jslint_installer.rb +3 -3
- data/lib/juicer/install/rhino_installer.rb +3 -2
- data/lib/juicer/install/yui_compressor_installer.rb +3 -2
- data/lib/juicer/jslint.rb +1 -1
- data/lib/juicer/merger/base.rb +1 -1
- data/lib/juicer/merger/javascript_merger.rb +3 -4
- data/lib/juicer/merger/stylesheet_merger.rb +13 -15
- data/lib/juicer/minifyer/closure_compiler.rb +90 -0
- data/lib/juicer/minifyer/java_base.rb +77 -0
- data/lib/juicer/minifyer/yui_compressor.rb +15 -48
- data/test/bin/jslint-1.0.js +523 -0
- data/test/bin/jslint.js +523 -0
- data/test/bin/rhino1_7R1.zip +0 -0
- data/test/bin/rhino1_7R2-RC1.jar +0 -0
- data/test/bin/rhino1_7R2-RC1.zip +0 -0
- data/test/bin/yuicompressor +0 -0
- data/test/bin/yuicompressor-2.3.5.zip +0 -0
- data/test/bin/yuicompressor-2.4.2.jar +0 -0
- data/test/bin/yuicompressor-2.4.2.zip +0 -0
- data/test/data/Changelog.txt +10 -0
- data/test/data/a.css +3 -0
- data/test/data/a.js +5 -0
- data/test/data/a1.css +5 -0
- data/test/data/b.css +1 -0
- data/test/data/b.js +5 -0
- data/test/data/b1.css +5 -0
- data/test/data/c1.css +3 -0
- data/test/data/css/2.gif +1 -0
- data/test/data/css/test.css +11 -0
- data/test/data/css/test2.css +1 -0
- data/test/data/d1.css +3 -0
- data/test/data/images/1.png +1 -0
- data/test/data/my_app.js +2 -0
- data/test/data/not-ok.js +2 -0
- data/test/data/ok.js +3 -0
- data/test/data/path_test.css +5 -0
- data/test/data/path_test2.css +14 -0
- data/test/data/pkg/module/moda.js +2 -0
- data/test/data/pkg/module/modb.js +3 -0
- data/test/data/pkg/pkg.js +1 -0
- data/test/fixtures/yui-download.html +425 -0
- data/test/test_helper.rb +36 -7
- data/test/unit/juicer/asset/path_resolver_test.rb +76 -0
- data/test/unit/juicer/asset/path_test.rb +370 -0
- data/test/unit/juicer/cache_buster_test.rb +104 -0
- data/test/{juicer/test_chainable.rb → unit/juicer/chainable_test.rb} +1 -1
- data/test/unit/juicer/command/install_test.rb +58 -0
- data/test/{juicer/command/test_list.rb → unit/juicer/command/list_test.rb} +26 -14
- data/test/unit/juicer/command/merge_test.rb +162 -0
- data/test/{juicer/command/test_util.rb → unit/juicer/command/util_test.rb} +10 -6
- data/test/unit/juicer/command/verify_test.rb +48 -0
- data/test/{juicer/test_css_cache_buster.rb → unit/juicer/css_cache_buster_test.rb} +10 -30
- data/test/unit/juicer/datafy_test.rb +37 -0
- data/test/{juicer/merger/test_css_dependency_resolver.rb → unit/juicer/dependency_resolver/css_dependency_resolver_test.rb} +2 -2
- data/test/{juicer/merger/test_javascript_dependency_resolver.rb → unit/juicer/dependency_resolver/javascript_dependency_resolver_test.rb} +13 -2
- data/test/unit/juicer/ext/{#string_test.rb# → string_test.rb} +0 -7
- data/test/unit/juicer/ext/symbol_test.rb +27 -0
- data/test/unit/juicer/image_embed_test.rb +271 -0
- data/test/unit/juicer/install/installer_base_test.rb +214 -0
- data/test/{juicer/install/test_jslint_installer.rb → unit/juicer/install/jslint_installer_test.rb} +1 -1
- data/test/{juicer/install/test_rhino_installer.rb → unit/juicer/install/rhino_installer_test.rb} +1 -1
- data/test/{juicer/install/test_yui_compressor_installer.rb → unit/juicer/install/yui_compressor_test.rb} +16 -16
- data/test/unit/juicer/jslint_test.rb +60 -0
- data/test/{juicer/merger/test_base.rb → unit/juicer/merger/base_test.rb} +1 -1
- data/test/{juicer/merger/test_javascript_merger.rb → unit/juicer/merger/javascript_merger_test.rb} +2 -2
- data/test/{juicer/merger/test_stylesheet_merger.rb → unit/juicer/merger/stylesheet_merger_test.rb} +15 -13
- data/test/unit/juicer/minifyer/closure_compressor_test.rb +107 -0
- data/test/{integration → unit}/juicer/minifyer/yui_compressor_test.rb +30 -47
- data/test/unit/juicer_test.rb +1 -0
- metadata +207 -113
- data/lib/juicer/core.rb +0 -61
- data/lib/juicer/merger/css_dependency_resolver.rb +0 -25
- data/lib/juicer/merger/dependency_resolver.rb +0 -82
- data/lib/juicer/merger/javascript_dependency_resolver.rb +0 -21
- data/tasks/ann.rake +0 -80
- data/tasks/bones.rake +0 -20
- data/tasks/gem.rake +0 -201
- data/tasks/git.rake +0 -40
- data/tasks/notes.rake +0 -27
- data/tasks/post_load.rake +0 -34
- data/tasks/rdoc.rake +0 -51
- data/tasks/rubyforge.rake +0 -55
- data/tasks/setup.rb +0 -292
- data/tasks/spec.rake +0 -54
- data/tasks/svn.rake +0 -47
- data/tasks/test.rake +0 -40
- data/tasks/test/setup.rake +0 -35
- data/tasks/zentest.rake +0 -36
- data/test/juicer/command/test_install.rb +0 -53
- data/test/juicer/command/test_merge.rb +0 -160
- data/test/juicer/command/test_verify.rb +0 -33
- data/test/juicer/install/test_installer_base.rb +0 -195
- data/test/juicer/minifyer/test_yui_compressor.rb +0 -159
- data/test/juicer/test_cache_buster.rb +0 -58
- data/test/juicer/test_core.rb +0 -47
- data/test/juicer/test_jslint.rb +0 -33
- data/test/test_juicer.rb +0 -4
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require "juicer/dependency_resolver/dependency_resolver"
|
|
2
|
+
|
|
3
|
+
module Juicer
|
|
4
|
+
# Resolves @depends and @depend statements in comments in JavaScript files.
|
|
5
|
+
# Only the first comment in a JavaScript file is parsed
|
|
6
|
+
#
|
|
7
|
+
class JavaScriptDependencyResolver < DependencyResolver
|
|
8
|
+
@@depends_pattern = /\@depends?\s+([^\s\'\"\;]+)/
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
def parse(line, imported_file = nil)
|
|
12
|
+
return $1 if line =~ @@depends_pattern
|
|
13
|
+
|
|
14
|
+
# If we have already skimmed through some @depend/@depends or a
|
|
15
|
+
# closing comment we're done.
|
|
16
|
+
throw :done unless imported_file.nil? || !(line =~ /\*\//)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def extension
|
|
20
|
+
".js"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Additions to core Ruby objects
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
class String
|
|
6
|
+
|
|
7
|
+
unless String.method_defined?(:camel_case)
|
|
8
|
+
#
|
|
9
|
+
# Turn an underscored string into camel case, ie this_becomes -> ThisBecomes
|
|
10
|
+
#
|
|
11
|
+
def camel_case
|
|
12
|
+
self.split("_").inject("") { |str, piece| str + piece.capitalize }
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
unless String.method_defined?(:to_class)
|
|
17
|
+
#
|
|
18
|
+
# Treat a string as a class name and return the class. Optionally provide a
|
|
19
|
+
# module to look up the class in.
|
|
20
|
+
#
|
|
21
|
+
def to_class(mod = nil)
|
|
22
|
+
res = "#{mod}::#{self}".sub(/^::/, "").split("::").inject(Object) do |mod, obj|
|
|
23
|
+
raise "No such class/module" unless mod.const_defined?(obj)
|
|
24
|
+
mod = mod.const_get(obj)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
unless String.method_defined?(:classify)
|
|
30
|
+
#
|
|
31
|
+
# Turn a string in either underscore or camel case form into a class directly
|
|
32
|
+
#
|
|
33
|
+
def classify(mod = nil)
|
|
34
|
+
self.camel_case.to_class(mod)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
unless String.method_defined?(:underscore)
|
|
39
|
+
#
|
|
40
|
+
# Turn a camelcase string into underscore string
|
|
41
|
+
#
|
|
42
|
+
def underscore
|
|
43
|
+
self.split(/([A-Z][^A-Z]*)/).find_all { |str| str != "" }.join("_").downcase
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class Symbol
|
|
2
|
+
#
|
|
3
|
+
# Converts symbol to string and calls String#camel_case
|
|
4
|
+
#
|
|
5
|
+
def camel_case
|
|
6
|
+
self.to_s.camel_case
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
#
|
|
10
|
+
# Converts symbol to string and calls String#classify
|
|
11
|
+
#
|
|
12
|
+
def classify(mod = nil)
|
|
13
|
+
self.to_s.classify(mod)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
require "juicer/chainable"
|
|
2
|
+
require "juicer/cache_buster"
|
|
3
|
+
require "juicer/asset/path_resolver"
|
|
4
|
+
|
|
5
|
+
module Juicer
|
|
6
|
+
#
|
|
7
|
+
# The ImageEmbed is a tool that can parse a CSS file and substitute all
|
|
8
|
+
# referenced URLs by a data uri
|
|
9
|
+
#
|
|
10
|
+
# - data uri (http://en.wikipedia.org/wiki/Data_URI_scheme)
|
|
11
|
+
#
|
|
12
|
+
# Only local resources will be processed this way, external resources referenced
|
|
13
|
+
# by absolute urls will be left alone
|
|
14
|
+
#
|
|
15
|
+
class ImageEmbed
|
|
16
|
+
include Juicer::Chainable
|
|
17
|
+
|
|
18
|
+
# The maximum supported limit for modern browsers, See the Readme.rdoc for details
|
|
19
|
+
SIZE_LIMIT = 32768
|
|
20
|
+
|
|
21
|
+
#
|
|
22
|
+
# Returns the size limit
|
|
23
|
+
#
|
|
24
|
+
def size_limit
|
|
25
|
+
SIZE_LIMIT
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def initialize(options = {})
|
|
29
|
+
@document_root = options[:document_root]
|
|
30
|
+
@document_root.sub!(%r{/?$}, "") if @document_root # Remove trailing slash
|
|
31
|
+
@type = options[:type] || :none
|
|
32
|
+
@contents = nil
|
|
33
|
+
@hosts = options[:hosts]
|
|
34
|
+
@path_resolver = Juicer::Asset::PathResolver.new(:document_root => options[:document_root],
|
|
35
|
+
:hosts => options[:hosts])
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
#
|
|
39
|
+
# Update file. If no +output+ is provided, the input file is overwritten
|
|
40
|
+
#
|
|
41
|
+
def save(file, output = nil)
|
|
42
|
+
return unless @type == :data_uri
|
|
43
|
+
|
|
44
|
+
output_file = output || file
|
|
45
|
+
@contents = File.read(file)
|
|
46
|
+
used = []
|
|
47
|
+
|
|
48
|
+
@path_resolver = Juicer::Asset::PathResolver.new(:document_root => @document_root,
|
|
49
|
+
:hosts => @hosts,
|
|
50
|
+
:base => File.dirname(file))
|
|
51
|
+
|
|
52
|
+
assets = urls(file)
|
|
53
|
+
|
|
54
|
+
# TODO: Remove "?embed=true" from duplicate urls
|
|
55
|
+
duplicates = duplicate_urls(assets)
|
|
56
|
+
|
|
57
|
+
if duplicates.length > 0
|
|
58
|
+
Juicer::LOGGER.warn("Duplicate image urls detected, these images will not be embedded: #{duplicates.collect { |v| v.gsub('?embed=true', '') }.inspect}")
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
assets.each do |asset|
|
|
62
|
+
begin
|
|
63
|
+
next if used.include?(asset) || duplicates.include?(asset.path)
|
|
64
|
+
used << asset
|
|
65
|
+
|
|
66
|
+
# make sure we do not exceed SIZE_LIMIT
|
|
67
|
+
new_path = embed_data_uri(asset.filename)
|
|
68
|
+
|
|
69
|
+
if new_path.length < SIZE_LIMIT
|
|
70
|
+
# replace the url in the css file with the data uri
|
|
71
|
+
@contents.gsub!(asset.path, embed_data_uri(asset.path))
|
|
72
|
+
else
|
|
73
|
+
Juicer::LOGGER.warn("The final data uri for the image located at #{asset.path.gsub('?embed=true', '')} exceeds #{SIZE_LIMIT} and will not be embedded to maintain compatability.")
|
|
74
|
+
end
|
|
75
|
+
rescue Errno::ENOENT
|
|
76
|
+
puts "Unable to locate file #{asset.path}, skipping image embedding"
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
File.open(output || file, "w") { |f| f.puts @contents }
|
|
81
|
+
@contents = nil
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
chain_method :save
|
|
85
|
+
|
|
86
|
+
def embed_data_uri( path )
|
|
87
|
+
new_path = path
|
|
88
|
+
|
|
89
|
+
if path.match( /\?embed=true$/ )
|
|
90
|
+
supported_file_matches = path.match( /(?:\.)(png|gif|jpg|jpeg)(?:\?embed=true)$/i )
|
|
91
|
+
filetype = supported_file_matches[1] if supported_file_matches
|
|
92
|
+
|
|
93
|
+
if ( filetype )
|
|
94
|
+
filename = path.gsub('?embed=true','')
|
|
95
|
+
|
|
96
|
+
# check if file exists, throw an error if it doesn't exist
|
|
97
|
+
if File.exist?( filename )
|
|
98
|
+
|
|
99
|
+
# read contents of file into memory
|
|
100
|
+
content = File.read( filename )
|
|
101
|
+
content_type = "image/#{filetype}"
|
|
102
|
+
|
|
103
|
+
# encode the url
|
|
104
|
+
new_path = Datafy::make_data_uri( content, content_type )
|
|
105
|
+
else
|
|
106
|
+
puts "Unable to locate file #{filename} on local file system, skipping image embedding"
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
return new_path
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
#
|
|
114
|
+
# Returns all referenced URLs in +file+.
|
|
115
|
+
#
|
|
116
|
+
def urls(file)
|
|
117
|
+
@contents = File.read(file) unless @contents
|
|
118
|
+
|
|
119
|
+
@contents.scan(/url\([\s"']*([^\)"'\s]*)[\s"']*\)/m).collect do |match|
|
|
120
|
+
@path_resolver.resolve(match.first)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
private
|
|
125
|
+
def duplicate_urls(urls)
|
|
126
|
+
urls.inject({}) { |h,v| h[v.path] = h[v.path].to_i+1; h }.reject{ |k,v| v == 1 }.keys
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
data/lib/juicer/install/base.rb
CHANGED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require "juicer"
|
|
2
|
+
require "juicer/install/base"
|
|
3
|
+
require "zip/zip"
|
|
4
|
+
|
|
5
|
+
module Juicer
|
|
6
|
+
module Install
|
|
7
|
+
#
|
|
8
|
+
# Install and uninstall routines for the Google Closure Compiler.
|
|
9
|
+
# Installation downloads the Closure Compiler distribution, unzips it and
|
|
10
|
+
# storesthe jar file on disk along with the README.
|
|
11
|
+
#
|
|
12
|
+
class ClosureCompilerInstaller < Base
|
|
13
|
+
def initialize(install_dir = Juicer.home)
|
|
14
|
+
super(install_dir)
|
|
15
|
+
@latest = nil
|
|
16
|
+
@website = "http://code.google.com/p/closure-compiler/downloads/list"
|
|
17
|
+
@download_link = "http://closure-compiler.googlecode.com/files/compiler-%s.zip"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
#
|
|
21
|
+
# Install the Closure Compiler. Downloads the distribution and keeps the jar
|
|
22
|
+
# file inside PATH/closure_compiler/bin and the README in
|
|
23
|
+
# PATH/closere_compiler/yyyymmdd/ where yyyymmdd is the version, most recent if
|
|
24
|
+
# not specified otherwise.
|
|
25
|
+
#
|
|
26
|
+
# Path defaults to environment variable $JUICER_HOME or default Juicer
|
|
27
|
+
# home
|
|
28
|
+
#
|
|
29
|
+
def install(version = nil)
|
|
30
|
+
version = super(version)
|
|
31
|
+
base = "closure-compiler-#{version}"
|
|
32
|
+
filename = download(@download_link % version)
|
|
33
|
+
target = File.join(@install_dir, path)
|
|
34
|
+
|
|
35
|
+
Zip::ZipFile.open(filename) do |file|
|
|
36
|
+
file.extract("README", File.join(target, version, "README"))
|
|
37
|
+
file.extract("compiler.jar", File.join(target, "bin", "#{base}.jar"))
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
#
|
|
42
|
+
# Uninstalls the given version of Closure Compiler. If no location is
|
|
43
|
+
# provided the environment variable $JUICER_HOME or Juicers default home
|
|
44
|
+
# directory is used.
|
|
45
|
+
#
|
|
46
|
+
# If no version is provided the most recent version is assumed.
|
|
47
|
+
#
|
|
48
|
+
# If there are no more files left in INSTALLATION_PATH/closure_compiler, the
|
|
49
|
+
# whole directory is removed.
|
|
50
|
+
#
|
|
51
|
+
def uninstall(version = nil)
|
|
52
|
+
super(version) do |dir, version|
|
|
53
|
+
File.delete(File.join(dir, "bin/closure-compiler-#{version}.jar"))
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
#
|
|
58
|
+
# Check which version is the most recent
|
|
59
|
+
#
|
|
60
|
+
def latest
|
|
61
|
+
return @latest if @latest
|
|
62
|
+
webpage = Nokogiri::HTML(open(@website))
|
|
63
|
+
@latest = (webpage / "//table[@id='resultstable']//td/a[contains(@href, 'compiler')]").map{|link|
|
|
64
|
+
link.get_attribute('href')[/\d{8}/].to_i
|
|
65
|
+
}.sort.last.to_s
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
require
|
|
2
|
-
require
|
|
1
|
+
require "juicer"
|
|
2
|
+
require "juicer/install/base"
|
|
3
3
|
require "zip/zip"
|
|
4
4
|
|
|
5
5
|
module Juicer
|
|
@@ -28,7 +28,7 @@ module Juicer
|
|
|
28
28
|
def install(version = nil)
|
|
29
29
|
version = super(version)
|
|
30
30
|
filename = download(File.join(@website, "rhino/jslint.js"))
|
|
31
|
-
|
|
31
|
+
FileUtils.copy(filename, File.join(@install_dir, path, "bin", "jslint-#{version}.js"))
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
#
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "juicer"
|
|
2
|
+
require "juicer/install/base"
|
|
2
3
|
require "zip/zip"
|
|
3
4
|
|
|
4
5
|
module Juicer
|
|
@@ -12,7 +13,7 @@ module Juicer
|
|
|
12
13
|
def initialize(install_dir = Juicer.home)
|
|
13
14
|
super(install_dir)
|
|
14
15
|
@latest = "1_7R2-RC1"
|
|
15
|
-
@website = "
|
|
16
|
+
@website = "http://ftp.mozilla.org/pub/mozilla.org/js/"
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
#
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "juicer"
|
|
2
|
+
require "juicer/install/base"
|
|
2
3
|
require "zip/zip"
|
|
3
4
|
|
|
4
5
|
module Juicer
|
|
@@ -58,7 +59,7 @@ module Juicer
|
|
|
58
59
|
#
|
|
59
60
|
def latest
|
|
60
61
|
return @latest if @latest
|
|
61
|
-
webpage =
|
|
62
|
+
webpage = Nokogiri::HTML(open(@website))
|
|
62
63
|
@latest = (webpage / "//h2[@id='yuicompressor']/../../../..//a")[0].get_attribute("href").match(/(\d\.\d\.\d)/)[1]
|
|
63
64
|
end
|
|
64
65
|
end
|
data/lib/juicer/jslint.rb
CHANGED
data/lib/juicer/merger/base.rb
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
end
|
|
2
|
+
require "juicer/merger/base"
|
|
3
|
+
require "juicer/dependency_resolver/javascript_dependency_resolver"
|
|
5
4
|
|
|
6
5
|
module Juicer
|
|
7
6
|
module Merger
|
|
@@ -22,7 +21,7 @@ end
|
|
|
22
21
|
# or similar.
|
|
23
22
|
#
|
|
24
23
|
if $0 == __FILE__
|
|
25
|
-
|
|
24
|
+
puts("Usage: javascript_merger.rb file[...] output") and exit if $*.length < 2
|
|
26
25
|
|
|
27
26
|
fm = JavaScriptMerger.new()
|
|
28
27
|
fm << $*[0..-2]
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
end
|
|
5
|
-
|
|
2
|
+
require "juicer/merger/base"
|
|
3
|
+
require "juicer/dependency_resolver/css_dependency_resolver"
|
|
6
4
|
require 'pathname'
|
|
7
5
|
|
|
8
6
|
module Juicer
|
|
@@ -15,7 +13,7 @@ module Juicer
|
|
|
15
13
|
# Constructor
|
|
16
14
|
#
|
|
17
15
|
# Options:
|
|
18
|
-
# * <tt>:
|
|
16
|
+
# * <tt>:document_root</tt> - Path to web root if there is any @import statements
|
|
19
17
|
# using absolute URLs
|
|
20
18
|
#
|
|
21
19
|
def initialize(files = [], options = {})
|
|
@@ -25,8 +23,8 @@ module Juicer
|
|
|
25
23
|
@host_num = 0
|
|
26
24
|
@use_absolute = options.key?(:absolute_urls) ? options[:absolute_urls] : false
|
|
27
25
|
@use_relative = options.key?(:relative_urls) ? options[:relative_urls] : false
|
|
28
|
-
@
|
|
29
|
-
@
|
|
26
|
+
@document_root = options[:document_root]
|
|
27
|
+
@document_root = File.expand_path(@document_root).sub(/\/?$/, "") if @document_root # Make sure path doesn't end in a /
|
|
30
28
|
end
|
|
31
29
|
|
|
32
30
|
private
|
|
@@ -42,10 +40,10 @@ module Juicer
|
|
|
42
40
|
# The options hash decides how Juicer recalculates referenced URLs:
|
|
43
41
|
#
|
|
44
42
|
# options[:absolute_urls] When true, all paths are converted to absolute
|
|
45
|
-
# URLs. Requires options[:
|
|
43
|
+
# URLs. Requires options[:document_root] to define
|
|
46
44
|
# root directory to resolve absolute URLs from.
|
|
47
45
|
# options[:relative_urls] When true, all paths are converted to relative
|
|
48
|
-
# paths. Requires options[:
|
|
46
|
+
# paths. Requires options[:document_root] to define
|
|
49
47
|
# root directory to resolve absolute URLs from.
|
|
50
48
|
#
|
|
51
49
|
# If none if these are set then relative URLs are recalculated to match
|
|
@@ -55,7 +53,7 @@ module Juicer
|
|
|
55
53
|
# for all absolute URLs regardless of absolute/relative URL strategy.
|
|
56
54
|
#
|
|
57
55
|
def merge(file)
|
|
58
|
-
content = super.gsub(/^\s
|
|
56
|
+
content = super.gsub(/^\s*@import(?:\surl\(|\s)(['"]?)([^\?'"\)\s]+)(\?(?:[^'"\)]+)?)?\1\)?(?:[^?;]+)?;?/i, "")
|
|
59
57
|
dir = File.expand_path(File.dirname(file))
|
|
60
58
|
|
|
61
59
|
content.scan(/url\([\s"']*([^\)"'\s]*)[\s"']*\)/m).uniq.collect do |url|
|
|
@@ -75,15 +73,15 @@ module Juicer
|
|
|
75
73
|
|
|
76
74
|
# Absolute URLs
|
|
77
75
|
if url =~ %r{^/} && @use_relative
|
|
78
|
-
raise ArgumentError.new("Unable to handle absolute URLs without :
|
|
79
|
-
path = Pathname.new(File.join(@
|
|
76
|
+
raise ArgumentError.new("Unable to handle absolute URLs without :document_root option") if !@document_root
|
|
77
|
+
path = Pathname.new(File.join(@document_root, url)).relative_path_from(@root).to_s
|
|
80
78
|
end
|
|
81
79
|
|
|
82
80
|
# All URLs that don't start with a protocol
|
|
83
81
|
if url !~ %r{^/} && url !~ %r{^[a-z]+://}
|
|
84
82
|
if @use_absolute
|
|
85
|
-
raise ArgumentError.new("Unable to handle absolute URLs without :
|
|
86
|
-
path = File.expand_path(File.join(dir, url)).sub(@
|
|
83
|
+
raise ArgumentError.new("Unable to handle absolute URLs without :document_root option") if !@document_root
|
|
84
|
+
path = File.expand_path(File.join(dir, url)).sub(@document_root, "") # Make absolute
|
|
87
85
|
else
|
|
88
86
|
path = Pathname.new(File.join(dir, url)).relative_path_from(@root).to_s # ...or redefine relative ref
|
|
89
87
|
end
|
|
@@ -104,7 +102,7 @@ end
|
|
|
104
102
|
# Run file from command line
|
|
105
103
|
#
|
|
106
104
|
if $0 == __FILE__
|
|
107
|
-
|
|
105
|
+
puts("Usage: stylesheet_merger.rb file[...] output") and exit if $*.length < 2
|
|
108
106
|
|
|
109
107
|
fm = Juicer::Merger::StylesheetMerger.new()
|
|
110
108
|
fm << $*[0..-2]
|