front-end-blender 0.8.1 → 0.8.2
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/README +16 -21
- data/bin/blend +16 -186
- data/lib/front_end_architect/blender.rb +159 -0
- metadata +2 -1
data/README
CHANGED
@@ -6,8 +6,8 @@ CSS and/or JavaScript assets for a site into efficient, production-ready files.
|
|
6
6
|
== Blendfile
|
7
7
|
|
8
8
|
The Blendfile, named blender.yaml by default, is the configuration file that
|
9
|
-
tells Blender which
|
10
|
-
file uses the YAML format. The output file is listed as hash key and
|
9
|
+
tells Blender which source files are combined into which output files. The
|
10
|
+
file uses the YAML format. The output file is listed as hash key and source
|
11
11
|
files are the hash values as an array. Here is a sample Blendfile:
|
12
12
|
|
13
13
|
# blender.yaml for boldpx.com
|
@@ -26,6 +26,18 @@ _style/_global-min.css:
|
|
26
26
|
- _style/_global/layout-screen.css
|
27
27
|
- _style/_global/layout-print.css
|
28
28
|
|
29
|
+
== Usage
|
30
|
+
|
31
|
+
Usage: blend [options]
|
32
|
+
-h, --help Show this message
|
33
|
+
-V, --version Prints Blender's version number
|
34
|
+
-f, --file FILE Use given Blendfile
|
35
|
+
-t, --type TYPE Select file type to blend (css, js)
|
36
|
+
-d, --data Convert url(image.ext) to url(data:) in CSS files EXPERIMENTAL
|
37
|
+
--force Force blending when source files aren't newer than output files
|
38
|
+
--yui=YUIOPTS Pass arguments to YUI Compressor
|
39
|
+
-g, --generate Generate a stub Blendfile
|
40
|
+
|
29
41
|
== Examples
|
30
42
|
|
31
43
|
In your site directory run 'blend' to minify CSS and JavaScript.
|
@@ -37,27 +49,10 @@ Other examples:
|
|
37
49
|
blend -t css -d
|
38
50
|
blend --yui='--preserve-semi'
|
39
51
|
|
40
|
-
== Usage
|
41
|
-
|
42
|
-
blend [options] [-- yui-compressor-options]
|
43
|
-
|
44
|
-
For help use: blend -h
|
45
|
-
|
46
|
-
== Options
|
47
|
-
|
48
|
-
-h, --help Displays help message
|
49
|
-
-v, --version Display the version
|
50
|
-
-f <file>, --file <file> Use given Blendfile
|
51
|
-
-t <css|js>, --type <css|js> Select file type to blend (css, js)
|
52
|
-
-d, --data Convert url(image.ext) to url(data:) in CSS files EXPERIMENTAL
|
53
|
-
--force Force blending when source files aren't newer than output files
|
54
|
-
--yui= Pass arguments to YUI Compressor
|
55
|
-
-g, --generate Generate a stub Blendfile
|
56
|
-
|
57
52
|
== Installation
|
58
53
|
|
59
|
-
To install the
|
60
|
-
sudo gem install
|
54
|
+
To install the rubygem, run the following at the command line:
|
55
|
+
sudo gem install blender
|
61
56
|
|
62
57
|
Java, v1.4 or greater is required
|
63
58
|
|
data/bin/blend
CHANGED
@@ -6,194 +6,24 @@
|
|
6
6
|
# Blender is freely distributable under the terms of an MIT-style license.
|
7
7
|
# For details, see http://www.opensource.org/licenses/mit-license.php
|
8
8
|
|
9
|
-
|
9
|
+
$:.unshift File.join(File.dirname(File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__), *%w[.. lib])
|
10
10
|
require 'optparse'
|
11
|
-
require '
|
12
|
-
require 'ostruct'
|
13
|
-
require 'base64'
|
14
|
-
require 'benchmark'
|
15
|
-
require 'mime/types'
|
16
|
-
require 'find'
|
11
|
+
require 'front_end_architect/blender'
|
17
12
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
@options.force = false
|
32
|
-
@options.generate = false
|
33
|
-
end
|
34
|
-
|
35
|
-
def blend
|
36
|
-
if parsed_options?
|
37
|
-
if @options.generate
|
38
|
-
create_blendfile
|
39
|
-
end
|
40
|
-
|
41
|
-
elapsed = Benchmark.realtime do
|
42
|
-
unless File.exists? @options.blendfile
|
43
|
-
puts "Couldn't find '#{@options.blendfile}'"
|
44
|
-
exit 1
|
45
|
-
end
|
46
|
-
|
47
|
-
blender = YAML::load_file @options.blendfile
|
48
|
-
|
49
|
-
Dir.chdir(File.dirname(@options.blendfile))
|
50
|
-
|
51
|
-
blender.each do |output_name, inputs|
|
52
|
-
output_new = false
|
53
|
-
|
54
|
-
# Checks the type flag and if the current file meets the type requirements continues
|
55
|
-
if output_name.match "." + @options.file_type.to_s
|
56
|
-
file_type = output_name.match(/\.css/) ? "css" : "js"
|
57
|
-
|
58
|
-
# Checks if output file exists and checks the mtimes of the source files to the output file if new creates a new file
|
59
|
-
if File.exists? output_name
|
60
|
-
inputs.each do |i|
|
61
|
-
if File.mtime(i) > File.mtime(output_name)
|
62
|
-
output_new = true
|
63
|
-
break
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
if output_new || @options.force
|
68
|
-
create_output(output_name, inputs, file_type)
|
69
|
-
else
|
70
|
-
puts "Skipping: #{output_name}"
|
71
|
-
end
|
72
|
-
else
|
73
|
-
create_output(output_name, inputs, file_type)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
puts sprintf("%.5f", elapsed) + " seconds"
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
protected
|
84
|
-
|
85
|
-
def parsed_options?
|
86
|
-
opts = OptionParser.new
|
87
|
-
|
88
|
-
opts.on('-h', '--help') { output_help }
|
89
|
-
opts.on('-v', '--version') { output_version; exit 0 }
|
90
|
-
opts.on('-f FILE', '--file FILE', String, "Use given Blendfile") {|f| @options.blendfile = f }
|
91
|
-
opts.on('-t TYPE', '--type TYPE', [:css, :js], "Select file type to blend (css, js)") {|t| @options.file_type = t }
|
92
|
-
opts.on('-d', '--data', String, "Convert url(image.ext) to url(data:) in CSS files EXPERIMENTAL") { @options.data = true }
|
93
|
-
opts.on( '--force', String, "Force blending when source files aren't newer than output files") { @options.force = true }
|
94
|
-
opts.on( '--yui=YUIOPTS', String, "Pass arguments to YUI Compressor") {|o| @options.yuiopts = o }
|
95
|
-
opts.on('-g', '--generate', String, "Generate a stub Blendfile") { @options.generate = true }
|
96
|
-
|
97
|
-
opts.parse!(@arguments) rescue return false
|
98
|
-
|
99
|
-
true
|
100
|
-
end
|
101
|
-
|
102
|
-
def create_blendfile
|
103
|
-
if File.exists?(@options.blendfile) && !@options.force
|
104
|
-
puts "'#{@options.blendfile}' already exists"
|
105
|
-
exit 1
|
106
|
-
end
|
107
|
-
|
108
|
-
blend_files = Hash.new
|
109
|
-
|
110
|
-
Find.find(Dir.getwd) do |f|
|
111
|
-
f.gsub!(Dir.getwd.to_s+"/", "")
|
112
|
-
if File.extname(f) == ".css"
|
113
|
-
file = f.split(".css")
|
114
|
-
min_file = file[0] + "-min.css"
|
115
|
-
blend_files[f] = [min_file]
|
116
|
-
end
|
117
|
-
|
118
|
-
if File.extname(f) == ".js"
|
119
|
-
file = f.split(".js")
|
120
|
-
min_file = file[0] + "-min.js"
|
121
|
-
blend_files[f] = [min_file]
|
122
|
-
end
|
123
|
-
|
124
|
-
Find.prune if File.basename(f).index('.') == 0
|
125
|
-
end
|
126
|
-
|
127
|
-
File.open(@options.blendfile, 'w') { |f| YAML.dump(blend_files, f) }
|
128
|
-
|
129
|
-
exit 0
|
130
|
-
end
|
131
|
-
|
132
|
-
# TODO Change to work with directory hashes (css/: [ colors.css, layout.css ])
|
133
|
-
def create_output(output_name, inputs, type)
|
134
|
-
File.open(output_name, 'w') do |output_file|
|
135
|
-
output = ''
|
136
|
-
|
137
|
-
inputs.each do |i|
|
138
|
-
output << IO.read(i)
|
139
|
-
end
|
140
|
-
|
141
|
-
# Compress
|
142
|
-
real_file = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
|
143
|
-
|
144
|
-
IO.popen("java -jar #{File.dirname(real_file)}/../lib/yui/yuicompressor.jar #{@options.yuiopts} --type #{type}", mode="r+") do |io|
|
145
|
-
io.write output
|
146
|
-
io.close_write
|
147
|
-
|
148
|
-
output = io.read
|
149
|
-
|
150
|
-
if File.extname(output_name) == ".css"
|
151
|
-
output.gsub! ' and(', ' and (' # Workaround for YUI Compressor Bug #1938329
|
152
|
-
output.gsub! '/**/;}', '/**/}' # Workaround for YUI Compressor Bug #1961175
|
153
|
-
|
154
|
-
if @options.data
|
155
|
-
output = output.gsub(/url\(['"]?([^?']+)['"]+\)/im) do
|
156
|
-
uri = $1
|
157
|
-
mime_type = ''
|
158
|
-
|
159
|
-
# Make the URI absolute instead of relative. TODO Seems kinda hacky is there a better way?
|
160
|
-
uri.gsub! "../", ""
|
161
|
-
|
162
|
-
# Figure out the mime type.
|
163
|
-
mime_type = MIME::Types.type_for(uri)
|
164
|
-
|
165
|
-
url_contents = make_data_uri(IO.read(uri), mime_type[0])
|
166
|
-
|
167
|
-
%Q!url("#{url_contents}")!
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
output_file << output
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
puts output_name
|
177
|
-
end
|
178
|
-
|
179
|
-
def make_data_uri(content, content_type)
|
180
|
-
outuri = 'data:' + content_type + ';base64'
|
181
|
-
content = Base64.encode64(content)
|
182
|
-
outuri += ",#{content}"
|
183
|
-
|
184
|
-
outuri.gsub("\n", '')
|
185
|
-
end
|
186
|
-
|
187
|
-
def output_version
|
188
|
-
puts "Blender v#{VERSION}"
|
189
|
-
end
|
190
|
-
|
191
|
-
def output_help
|
192
|
-
output_version
|
193
|
-
RDoc::usage() #exits app
|
194
|
-
end
|
13
|
+
options = {}
|
14
|
+
|
15
|
+
opts = OptionParser.new do |opts|
|
16
|
+
opts.on('-h', '--help', "Show this message") { puts opts; exit 0 }
|
17
|
+
opts.on('-V', '--version', "Show the version number") { puts "Front-End Blender v#{Blender::VERSION}"; exit 0 }
|
18
|
+
opts.on('-f FILE', '--file FILE', String, "Use given Blendfile") {|f| options[:blendfile] = f }
|
19
|
+
opts.on('-t TYPE', '--type TYPE', [:css, :js], "Select file type to blend (css, js)") {|t| options[:file_type] = t }
|
20
|
+
opts.on('-d', '--data', String, "Convert url(image.ext) to url(data:) in CSS files EXPERIMENTAL") { options[:data] = true }
|
21
|
+
opts.on( '--force', String, "Force blending when source files aren't newer than output files") { options[:force] = true }
|
22
|
+
opts.on( '--yui=YUIOPTS', String, "Pass arguments to YUI Compressor") {|o| options[:yuiopts] = o }
|
23
|
+
opts.on('-g', '--generate', String, "Generate a stub Blendfile") { options[:generate] = true }
|
24
|
+
|
25
|
+
opts.parse!(ARGV) rescue return false
|
195
26
|
end
|
196
27
|
|
197
|
-
|
198
|
-
blender = Blender.new(ARGV, STDIN)
|
28
|
+
blender = Blender.new(options)
|
199
29
|
blender.blend
|
@@ -0,0 +1,159 @@
|
|
1
|
+
# Copyright (c) 2008 Chris Griego
|
2
|
+
# (c) 2008 Blake Elshire
|
3
|
+
#
|
4
|
+
# Blender is freely distributable under the terms of an MIT-style license.
|
5
|
+
# For details, see http://www.opensource.org/licenses/mit-license.php
|
6
|
+
|
7
|
+
require 'rubygems'
|
8
|
+
require 'yaml'
|
9
|
+
require 'base64'
|
10
|
+
require 'benchmark'
|
11
|
+
require 'mime/types'
|
12
|
+
require 'find'
|
13
|
+
|
14
|
+
class Blender
|
15
|
+
VERSION = '0.8.2'
|
16
|
+
|
17
|
+
DEFAULT_OPTIONS = {
|
18
|
+
:blendfile => 'blender.yaml',
|
19
|
+
:data => false,
|
20
|
+
:force => false,
|
21
|
+
}
|
22
|
+
|
23
|
+
attr_reader :options
|
24
|
+
|
25
|
+
def initialize(opts)
|
26
|
+
@options = DEFAULT_OPTIONS.merge(opts)
|
27
|
+
end
|
28
|
+
|
29
|
+
def blend
|
30
|
+
if @options[:generate]
|
31
|
+
create_blendfile
|
32
|
+
end
|
33
|
+
|
34
|
+
elapsed = Benchmark.realtime do
|
35
|
+
unless File.exists? @options[:blendfile]
|
36
|
+
puts "Couldn't find '#{@options[:blendfile]}'"
|
37
|
+
exit 1
|
38
|
+
end
|
39
|
+
|
40
|
+
blender = YAML::load_file @options[:blendfile]
|
41
|
+
|
42
|
+
Dir.chdir(File.dirname(@options[:blendfile]))
|
43
|
+
|
44
|
+
blender.each do |output_name, sources|
|
45
|
+
output_new = false
|
46
|
+
|
47
|
+
# Checks the type flag and if the current file meets the type requirements continues
|
48
|
+
if output_name.match "." + @options[:file_type].to_s
|
49
|
+
file_type = output_name.match(/\.css/) ? "css" : "js"
|
50
|
+
|
51
|
+
# Checks if output file exists and checks the mtimes of the source files to the output file if new creates a new file
|
52
|
+
if File.exists? output_name
|
53
|
+
sources.each do |i|
|
54
|
+
if File.mtime(i) > File.mtime(output_name)
|
55
|
+
output_new = true
|
56
|
+
break
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
if output_new || @options[:force]
|
61
|
+
create_output(output_name, sources, file_type)
|
62
|
+
else
|
63
|
+
puts "Skipping: #{output_name}"
|
64
|
+
end
|
65
|
+
else
|
66
|
+
create_output(output_name, sources, file_type)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
puts sprintf("%.5f", elapsed) + " seconds"
|
73
|
+
end
|
74
|
+
|
75
|
+
protected
|
76
|
+
|
77
|
+
def create_blendfile
|
78
|
+
if File.exists?(@options[:blendfile]) && !@options[:force]
|
79
|
+
puts "'#{@options[:blendfile]}' already exists"
|
80
|
+
exit 1
|
81
|
+
end
|
82
|
+
|
83
|
+
blend_files = Hash.new
|
84
|
+
|
85
|
+
Find.find(Dir.getwd) do |f|
|
86
|
+
f.gsub!(Dir.getwd.to_s+"/", "")
|
87
|
+
if File.extname(f) == ".css"
|
88
|
+
file = f.split(".css")
|
89
|
+
min_file = file[0] + "-min.css"
|
90
|
+
blend_files[f] = [min_file]
|
91
|
+
end
|
92
|
+
|
93
|
+
if File.extname(f) == ".js"
|
94
|
+
file = f.split(".js")
|
95
|
+
min_file = file[0] + "-min.js"
|
96
|
+
blend_files[f] = [min_file]
|
97
|
+
end
|
98
|
+
|
99
|
+
Find.prune if File.basename(f).index('.') == 0
|
100
|
+
end
|
101
|
+
|
102
|
+
File.open(@options[:blendfile], 'w') { |f| YAML.dump(blend_files, f) }
|
103
|
+
|
104
|
+
exit 0
|
105
|
+
end
|
106
|
+
|
107
|
+
# TODO Change to work with directory hashes (css/: [ colors.css, layout.css ])
|
108
|
+
def create_output(output_name, sources, type)
|
109
|
+
File.open(output_name, 'w') do |output_file|
|
110
|
+
output = ''
|
111
|
+
|
112
|
+
sources.each do |i|
|
113
|
+
output << IO.read(i)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Compress
|
117
|
+
libdir = File.join(File.dirname(File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__), *%w[.. .. lib])
|
118
|
+
|
119
|
+
IO.popen("java -jar #{libdir}/yui/yuicompressor.jar #{@options[:yuiopts]} --type #{type}", mode="r+") do |io|
|
120
|
+
io.write output
|
121
|
+
io.close_write
|
122
|
+
|
123
|
+
output = io.read
|
124
|
+
|
125
|
+
if File.extname(output_name) == ".css"
|
126
|
+
output.gsub! ' and(', ' and (' # Workaround for YUI Compressor Bug #1938329
|
127
|
+
output.gsub! '/**/;}', '/**/}' # Workaround for YUI Compressor Bug #1961175
|
128
|
+
|
129
|
+
if @options[:data]
|
130
|
+
output = output.gsub(/url\(['"]?([^?']+)['"]+\)/im) do
|
131
|
+
uri = $1
|
132
|
+
mime_type = ''
|
133
|
+
|
134
|
+
# Make the URI absolute instead of relative. TODO Seems kinda hacky is there a better way?
|
135
|
+
uri.gsub! "../", ""
|
136
|
+
|
137
|
+
# Figure out the mime type.
|
138
|
+
mime_type = MIME::Types.type_for(uri)
|
139
|
+
|
140
|
+
url_contents = make_data_uri(IO.read(uri), mime_type[0])
|
141
|
+
|
142
|
+
%Q!url("#{url_contents}")!
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
output_file << output
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
puts output_name
|
152
|
+
end
|
153
|
+
|
154
|
+
def make_data_uri(content, content_type)
|
155
|
+
content = Base64.encode64(content)
|
156
|
+
uri = "data:#{content_type};base64,#{content}"
|
157
|
+
uri.gsub("\n", '')
|
158
|
+
end
|
159
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: front-end-blender
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Blake Elshire & Chris Griego
|
@@ -33,6 +33,7 @@ files:
|
|
33
33
|
- README
|
34
34
|
- MIT-LICENSE
|
35
35
|
- bin/blend
|
36
|
+
- lib/front_end_architect/blender.rb
|
36
37
|
- lib/yui/yuicompressor.jar
|
37
38
|
- lib/yui/LICENSE
|
38
39
|
has_rdoc: false
|