sqweeze 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest +20 -0
- data/README.rdoc +28 -0
- data/Rakefile +15 -0
- data/bin/sqweeze +116 -0
- data/lib/compilers/assetLinker.rb +33 -0
- data/lib/compilers/cssDomCompiler.rb +23 -0
- data/lib/compilers/jsDomCompiler.rb +24 -0
- data/lib/compressor.rb +128 -0
- data/lib/compressors/cssCompressor.rb +103 -0
- data/lib/compressors/gifCompressor.rb +13 -0
- data/lib/compressors/jpegCompressor.rb +6 -0
- data/lib/compressors/jsCompressor.rb +27 -0
- data/lib/compressors/pngCompressor.rb +11 -0
- data/lib/confManager.rb +191 -0
- data/lib/domCompiler.rb +51 -0
- data/lib/sqweezeUtils.rb +86 -0
- data/spec/confManager_spec.rb +61 -0
- data/spec/domCompiler_spec.rb +41 -0
- data/spec/sqw_spec_helper.rb +24 -0
- data/sqweeze.gemspec +41 -0
- metadata +151 -0
data/Manifest
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Manifest
|
2
|
+
README.rdoc
|
3
|
+
Rakefile
|
4
|
+
bin/sqweeze
|
5
|
+
lib/compilers/assetLinker.rb
|
6
|
+
lib/compilers/cssDomCompiler.rb
|
7
|
+
lib/compilers/jsDomCompiler.rb
|
8
|
+
lib/compressor.rb
|
9
|
+
lib/compressors/cssCompressor.rb
|
10
|
+
lib/compressors/gifCompressor.rb
|
11
|
+
lib/compressors/jpegCompressor.rb
|
12
|
+
lib/compressors/jsCompressor.rb
|
13
|
+
lib/compressors/pngCompressor.rb
|
14
|
+
lib/confManager.rb
|
15
|
+
lib/domCompiler.rb
|
16
|
+
lib/sqweezeUtils.rb
|
17
|
+
spec/confManager_spec.rb
|
18
|
+
spec/domCompiler_spec.rb
|
19
|
+
spec/sqw_spec_helper.rb
|
20
|
+
sqweeze.gemspec
|
data/README.rdoc
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
== Sqweeze
|
2
|
+
A command line web asset optimisation tool.
|
3
|
+
|
4
|
+
=== Features
|
5
|
+
|
6
|
+
_Sqweeze_ cuts the unnecessary bytes out of your web assets, helping you delivering your web project more fast and efficiently.
|
7
|
+
With a little help from a number of well known open source third party tools, _Sqweeze_ does the following:
|
8
|
+
|
9
|
+
* Lossless compresses .PNG, .JPEG and .GIF image assets.
|
10
|
+
* Compresses and concatenates into single files multiple Stylesheets and Javascript files.
|
11
|
+
* Embeds the compressed assets referenced into the stylesheet, using using {Data-uris}[https://developer.mozilla.org/En/The_data_URL_scheme] (for proper browsers and IE8) and {MHTML}[http://en.wikipedia.org/wiki/MHTML] (for IE6-7).
|
12
|
+
* Finally, it provides some basic functionality to linking the compressed Javascript and CSS files back to the document.
|
13
|
+
|
14
|
+
=== Installing it
|
15
|
+
|
16
|
+
Sqweeze relies on a few command-line image compression tools, namely Pngcrush, Jpegtrain, and Gifsicle, which have to be installed first.
|
17
|
+
On an Ubuntu box, you can install these by running a single command line
|
18
|
+
|
19
|
+
sudo apt-get install pngcrush gifsicle libjpeg-progs
|
20
|
+
|
21
|
+
(Mac OSX users can install the first two as Macports packages. The third (part of libjpeg) instead, has to be
|
22
|
+
{compiled manually}[http://www.phpied.com/installing-jpegtran-mac-unix-linux]. However, Jpegtrain will not be needed as long as you do not have Jpeg files into your project.)
|
23
|
+
|
24
|
+
Once installed the requirements above, you can install sqweeze, and its ruby dependencies, through ruby gems
|
25
|
+
|
26
|
+
gem install sqweeze
|
27
|
+
|
28
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'echoe'
|
4
|
+
|
5
|
+
Echoe.new('sqweeze', '0.0.1') do |p|
|
6
|
+
p.description = "A command line web-asset optimisation tool"
|
7
|
+
p.url = "http://github.com/premasagar/sqwidget-builder"
|
8
|
+
p.author = "Andrea Fiore"
|
9
|
+
p.email = "and@inventati.org"
|
10
|
+
p.spec_pattern=['spec']
|
11
|
+
p.ignore_pattern = ["doc/", 'spec/test_dir_sqweezed',"webapp"]
|
12
|
+
p.runtime_dependencies = ['hpricot >= 0.8.2','closure-compiler >=0.2.2','yui-compressor >= 0.9.1']
|
13
|
+
|
14
|
+
end
|
15
|
+
|
data/bin/sqweeze
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# rubygems
|
3
|
+
%w[rubygems yui/compressor closure-compiler hpricot].each{|lib| require lib}
|
4
|
+
# ruby standard library
|
5
|
+
%w[logger singleton yaml base64 open-uri pathname optparse].each{|lib| require lib}
|
6
|
+
|
7
|
+
# add lib sub-directories to load path
|
8
|
+
SQWEEZE_DIR=File.expand_path( File.dirname(File.dirname(__FILE__)))
|
9
|
+
$LOAD_PATH.unshift(SQWEEZE_DIR) unless $LOAD_PATH.include?(SQWEEZE_DIR)
|
10
|
+
['lib','lib/compressor', 'lib/compilers'].each do |sub_dir|
|
11
|
+
$LOAD_PATH.unshift("#{SQWEEZE_DIR}/#{sub_dir}")
|
12
|
+
end
|
13
|
+
|
14
|
+
%w[sqweezeUtils confManager compressor domCompiler
|
15
|
+
compressors/cssCompressor compressors/jsCompressor compressors/gifCompressor compressors/pngCompressor compressors/jpegCompressor
|
16
|
+
compilers/cssDomCompiler compilers/jsDomCompiler compilers/assetLinker
|
17
|
+
].each{|lib| require lib}
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
options = {}
|
23
|
+
op=OptionParser.new do |opts|
|
24
|
+
|
25
|
+
opts.banner = "Usage: sqweeze [options] SOURCE_DIR [TARGET_DIR]"
|
26
|
+
opts.program_name= 'sqweeze'
|
27
|
+
opts.on("-s", "--optimisation-strategy=ALL_IN_ONE",
|
28
|
+
"JavaScript/CSS optimisation strategy to be adopted ") do |s|
|
29
|
+
raise OptionParser::InvalidArgument unless ['all_inline','all_in_one'].include?(s)
|
30
|
+
options[:optimisation_strategy] = s.downcase.to_sym
|
31
|
+
end
|
32
|
+
|
33
|
+
opts.separator ""
|
34
|
+
opts.separator "File Selection:"
|
35
|
+
opts.on('-i','--include-files=PATTERN', "Include a file/directory pattern (e.g. images/**/*.png ) ") do |inc|
|
36
|
+
options[:include_files] = inc
|
37
|
+
end
|
38
|
+
opts.on('-e','--exclude-files=PATTERN', "Exclude a file/directory pattern (e.g. doc/**/*.* )") do |exc|
|
39
|
+
options[:exclude_files] = exc
|
40
|
+
end
|
41
|
+
opts.on('-d','--dom-documents=PATTERN', "Dom document/s to which CSS/JS should be linked (e.g. **/index.html )") do |dom|
|
42
|
+
options[:dom_documents] = dom
|
43
|
+
end
|
44
|
+
|
45
|
+
opts.separator ""
|
46
|
+
opts.separator "Image Compression:"
|
47
|
+
opts.on("--[no-]png", "do/do-not use the PNG Compressor ") do |png|
|
48
|
+
options[:compress_png] = png
|
49
|
+
end
|
50
|
+
opts.on("--[no-]jpeg", "do/do-not use the Jpeg Compressor ") do |jpeg|
|
51
|
+
options[:compress_jpeg] = jpeg
|
52
|
+
end
|
53
|
+
opts.on("--[no-]gif", "do/do-not use the GIF Compressor ") do |gif|
|
54
|
+
options[:compress_gif] = gif
|
55
|
+
end
|
56
|
+
opts.separator ""
|
57
|
+
opts.separator "Stylesheets:"
|
58
|
+
|
59
|
+
opts.on("--[no-]css", "do/do-not use the CSS Compressor ") do |css|
|
60
|
+
options[:compress_css] = css
|
61
|
+
end
|
62
|
+
opts.on("-m","--mhtml-root=[ABSOLUTE_URL]", 'An absolute url pointing at the project stylesheets directory on the web') do |mr|
|
63
|
+
# raise OptionParser::InvalidArgument unless URI(mr).absolute?
|
64
|
+
options[:mhtml_root] = mr
|
65
|
+
end
|
66
|
+
opts.separator ""
|
67
|
+
opts.separator "JavaScript:"
|
68
|
+
|
69
|
+
opts.on("--[no-]js", "do/do-not use the JS Compressor ") do |js|
|
70
|
+
options[:compress_js] = js
|
71
|
+
end
|
72
|
+
opts.on('-a','--append_scripts_to=HEAD', "Append script elements to the HEAD or the BODY of the document") do |elm|
|
73
|
+
options[:append_scripts_to] = elm
|
74
|
+
end
|
75
|
+
opts.on("-j","--default-js-compressor=YUI", "Sets the default JavaScript compressor (can be either YUI or Closure) ") do |j|
|
76
|
+
raise OptionParser::InvalidArgument unless ['yui','closure'].include?(j.downcase)
|
77
|
+
options[:default_js_compressor] = j.downcase.to_sym
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
begin
|
83
|
+
op.parse!
|
84
|
+
Proc.new { puts "Missing SOURCE_DIR argument"; exit(1) }.call unless ARGV[0]
|
85
|
+
Proc.new { puts "source directory #{ARGV[0]} does not exist, please provide a valid path"
|
86
|
+
exit(1) }.call unless File.exists?(ARGV[0])
|
87
|
+
|
88
|
+
|
89
|
+
$log=Logger.new( STDERR )
|
90
|
+
cm=ConfManager.instance
|
91
|
+
cm.prepare(ARGV[0], ARGV[1], options)
|
92
|
+
|
93
|
+
# Compress images
|
94
|
+
{ :compress_png => PngCompressor.new,
|
95
|
+
:compress_gif => GifCompressor.new,
|
96
|
+
:compress_jpeg => JpegCompressor.new
|
97
|
+
}.each do |opt, cmp|
|
98
|
+
cmp.compress unless cm.get_conf(opt) == false
|
99
|
+
end
|
100
|
+
|
101
|
+
case cm.get_conf(:optimisation_strategy)
|
102
|
+
when :all_inline
|
103
|
+
puts "not implemented yet.."
|
104
|
+
exit
|
105
|
+
|
106
|
+
|
107
|
+
when :all_in_one
|
108
|
+
{ :compress_js => JsCompressor.new,
|
109
|
+
:compress_css => CssCompressor.new
|
110
|
+
}.each do |opt, cmp|
|
111
|
+
cmp.compress unless cm.get_conf(opt) == false
|
112
|
+
end
|
113
|
+
# link assets to main HTML file
|
114
|
+
AssetLinker.new.compile unless cm.get_conf(:dom_documents).empty?
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class AssetLinker < DOMCompiler
|
2
|
+
|
3
|
+
def compile
|
4
|
+
iterate_over("link[@rel='stylesheet'], script[@src]") do |elm,doc|
|
5
|
+
# Skip if the script has an absolute link
|
6
|
+
next if elm.get_attribute('src') =~ /^http:\/\//
|
7
|
+
# Otherwise delete.
|
8
|
+
elm.parent.children.delete(elm)
|
9
|
+
end
|
10
|
+
dom_documents.each do |path|
|
11
|
+
# Append concatenated JavaScript file.
|
12
|
+
doc = Hpricot(open(path))
|
13
|
+
doc.search(@cm.get_conf(:append_scripts_to).to_s.downcase).append( "<script type='text/javascript' src='javascripts.min.js'></script>")
|
14
|
+
|
15
|
+
stylesheets_html=<<EOF
|
16
|
+
<!--[if lte IE 8]>
|
17
|
+
<link href="stylesheets.min.mhtml.css" rel="stylesheet" />
|
18
|
+
<![endif]-->
|
19
|
+
<!--[if IE 8]>
|
20
|
+
<link href="stylesheets.min.datauri.css" rel="stylesheet" />
|
21
|
+
<![endif]-->
|
22
|
+
<!--[if !IE]>
|
23
|
+
<link href="stylesheets.min.datauri.css" rel="stylesheet" />
|
24
|
+
<![endif]-->
|
25
|
+
EOF
|
26
|
+
|
27
|
+
# Append ie conditional tags
|
28
|
+
doc.search('head').append(stylesheets_html)
|
29
|
+
write_file(doc.innerHTML,path)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class CssDomCompiler < DOMCompiler
|
2
|
+
|
3
|
+
def compile
|
4
|
+
iterate_over('link[@rel="stylesheet"]') do |elm, doc|
|
5
|
+
next unless elm.has_attribute?('href') and not elm.get_attribute('href').nil?
|
6
|
+
|
7
|
+
fbody=get_resource(elm.get_attribute('href'))
|
8
|
+
|
9
|
+
# this is a bit convoluted, but it seems to be the right way of doing it
|
10
|
+
elm.parent.children.delete(elm)
|
11
|
+
|
12
|
+
style_html = "<style type=\"text/css\">\n" + css_cdata(fbody,:compress) + '</style>'
|
13
|
+
doc.search('head').append(style_html)
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def compress(fbody)
|
20
|
+
YUI::CssCompressor.new.compress(fbody)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class JsDomCompiler < DOMCompiler
|
2
|
+
|
3
|
+
def compile
|
4
|
+
iterate_over('script[@src]') do |element, doc |
|
5
|
+
|
6
|
+
res_body=get_resource(element.get_attribute('src'))
|
7
|
+
element.remove_attribute('src')
|
8
|
+
# do the YUI/CLOSURE thing here
|
9
|
+
element.innerHTML=js_cdata(res_body,:compress)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
def compress(fbody)
|
15
|
+
unless @cm.default_js_compressor == :closure
|
16
|
+
compressor, method = YUI::JavaScriptCompressor.new( :munge => true), :compress
|
17
|
+
else
|
18
|
+
compressor, method = Closure::Compiler.new, :compiler
|
19
|
+
end
|
20
|
+
compressor.send(method,fbody)
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
end
|
data/lib/compressor.rb
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
# Pseudo-abstract class inherited by all the other classes performing asset-compression operations
|
2
|
+
|
3
|
+
class Compressor
|
4
|
+
include SqweezeUtils
|
5
|
+
|
6
|
+
# Sets the file extensions that a compressor accepts
|
7
|
+
#
|
8
|
+
# *Note*: As this class cannot be instanciated directly, this method is only used by subclasses.
|
9
|
+
def initialize(input_file_extensions)
|
10
|
+
|
11
|
+
# Behave as a pseudo abstract class
|
12
|
+
raise "Cannot instantiate #{self.class} directly" if self.class == Compressor
|
13
|
+
|
14
|
+
@cm=ConfManager.instance
|
15
|
+
@input_file_extensions=input_file_extensions
|
16
|
+
|
17
|
+
|
18
|
+
# Get the project file list from the configuration manager
|
19
|
+
@input_files=@cm.files
|
20
|
+
|
21
|
+
# The commands used by this compressor,
|
22
|
+
# listed in order of priority
|
23
|
+
|
24
|
+
@commands={}
|
25
|
+
|
26
|
+
# Set the default shell command to use for this compressor.
|
27
|
+
# issue: what's the point of calling this default command and not just default..
|
28
|
+
@default_command=nil
|
29
|
+
|
30
|
+
# whether or not concatenating the input files (it is the case of css and javascripts)
|
31
|
+
@concatenate_input=false
|
32
|
+
|
33
|
+
# Store the overall byte weight of the assets, before compressions
|
34
|
+
@byteweight_before = collect_filepaths.inject(0){|sum,f| sum+File.size(f)}
|
35
|
+
|
36
|
+
#set later, after compression
|
37
|
+
@byteweight_after = 0
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
attr_reader :input_file_extensions, #something here
|
42
|
+
:byteweight_before,
|
43
|
+
:byteweight_after
|
44
|
+
|
45
|
+
|
46
|
+
# Sets the system command to be invoked by the compressor.
|
47
|
+
#
|
48
|
+
# This raises a runtime error if the third party command cannot be found in the file system.
|
49
|
+
def set_command(libname,command)
|
50
|
+
|
51
|
+
raise "missing library #{libname}" unless @cm.get_conf(:bin_paths).keys.include?(libname)
|
52
|
+
@default_command=libname if @commands.empty?
|
53
|
+
@commands[libname]=command
|
54
|
+
end
|
55
|
+
|
56
|
+
# Turns a string or an array of strings containing several file extension names into regular expressions.
|
57
|
+
|
58
|
+
def filextension2regexpstr(ext=@input_file_extensions)
|
59
|
+
if @input_file_extensions.is_a?(Array) and @input_file_extensions.size > 1
|
60
|
+
"(#{@input_file_extensions.collect{|ext|"\.#{ext}"}.join('|')})$"
|
61
|
+
else
|
62
|
+
"\.#{@input_file_extensions}$"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
# Collects the paths of files having the compressor extension name.
|
68
|
+
def collect_filepaths
|
69
|
+
exp_str = filextension2regexpstr
|
70
|
+
@cm.files.select{|path| path =~ Regexp.new(exp_str,true) }
|
71
|
+
end
|
72
|
+
|
73
|
+
# Applies a system command to a list of file paths.
|
74
|
+
#
|
75
|
+
# This method is overridden by both CssCompressor and JsCompressor, as these two classes do not rely on
|
76
|
+
# command line executable but use ruby bindings to YUI and Google Closure.
|
77
|
+
|
78
|
+
def process(inputpath,cmd=nil)
|
79
|
+
output_path =@cm.get_target_path(inputpath)
|
80
|
+
|
81
|
+
cl= cmd.gsub('%executable%', @cm.get_conf(:bin_paths)[@default_command]).
|
82
|
+
gsub('%input%',inputpath).
|
83
|
+
gsub('%output%', output_path)
|
84
|
+
system(cl)
|
85
|
+
$log.debug("run command #{cl}, pid=#{$?.pid} exitstatus=#{$?.exitstatus}")
|
86
|
+
output_path
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
# Iterates over the list of file paths matching the compressor extension/s and applies the process method to each of them.
|
91
|
+
|
92
|
+
def compress
|
93
|
+
files=@input_files=collect_filepaths
|
94
|
+
|
95
|
+
# This will consist of only an entry (the concatenated file body)
|
96
|
+
# when compressing javascript or css files
|
97
|
+
|
98
|
+
files=[concatenate_files] if @concatenate_input
|
99
|
+
cmd= (@commands.empty?)? nil : @commands[ @default_command ]
|
100
|
+
|
101
|
+
files.each do |path|
|
102
|
+
output_path=process(path,cmd)
|
103
|
+
size_check(path,output_path) unless %w(.css .js).include?( File.extname(output_path))
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Makes sure that the byteweight of a compressed file is not larger that the original one.
|
108
|
+
|
109
|
+
def size_check(input_path,output_path)
|
110
|
+
before_size, after_size = byteweight(input_path), byteweight(output_path)
|
111
|
+
# if the compressed file is bigger than the original one, copy the original in the target dir
|
112
|
+
if after_size < before_size
|
113
|
+
$log.info("compressed #{input_path} to the #{ compression_percentage(before_size,after_size)}% of its original size (from: #{before_size} to #{after_size} bytes ) ")
|
114
|
+
@byteweight_after+=after_size
|
115
|
+
else
|
116
|
+
$log.debug("Oppss!!! output(#{after_size}) >= input(#{before_size}), using the original file #{input_path} ")
|
117
|
+
FileUtils.cp(input_path,output_path)
|
118
|
+
@byteweight_after+=before_size
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Concatenates several files into a single string (used in both CSS and JS compression).
|
123
|
+
|
124
|
+
def concatenate_files
|
125
|
+
@input_files.collect{|f|File.open(f,'r').read}.join("\n")
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# Compresses stylesheets using the YUI compressor, creating three new files in the target directory:
|
2
|
+
# [<code>stylesheets.min.css</code>]
|
3
|
+
# compressed and concatenated stylesheets without embedded assets (suitable for all browsers).
|
4
|
+
#
|
5
|
+
# [<code>stylesheets.datauir.css</code>]
|
6
|
+
# compressed and concatenated stylesheets with assets embedded as data-uris (suitable for both Webkit and Geko based browser, and ie8).
|
7
|
+
#
|
8
|
+
# [<code>stylesheets.mhtml.css</code>]
|
9
|
+
# compressed and concatenated stylesheets with assets embedded as data-uris (suitable for IE6 and IE7).
|
10
|
+
#
|
11
|
+
# *Note*: some of the methods used by this class are copied from Jash kenas's excellent {Jammit}[http://github.com/documentcloud/jammit/], an asset optimisation tool for Rails.
|
12
|
+
|
13
|
+
class CssCompressor < Compressor
|
14
|
+
|
15
|
+
# 32k maximum size for embeddable images (an IE8 limitation).
|
16
|
+
MAX_IMAGE_SIZE = 32768
|
17
|
+
|
18
|
+
# CSS asset-embedding regexes for URL rewriting.
|
19
|
+
EMBED_DETECTOR = /url\(['"]?([^\s)]+\.[a-z]+)(\?\d+)?['"]?\)/
|
20
|
+
|
21
|
+
# MHTML file constants.
|
22
|
+
MHTML_START = "/*\nContent-Type: multipart/related; boundary=\"SQWEEZED_ASSET\"\n"
|
23
|
+
MHTML_SEPARATOR= "--SQWEEZED_ASSET"
|
24
|
+
MHTML_END = "*/\n"
|
25
|
+
|
26
|
+
def initialize
|
27
|
+
super('css')
|
28
|
+
|
29
|
+
@concatenate_input=true
|
30
|
+
@concatenated_file=nil
|
31
|
+
# This hash is populated while generating the data uris
|
32
|
+
# in order to be reused later in the MHTML file
|
33
|
+
@assets={}
|
34
|
+
# TODO fonts..
|
35
|
+
end
|
36
|
+
|
37
|
+
def process(input_str,cmd=nil)
|
38
|
+
fout= (@concatenate_input)? "#{@cm.target_dir}/all.min.css" : @cm.get_target_path(inputpath)
|
39
|
+
compressed_output=YUI::CssCompressor.new.compress(input_str)
|
40
|
+
|
41
|
+
unless compressed_output.chomp.empty?
|
42
|
+
write_file(compressed_output,"#{@cm.target_dir}/stylesheets.min.css")
|
43
|
+
embed_datauris( compressed_output )
|
44
|
+
embed_mhtml( compressed_output ) if @cm.get_conf(:mhtml_root)
|
45
|
+
end
|
46
|
+
# this return is pointless
|
47
|
+
fout
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
private
|
53
|
+
def mhtml_location(path)
|
54
|
+
p=Pathname.new(path)
|
55
|
+
p.relative_path_from( Pathname.new(@cm.target_dir))
|
56
|
+
end
|
57
|
+
|
58
|
+
def embed_datauris(compressed_css)
|
59
|
+
out=compressed_css.gsub(EMBED_DETECTOR) do |url|
|
60
|
+
compressed_asset_path=remap_filepath($1)
|
61
|
+
mime_t=mime_type(compressed_asset_path)
|
62
|
+
if compressed_asset_path and File.exists?(compressed_asset_path) and File.size(compressed_asset_path) < MAX_IMAGE_SIZE and mime_t
|
63
|
+
base64_asset=encoded_contents( compressed_asset_path )
|
64
|
+
$log.debug("file:#{compressed_asset_path}; mime-type: #{mime_type($1)}#")
|
65
|
+
# label the image
|
66
|
+
@assets[ compressed_asset_path ] = base64_asset
|
67
|
+
"url(\"data:#{mime_t};charset=utf-8;base64,#{base64_asset}\")"
|
68
|
+
else
|
69
|
+
"url(#{$1})"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
write_file(out,"#{@cm.target_dir}/stylesheets.min.datauri.css")
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
def embed_mhtml(compressed_css)
|
79
|
+
mhtml= MHTML_START
|
80
|
+
|
81
|
+
@assets.each do |mhtml_loc,base64|
|
82
|
+
mhtml <<"
|
83
|
+
#{MHTML_SEPARATOR}
|
84
|
+
Content-location: #{ mhtml_loc }
|
85
|
+
Content-Transfer-Encoding:base64
|
86
|
+
|
87
|
+
#{base64}\n"
|
88
|
+
end
|
89
|
+
mhtml << "*/\n"
|
90
|
+
mhtml << compressed_css.gsub(EMBED_DETECTOR) do |css|
|
91
|
+
compressed_asset_path=remap_filepath($1)
|
92
|
+
if compressed_asset_path
|
93
|
+
"url(mhtml:#{@cm.get_conf(:mhtml_root).gsub(/\/$/,'')}/stylesheets.min.mhtml.css!#{mhtml_location( compressed_asset_path)})"
|
94
|
+
else
|
95
|
+
"url(#{$1})"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
write_file(mhtml,"#{@cm.target_dir}/stylesheets.min.mhtml.css")
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class JsCompressor < Compressor
|
2
|
+
|
3
|
+
def initialize
|
4
|
+
super('js')
|
5
|
+
@concatenate_input=true
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
def process(input_str,cmd=nil)
|
10
|
+
unless @cm.get_conf(:default_js_compressor) == :closure
|
11
|
+
compressor, method = YUI::JavaScriptCompressor.new( :munge => true), :compress
|
12
|
+
else
|
13
|
+
compressor, method = Closure::Compiler.new, :compiler
|
14
|
+
end
|
15
|
+
|
16
|
+
fout= (@concatenate_input)? "#{@cm.target_dir}/javascripts.min.js" : @cm.get_target_path(inputpath)
|
17
|
+
|
18
|
+
File.open(fout,'w') do |f|
|
19
|
+
f.write(compressor.send( method, input_str))
|
20
|
+
end
|
21
|
+
|
22
|
+
fout
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
|
data/lib/confManager.rb
ADDED
@@ -0,0 +1,191 @@
|
|
1
|
+
# Main component for handling Sqweeze's file and command-line configuration parameters
|
2
|
+
|
3
|
+
|
4
|
+
class ConfManager
|
5
|
+
include Singleton
|
6
|
+
# Class constructor.
|
7
|
+
#
|
8
|
+
# As ConfManager implements the singleton pattern, it is actually instanciated only once.
|
9
|
+
# The same instance might be retrieved from different places by calling the method:
|
10
|
+
#
|
11
|
+
# <code>ConfManager.instance()</code>
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@conf_filename='.sqweeze.yml'
|
15
|
+
@source_dir=nil
|
16
|
+
@target_dir=nil
|
17
|
+
@files=[]
|
18
|
+
|
19
|
+
@conf={
|
20
|
+
:bin_paths => {},
|
21
|
+
:dom_documents => [],
|
22
|
+
:include_files => [],
|
23
|
+
:exclude_files => [],
|
24
|
+
:compress_png => true,
|
25
|
+
:compress_jpeg => true,
|
26
|
+
:compress_gif => true,
|
27
|
+
:compress_js => true,
|
28
|
+
:compress_css => true,
|
29
|
+
:append_scripts_to => :head,
|
30
|
+
:default_js_compressor => :yui,
|
31
|
+
:optimisation_strategy => :all_in_one
|
32
|
+
}
|
33
|
+
end
|
34
|
+
attr_reader :target_dir,:source_dir,
|
35
|
+
:files,:conf_filename,:conf
|
36
|
+
|
37
|
+
|
38
|
+
# Setter method used to populate the <code>@conf</code> attribute with key value pairs.
|
39
|
+
#
|
40
|
+
# *Note*: string keys are automatically converted to symbols.
|
41
|
+
|
42
|
+
|
43
|
+
def set_conf(key,value);@conf[key.to_sym]=value;end
|
44
|
+
|
45
|
+
# Getter method for retrieving configuration values.
|
46
|
+
|
47
|
+
def get_conf(key);@conf[key.to_sym];end
|
48
|
+
|
49
|
+
# Sets the source directory, the target directory, and parse configuration files.
|
50
|
+
#
|
51
|
+
# [source] the source directory
|
52
|
+
#
|
53
|
+
# [target] the target directory
|
54
|
+
#
|
55
|
+
# [override_conf] a Hash which may be used to override file-based configuration.
|
56
|
+
|
57
|
+
def prepare(source,target=nil,override_conf={})
|
58
|
+
|
59
|
+
@source_dir=source
|
60
|
+
@target_dir=unless target
|
61
|
+
"#{File.basename(source)}_sqweezed"
|
62
|
+
else
|
63
|
+
target
|
64
|
+
end
|
65
|
+
|
66
|
+
write_globalconf
|
67
|
+
# Parses the global configuration file in $HOME.
|
68
|
+
parse_conf
|
69
|
+
# Parses the local configuration file in source directory.
|
70
|
+
local_conf=mkpath(@conf_filename)
|
71
|
+
parse_conf(local_conf) if File.exists?(local_conf)
|
72
|
+
|
73
|
+
# CLI/Overrides of the values already set in config files.
|
74
|
+
override_conf.each{|k,v| set_conf(k, v)} unless override_conf.empty?
|
75
|
+
|
76
|
+
# Creates the list of the files in the project directory.
|
77
|
+
|
78
|
+
list_files
|
79
|
+
copy_source
|
80
|
+
end
|
81
|
+
|
82
|
+
# Copies the source into the target directory.
|
83
|
+
def copy_source
|
84
|
+
FileUtils.cp_r(@source_dir,@target_dir)
|
85
|
+
# avoid nesting into each other multiple copies of the same directory
|
86
|
+
nested_dir=[@target_dir,File.basename(@source_dir)].join('/')
|
87
|
+
FileUtils.rm_r(nested_dir) if File.directory?(nested_dir)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Remaps a filepath from the source to the target directory.
|
91
|
+
#
|
92
|
+
# TODO:check if this works with relative paths (i.e. <code>../imgs/bar.png</code>)
|
93
|
+
|
94
|
+
def get_target_path(infile_path)
|
95
|
+
infile_path.gsub( Regexp.new("^#{@source_dir}"), @target_dir)
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
# Generates a file pattern suitable to be expanded by ruby's {Dir[]}[http://ruby-doc.org/core/classes/Dir.html] method.
|
100
|
+
|
101
|
+
def mkpath(pattern,dir=@source_dir)
|
102
|
+
dir.to_a.push(pattern).join('/')
|
103
|
+
end
|
104
|
+
|
105
|
+
# Defines a global <code>.sqweeze.yml</code> file and places it in the user's home directory.
|
106
|
+
#
|
107
|
+
# The golobal config files sets the default path of the image compression binaries
|
108
|
+
# (see @conf[:bin_paths]).
|
109
|
+
|
110
|
+
def write_globalconf
|
111
|
+
unless File.exists?("#{ENV['HOME']}/#{@conf_filename}")
|
112
|
+
File.open("#{ENV['HOME']}/#{@conf_filename}",'w') do |f|
|
113
|
+
f.write("bin_paths:
|
114
|
+
- pngcrush: /usr/bin/pngcrush
|
115
|
+
- jpegtran: /usr/bin/jpegtran
|
116
|
+
- gifsicle: /usr/bin/gifsicle
|
117
|
+
")
|
118
|
+
f.close
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Parses configuration files and sets user-defined file inclusion/exlusion patterns.
|
124
|
+
|
125
|
+
def parse_conf(configfile="#{ENV['HOME']}/#{@conf_filename}")
|
126
|
+
$log.debug("Parsing configuration file: #{configfile}")
|
127
|
+
conf=YAML::load_file( configfile )
|
128
|
+
|
129
|
+
bin_paths={}
|
130
|
+
# do not select commands if their path cannot be found on disk
|
131
|
+
conf['bin_paths'].each do |h|
|
132
|
+
if File.exists?(h.values.first)
|
133
|
+
bin_paths[h.keys.first.to_sym] = h.values.first
|
134
|
+
else
|
135
|
+
$log.warn("Command #{h.keys.first} not found in #{h.values.first}")
|
136
|
+
end
|
137
|
+
end
|
138
|
+
set_conf(:bin_paths,bin_paths) unless bin_paths.empty?
|
139
|
+
|
140
|
+
# Expand the dom document pattern excluding the files located in the source directory.
|
141
|
+
if conf['dom_documents']
|
142
|
+
|
143
|
+
domdoc_file_patterns = Dir[conf['dom_documents']].collect{|f| f.gsub(Regexp.new("^#{@source_dir}"),@target_dir)}
|
144
|
+
set_conf(:dom_documents, domdoc_file_patterns)
|
145
|
+
end
|
146
|
+
|
147
|
+
# Sets the favourite js compressor ( can either be :yui or :closure, defaults on YUI)
|
148
|
+
compressor = ( conf['default_js_compressor'] == :closure) ? :closure : :yui
|
149
|
+
set_conf(:default_js_compressor, compressor)
|
150
|
+
|
151
|
+
# others..
|
152
|
+
%w(include exclude).each {|k| set_conf(k, conf[k].to_a)}
|
153
|
+
%w(optimisation_strategy append_scripts_to).each{|k| set_conf(k,conf[k]) if conf[k]}
|
154
|
+
end
|
155
|
+
|
156
|
+
# Explodes the inclusion/exclusion patterns provided by the user into a list, and populates the @files attribute.
|
157
|
+
|
158
|
+
def list_files
|
159
|
+
# unless the user defined file inclusion list is empty, select only the files specified by the user.
|
160
|
+
# Otherwise consider all the files in the project directory as potentially compressible.
|
161
|
+
|
162
|
+
@files = unless get_conf(:include).empty?
|
163
|
+
files=get_files( get_conf(:include));$log.debug("Including #{files.size} file/s from user list")
|
164
|
+
files
|
165
|
+
else
|
166
|
+
get_files
|
167
|
+
end
|
168
|
+
|
169
|
+
# always exclude files explicitly blacklisted by the use
|
170
|
+
exclude_files=get_files(get_conf(:exclude))
|
171
|
+
|
172
|
+
|
173
|
+
$log.debug("Excluding #{exclude_files.size} file/s from user list")
|
174
|
+
@files -= exclude_files
|
175
|
+
$log.info("#{@files.size} file/s found")
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
# Get all the files matching an array of patterns
|
180
|
+
#
|
181
|
+
# (Any file expansion patterns accepted ruby's Dir[] method can be used).
|
182
|
+
|
183
|
+
def get_files(pathlist=['**/*'])
|
184
|
+
pathlist.collect{|pattern|
|
185
|
+
|
186
|
+
Dir[ mkpath(pattern) ].
|
187
|
+
reject{|f|File.directory?(f) or not File.exists?(f)}
|
188
|
+
}.flatten
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
data/lib/domCompiler.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# Pseudo-abstract inherited by all classes doing dom manipulations
|
2
|
+
class DOMCompiler
|
3
|
+
include SqweezeUtils
|
4
|
+
attr_reader :dom_documents
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
# @dom_extnames=['.html','.svg']
|
8
|
+
@cm=ConfManager.instance
|
9
|
+
#if @cm.link_assets_to and not @cm.link_assets_to.empty?
|
10
|
+
@dom_documents=@cm.get_conf(:dom_documents).to_a
|
11
|
+
end
|
12
|
+
# Retrieves a resource, being this either a URL or a file.
|
13
|
+
def get_resource(path_or_url)
|
14
|
+
f=open(remap_filepath(path_or_url))
|
15
|
+
(f.is_a? File)? f.read : f
|
16
|
+
end
|
17
|
+
# Iterates over a DOM element and allows to apply a custom block over it.
|
18
|
+
|
19
|
+
def iterate_over(selector)
|
20
|
+
@dom_documents.each do |path|
|
21
|
+
doc=Hpricot(open(path))
|
22
|
+
if doc
|
23
|
+
doc.search(selector).each do |element|
|
24
|
+
|
25
|
+
#$log.debug..
|
26
|
+
yield(element, doc)
|
27
|
+
# save document
|
28
|
+
#write_file(doc.innerHTML, [@cm.target_dir, File.basename(path) ].join('/') )
|
29
|
+
write_file(doc.innerHTML, path )
|
30
|
+
end
|
31
|
+
else
|
32
|
+
$log.error("DOMCompiler cannot parse #{path}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Wraps a string into CDATA escaped in order to be embedded into a <code><script></code> element.
|
38
|
+
# [text] a text string
|
39
|
+
# [callback] an instance method used to process the string (normally compile).
|
40
|
+
def js_cdata(text,callback)
|
41
|
+
["\n<!--//--><![CDATA[//><!--", self.send(callback,text), "//--><!]]>\n"].join("\n")
|
42
|
+
end
|
43
|
+
|
44
|
+
# Wraps a string into CDATA escaped in order to be embedded into a <code><style></code> element.
|
45
|
+
# [text] a text string
|
46
|
+
# [callback] an instance method used to process the string (normally compile).
|
47
|
+
def css_cdata(text,callback)
|
48
|
+
["/* <![CDATA[ */", self.send(callback,text), "/* ]]> */\n"].join("\n")
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
data/lib/sqweezeUtils.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
module SqweezeUtils
|
2
|
+
|
3
|
+
# Mapping from extension to mime-type of all embeddable assets.
|
4
|
+
EMBED_MIME_TYPES = {
|
5
|
+
'.png' => 'image/png',
|
6
|
+
'.jpg' => 'image/jpeg',
|
7
|
+
'.jpeg' => 'image/jpeg',
|
8
|
+
'.gif' => 'image/gif',
|
9
|
+
'.tif' => 'image/tiff',
|
10
|
+
'.tiff' => 'image/tiff',
|
11
|
+
'.ttf' => 'font/truetype',
|
12
|
+
'.otf' => 'font/opentype'
|
13
|
+
}
|
14
|
+
|
15
|
+
def write_file(fbody,fpath)
|
16
|
+
File.open(fpath,'w') do |f|
|
17
|
+
f.write(fbody)
|
18
|
+
f.close
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Grab the mime-type of an asset, by filename.
|
23
|
+
def mime_type(asset_path)
|
24
|
+
EMBED_MIME_TYPES[File.extname(asset_path)] if asset_path
|
25
|
+
end
|
26
|
+
|
27
|
+
# Remaps a file in the source directory to its compressed
|
28
|
+
# version in the target directory
|
29
|
+
#
|
30
|
+
# if the resource is an absolute URL fine,
|
31
|
+
# Otherwise, if the resource is a relative url in the source dir, try
|
32
|
+
# to map it to its compressed version in the target directory
|
33
|
+
|
34
|
+
def remap_filepath(path)
|
35
|
+
path=Pathname.new(path)
|
36
|
+
parent_dir, path_basename = path.parent, path.basename
|
37
|
+
is_absolute = URI.parse(path).absolute?
|
38
|
+
unless is_absolute
|
39
|
+
find_file_in_targetdir( [parent_dir, path_basename].join('/'))
|
40
|
+
else
|
41
|
+
path.to_s
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Return the Base64-encoded contents of an asset on a single line.
|
46
|
+
def encoded_contents(asset_path)
|
47
|
+
data = open(asset_path, 'rb'){|f| f.read }
|
48
|
+
Base64.encode64(data).gsub(/\n/, '')
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
# Gets the byte weight of input strames, wether these are file paths or just strings
|
53
|
+
|
54
|
+
def byteweight(path_or_string)
|
55
|
+
path_or_string="" if path_or_string.nil?
|
56
|
+
|
57
|
+
if File.exists?(path_or_string)
|
58
|
+
File.size(path_or_string)
|
59
|
+
else
|
60
|
+
bweight=0
|
61
|
+
path_or_string.each_byte{|b|bweight+=1}
|
62
|
+
bweight
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def compression_percentage(before_bweight,after_bweight)
|
67
|
+
sprintf('%.2f',after_bweight/before_bweight.to_f * 100)
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
# Find a file in the target directory
|
72
|
+
# endpath is a string containing parent directory and file name
|
73
|
+
# (e.g imgs/separator.png)
|
74
|
+
|
75
|
+
# TODO: rewrite this! (it sucks..)
|
76
|
+
|
77
|
+
def find_file_in_targetdir(endpath)
|
78
|
+
pattern= [@cm.target_dir,"**/*#{File.extname(endpath)}"].join('/')
|
79
|
+
#puts "searcing for files in #{pattern} ending with #{endpath}"
|
80
|
+
Dir[pattern].find{|path| path =~ Regexp.new("#{endpath}$")}
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'sqw_spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe ConfManager do
|
5
|
+
context "Starting up" do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@cm = ConfManager.instance
|
9
|
+
end
|
10
|
+
|
11
|
+
after(:each) do
|
12
|
+
@cm=nil
|
13
|
+
# clean up config files
|
14
|
+
%w( ENV['home'] test_dir ).each do |f|
|
15
|
+
f << "/.sqweeze.yml"
|
16
|
+
FileUtils.rm(f) if File.exists?(f)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it "Should create a .sqweeze.yml file in the home directory" do
|
21
|
+
@cm.prepare('test_dir')
|
22
|
+
File.exists?("#{ENV['HOME']}/.sqweeze.yml").should be_true
|
23
|
+
end
|
24
|
+
|
25
|
+
it "Should select the list of files provided by the user if the *include:* section of the .sqweeze.yml is not empty" do
|
26
|
+
extra_lines= ["include:","- js/**/*.js",'- color/**/*.png']
|
27
|
+
write_configfile(extra_lines[0..1].join("\n"))
|
28
|
+
@cm.prepare('test_dir')
|
29
|
+
@cm.should have(3).files
|
30
|
+
|
31
|
+
write_configfile(extra_lines.join("\n"))
|
32
|
+
@cm.prepare('test_dir')
|
33
|
+
@cm.should have(5).files
|
34
|
+
end
|
35
|
+
|
36
|
+
it "Should select all files in the project if the include: section of .sqweeze.yml is left empty" do
|
37
|
+
project_file_count= Dir['test_dir/**/*'].reject{|f| File.directory?(f)}.size
|
38
|
+
@cm.prepare('test_dir')
|
39
|
+
@cm.should have(project_file_count).files
|
40
|
+
end
|
41
|
+
|
42
|
+
it "Should always exclude the files specified by the user in the .sqweeze.yml exclude section " do
|
43
|
+
write_configfile(["exclude:","- js/**/*.js"].join("\n"))
|
44
|
+
project_file_count= Dir['test_dir/**/*'].reject{|f| File.directory?(f)}.size
|
45
|
+
@cm.prepare('test_dir')
|
46
|
+
@cm.should have(46).files
|
47
|
+
end
|
48
|
+
|
49
|
+
it "Should search *dom_documents* in the the target directory " do
|
50
|
+
write_configfile("dom_documents: test_dir/*/page.tpl.php")
|
51
|
+
@cm.prepare('test_dir')
|
52
|
+
@cm.get_conf(:dom_documents).should include('test_dir_sqweezed/tpl/page.tpl.php')
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require '../lib/confManager'
|
2
|
+
require '../lib/DomCompiler'
|
3
|
+
require '../lib/jsDomCompiler'
|
4
|
+
require '../lib/cssDomCompiler'
|
5
|
+
require 'sqw_spec_helper'
|
6
|
+
|
7
|
+
describe DOMCompiler do
|
8
|
+
before(:each) do
|
9
|
+
wget_webpage('http://www.dreamhost.com/domains.html','dom-testdir')
|
10
|
+
cm = ConfManager.instance
|
11
|
+
cm.prepare('dom-testdir','dom-testdir-build')
|
12
|
+
@js_c=JSDOMCompiler.new
|
13
|
+
end
|
14
|
+
|
15
|
+
after(:each) do
|
16
|
+
FileUtils.rm_r('dom-testdir')
|
17
|
+
FileUtils.rm_r('dom-testdir-build')
|
18
|
+
end
|
19
|
+
|
20
|
+
it "(all subclasses) should look for *dom_documents* in target directory" do
|
21
|
+
@js_c.should have(1).dom_documents
|
22
|
+
@js_c.dom_documents.should include('dom-testdir-build/index.html')
|
23
|
+
end
|
24
|
+
|
25
|
+
it "Should fill each script element having a src attribute with the compressed content of the javascript file therin referenciated" do
|
26
|
+
@js_c.compile
|
27
|
+
|
28
|
+
Hpricot( open('dom-testdir-build/index.html')).search('script').each do |element|
|
29
|
+
element.innerHTML.should_not be_empty
|
30
|
+
element.get_attribute('src').should be_nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it "Should fill each link tag having a href attribute with the compressed content of the css file therein referenced" do
|
35
|
+
@css_c=CSSDOMCompiler.new
|
36
|
+
@css_c.compile()
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
@@ -0,0 +1,24 @@
|
|
1
|
+
SQW_CONF_FILE='test_dir/.sqweeze.yml'
|
2
|
+
SQW_FBODY=<<EOF
|
3
|
+
bin_paths:
|
4
|
+
- pngcrush: /usr/bin/pngcrush
|
5
|
+
- jpegtran: /usr/bin/jpegtran
|
6
|
+
- gifsicle: /usr/bin/gifsicle
|
7
|
+
#- cssembed: /home/and/installed/cssembed.jar
|
8
|
+
EOF
|
9
|
+
|
10
|
+
def write_configfile(extra_lines='')
|
11
|
+
fbody = SQW_FBODY + extra_lines
|
12
|
+
f=File.open(SQW_CONF_FILE,'w')
|
13
|
+
f.write( fbody)
|
14
|
+
f.close
|
15
|
+
end
|
16
|
+
|
17
|
+
def delete_configfile
|
18
|
+
FileUtils.rm_r(SQW_CONF_FILE) if File.exists?(SQW_CONF_FILE)
|
19
|
+
end
|
20
|
+
|
21
|
+
def wget_webpage(url,dir_prefix)
|
22
|
+
domain=URI.parse(url).host
|
23
|
+
system("wget --no-parent --timestamping --convert-links --page-requisites --no-directories --no-host-directories -erobots=off --quiet --directory-prefix=#{dir_prefix} #{url}")
|
24
|
+
end
|
data/sqweeze.gemspec
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{sqweeze}
|
5
|
+
s.version = "0.0.2"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Andrea Fiore"]
|
9
|
+
s.date = %q{2010-05-01}
|
10
|
+
s.default_executable = %q{sqweeze}
|
11
|
+
s.description = %q{A command line web-asset optimisation tool}
|
12
|
+
s.email = %q{and@inventati.org}
|
13
|
+
s.executables = ["sqweeze"]
|
14
|
+
s.extra_rdoc_files = ["README.rdoc", "bin/sqweeze", "lib/compilers/assetLinker.rb", "lib/compilers/cssDomCompiler.rb", "lib/compilers/jsDomCompiler.rb", "lib/compressor.rb", "lib/compressors/cssCompressor.rb", "lib/compressors/gifCompressor.rb", "lib/compressors/jpegCompressor.rb", "lib/compressors/jsCompressor.rb", "lib/compressors/pngCompressor.rb", "lib/confManager.rb", "lib/domCompiler.rb", "lib/sqweezeUtils.rb"]
|
15
|
+
s.files = ["Manifest", "README.rdoc", "Rakefile", "bin/sqweeze", "lib/compilers/assetLinker.rb", "lib/compilers/cssDomCompiler.rb", "lib/compilers/jsDomCompiler.rb", "lib/compressor.rb", "lib/compressors/cssCompressor.rb", "lib/compressors/gifCompressor.rb", "lib/compressors/jpegCompressor.rb", "lib/compressors/jsCompressor.rb", "lib/compressors/pngCompressor.rb", "lib/confManager.rb", "lib/domCompiler.rb", "lib/sqweezeUtils.rb", "spec/confManager_spec.rb", "spec/domCompiler_spec.rb", "spec/sqw_spec_helper.rb", "sqweeze.gemspec"]
|
16
|
+
s.homepage = %q{http://github.com/premasagar/sqwidget-builder}
|
17
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Sqweeze", "--main", "README.rdoc"]
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
s.rubyforge_project = %q{sqweeze}
|
20
|
+
s.rubygems_version = %q{1.3.5}
|
21
|
+
s.summary = %q{A command line web-asset optimisation tool}
|
22
|
+
|
23
|
+
if s.respond_to? :specification_version then
|
24
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
25
|
+
s.specification_version = 3
|
26
|
+
|
27
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
28
|
+
s.add_runtime_dependency(%q<hpricot>, [">= 0", "= 0.8.2"])
|
29
|
+
s.add_runtime_dependency(%q<closure-compiler>, [">= 0.2.2"])
|
30
|
+
s.add_runtime_dependency(%q<yui-compressor>, [">= 0", "= 0.9.1"])
|
31
|
+
else
|
32
|
+
s.add_dependency(%q<hpricot>, [">= 0", "= 0.8.2"])
|
33
|
+
s.add_dependency(%q<closure-compiler>, [">= 0.2.2"])
|
34
|
+
s.add_dependency(%q<yui-compressor>, [">= 0", "= 0.9.1"])
|
35
|
+
end
|
36
|
+
else
|
37
|
+
s.add_dependency(%q<hpricot>, [">= 0", "= 0.8.2"])
|
38
|
+
s.add_dependency(%q<closure-compiler>, [">= 0.2.2"])
|
39
|
+
s.add_dependency(%q<yui-compressor>, [">= 0", "= 0.9.1"])
|
40
|
+
end
|
41
|
+
end
|
metadata
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sqweeze
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
version: 0.0.2
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Andrea Fiore
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-05-01 00:00:00 +01:00
|
18
|
+
default_executable: sqweeze
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: hpricot
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
- - "="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
segments:
|
33
|
+
- 0
|
34
|
+
- 8
|
35
|
+
- 2
|
36
|
+
version: 0.8.2
|
37
|
+
type: :runtime
|
38
|
+
version_requirements: *id001
|
39
|
+
- !ruby/object:Gem::Dependency
|
40
|
+
name: closure-compiler
|
41
|
+
prerelease: false
|
42
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
- 2
|
49
|
+
- 2
|
50
|
+
version: 0.2.2
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: yui-compressor
|
55
|
+
prerelease: false
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
- - "="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
segments:
|
66
|
+
- 0
|
67
|
+
- 9
|
68
|
+
- 1
|
69
|
+
version: 0.9.1
|
70
|
+
type: :runtime
|
71
|
+
version_requirements: *id003
|
72
|
+
description: A command line web-asset optimisation tool
|
73
|
+
email: and@inventati.org
|
74
|
+
executables:
|
75
|
+
- sqweeze
|
76
|
+
extensions: []
|
77
|
+
|
78
|
+
extra_rdoc_files:
|
79
|
+
- README.rdoc
|
80
|
+
- bin/sqweeze
|
81
|
+
- lib/compilers/assetLinker.rb
|
82
|
+
- lib/compilers/cssDomCompiler.rb
|
83
|
+
- lib/compilers/jsDomCompiler.rb
|
84
|
+
- lib/compressor.rb
|
85
|
+
- lib/compressors/cssCompressor.rb
|
86
|
+
- lib/compressors/gifCompressor.rb
|
87
|
+
- lib/compressors/jpegCompressor.rb
|
88
|
+
- lib/compressors/jsCompressor.rb
|
89
|
+
- lib/compressors/pngCompressor.rb
|
90
|
+
- lib/confManager.rb
|
91
|
+
- lib/domCompiler.rb
|
92
|
+
- lib/sqweezeUtils.rb
|
93
|
+
files:
|
94
|
+
- Manifest
|
95
|
+
- README.rdoc
|
96
|
+
- Rakefile
|
97
|
+
- bin/sqweeze
|
98
|
+
- lib/compilers/assetLinker.rb
|
99
|
+
- lib/compilers/cssDomCompiler.rb
|
100
|
+
- lib/compilers/jsDomCompiler.rb
|
101
|
+
- lib/compressor.rb
|
102
|
+
- lib/compressors/cssCompressor.rb
|
103
|
+
- lib/compressors/gifCompressor.rb
|
104
|
+
- lib/compressors/jpegCompressor.rb
|
105
|
+
- lib/compressors/jsCompressor.rb
|
106
|
+
- lib/compressors/pngCompressor.rb
|
107
|
+
- lib/confManager.rb
|
108
|
+
- lib/domCompiler.rb
|
109
|
+
- lib/sqweezeUtils.rb
|
110
|
+
- spec/confManager_spec.rb
|
111
|
+
- spec/domCompiler_spec.rb
|
112
|
+
- spec/sqw_spec_helper.rb
|
113
|
+
- sqweeze.gemspec
|
114
|
+
has_rdoc: true
|
115
|
+
homepage: http://github.com/premasagar/sqwidget-builder
|
116
|
+
licenses: []
|
117
|
+
|
118
|
+
post_install_message:
|
119
|
+
rdoc_options:
|
120
|
+
- --line-numbers
|
121
|
+
- --inline-source
|
122
|
+
- --title
|
123
|
+
- Sqweeze
|
124
|
+
- --main
|
125
|
+
- README.rdoc
|
126
|
+
require_paths:
|
127
|
+
- lib
|
128
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
segments:
|
133
|
+
- 0
|
134
|
+
version: "0"
|
135
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
segments:
|
140
|
+
- 1
|
141
|
+
- 2
|
142
|
+
version: "1.2"
|
143
|
+
requirements: []
|
144
|
+
|
145
|
+
rubyforge_project: sqweeze
|
146
|
+
rubygems_version: 1.3.6
|
147
|
+
signing_key:
|
148
|
+
specification_version: 3
|
149
|
+
summary: A command line web-asset optimisation tool
|
150
|
+
test_files: []
|
151
|
+
|