assetbuild 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Manifest +28 -0
- data/README +55 -0
- data/Rakefile +21 -0
- data/VERSION +1 -0
- data/bin/assetbuild +37 -0
- data/bin/buildcoffee +53 -0
- data/bin/buildcss +54 -0
- data/demo/assetbuild.yml +15 -0
- data/demo/assets.css +1 -0
- data/demo/coffee_bundle/demo.coffee +29 -0
- data/demo/coffee_bundle/demo2.coffee +25 -0
- data/demo/main.js +1 -0
- data/demo/secondary.css +5 -0
- data/demo/stand_alone.coffee +13 -0
- data/demo/stand_alone.js +1 -0
- data/demo/styles/reset.css +11 -0
- data/demo/styles/special/basic_stuff.css +14 -0
- data/demo/styles/special/more_stuff.css +5 -0
- data/demo/styles/typography.css +10 -0
- data/demo/test.css +31 -0
- data/lib/asset_build.rb +26 -0
- data/lib/asset_build/coffee_bundler.rb +58 -0
- data/lib/asset_build/css_reader.rb +60 -0
- data/spec/asset_build_spec.rb +18 -0
- data/spec/coffee_bundler_spec.rb +37 -0
- data/spec/css_reader_spec.rb +140 -0
- metadata +92 -0
data/.gitignore
ADDED
data/Manifest
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
Manifest
|
2
|
+
README
|
3
|
+
Rakefile
|
4
|
+
assetbuild.gemspec
|
5
|
+
bin/assetbuild
|
6
|
+
bin/buildcoffee
|
7
|
+
bin/buildcss
|
8
|
+
demo/assetbuild.yml
|
9
|
+
demo/assets.css
|
10
|
+
demo/coffee_bundle/demo.coffee
|
11
|
+
demo/coffee_bundle/demo2.coffee
|
12
|
+
demo/main.js
|
13
|
+
demo/secondary.css
|
14
|
+
demo/stand_alone.coffee
|
15
|
+
demo/stand_alone.js
|
16
|
+
demo/styles/reset.css
|
17
|
+
demo/styles/special/basic_stuff.css
|
18
|
+
demo/styles/special/more_stuff.css
|
19
|
+
demo/styles/typography.css
|
20
|
+
demo/test.build.css
|
21
|
+
demo/test.build.min.css
|
22
|
+
demo/test.css
|
23
|
+
lib/asset_build.rb
|
24
|
+
lib/asset_build/coffee_bundler.rb
|
25
|
+
lib/asset_build/css_reader.rb
|
26
|
+
spec/asset_build_spec.rb
|
27
|
+
spec/coffee_bundler_spec.rb
|
28
|
+
spec/css_reader_spec.rb
|
data/README
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
Builds, bundles, and minifies CSS and CoffeeScript files.
|
2
|
+
|
3
|
+
== Building CSS
|
4
|
+
|
5
|
+
> require 'css-reader'
|
6
|
+
> css = CSSReader.new("test.css","secondary.css")
|
7
|
+
> css.save("production.css", :compress => true)
|
8
|
+
|
9
|
+
The above commands will generate new file that merges the files passed to the class in order. Also, and "@import" statement is processed inline and is also inserted in the order it is encountered recursively throughout the CSS. In this example the file has also been yui-compressed.
|
10
|
+
|
11
|
+
Alternatively, you can pass in additional css files at later point with the append method:
|
12
|
+
|
13
|
+
> css = CSSReader.new("test.css")
|
14
|
+
> # do stuff...
|
15
|
+
> css.append("secondary.css")
|
16
|
+
|
17
|
+
You could also run this from the command line:
|
18
|
+
|
19
|
+
> buildcss public/stylesheets/main.css -c
|
20
|
+
|
21
|
+
Which will recursively process all imported files and then write a single minified CSS file to:
|
22
|
+
public/stylesheets/main.build.min.css
|
23
|
+
|
24
|
+
== Building CoffeeScript
|
25
|
+
|
26
|
+
> require 'coffee-bundler'
|
27
|
+
> js = CoffeeBundler.new("path/to/coffee/bundle")
|
28
|
+
> js.save("public/javascripts/bundle.min.js", :compress => true)
|
29
|
+
|
30
|
+
This will effectively bundle files that match:
|
31
|
+
path/to/coffee/bundle/*.coffee
|
32
|
+
|
33
|
+
...into a single minified JS file located at:
|
34
|
+
public/javascripts/bundle.min.js
|
35
|
+
|
36
|
+
No, this will not work unless you have coffee-script installed on your system!
|
37
|
+
|
38
|
+
== Dependencies
|
39
|
+
|
40
|
+
Requires the yui-compressor gem:
|
41
|
+
|
42
|
+
> gem install -r yui-compressor
|
43
|
+
|
44
|
+
More info:
|
45
|
+
http://github.com/sstephenson/ruby-yui-compressor
|
46
|
+
|
47
|
+
== Specs
|
48
|
+
|
49
|
+
A simple but comprehensive rSpec suite is provided for quality assurance purposes.
|
50
|
+
|
51
|
+
> spec css_reader_spec.rb
|
52
|
+
|
53
|
+
== Disclaimer
|
54
|
+
|
55
|
+
This is really crude but useful. You could easily crash it if you placed an @import statement in a fashion to create an infinite loop. Don't do that! :)
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
# Rakefile
|
5
|
+
begin
|
6
|
+
require 'jeweler'
|
7
|
+
Jeweler::Tasks.new do |gemspec|
|
8
|
+
gemspec.name = "assetbuild"
|
9
|
+
gemspec.summary = "Easily merge and compress multiple asset files together (currently supports CSS and coffee-script)."
|
10
|
+
gemspec.homepage = "http://github.com/jimjeffers/assetbuild"
|
11
|
+
gemspec.authors = ["Jim Jeffers"]
|
12
|
+
gemspec.description = "Easily merge and compress multiple asset files together (currently supports CSS and coffee-script)."
|
13
|
+
gemspec.email = "shout@jimjeffers.com"
|
14
|
+
gemspec.executables = ["assetbuild", "buildcoffee", "buildcss"]
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler not available. Install it with: sudo gem install jeweler -s http://gemcutter.org"
|
19
|
+
end
|
20
|
+
|
21
|
+
Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/bin/assetbuild
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'rubygems' unless ENV['NO_RUBYGEMS']
|
5
|
+
require File.expand_path(File.join(File.dirname(__FILE__),'..','lib','asset_build'))
|
6
|
+
|
7
|
+
# Argument defaults
|
8
|
+
options = {
|
9
|
+
:individual => false,
|
10
|
+
:compress => false
|
11
|
+
}
|
12
|
+
|
13
|
+
# Get arguments
|
14
|
+
opts = OptionParser.new do |o|
|
15
|
+
o.banner = "usage: assetbuild path_to_yml"
|
16
|
+
o.separator ""
|
17
|
+
|
18
|
+
# Version
|
19
|
+
o.on_tail("-v", "--version", "show version") do
|
20
|
+
#puts "assetbuild " + AssetBuild.version
|
21
|
+
exit
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.parse! # Parse arguments into `options` hash
|
26
|
+
|
27
|
+
# Get source from command line
|
28
|
+
files = []
|
29
|
+
ARGV.each do |arg|
|
30
|
+
if arg[0] == "-"
|
31
|
+
break
|
32
|
+
else
|
33
|
+
# TODO: Find a cleaner way to do this. I know there has to be one.
|
34
|
+
builder = AssetBuild.new(File.expand_path(File.join(ENV["PWD"],arg)))
|
35
|
+
builder.process_files!
|
36
|
+
end
|
37
|
+
end
|
data/bin/buildcoffee
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'rubygems' unless ENV['NO_RUBYGEMS']
|
5
|
+
require File.expand_path(File.join(File.dirname(__FILE__),'..','lib','asset_build'))
|
6
|
+
|
7
|
+
# Argument defaults
|
8
|
+
options = {
|
9
|
+
:individual => false,
|
10
|
+
:compress => false
|
11
|
+
}
|
12
|
+
|
13
|
+
# Get arguments
|
14
|
+
opts = OptionParser.new do |o|
|
15
|
+
o.banner = "usage: buildcoffee source [destination] [--compress]"
|
16
|
+
o.separator ""
|
17
|
+
|
18
|
+
# Use YUI compression?
|
19
|
+
o.on("-c", "--compress", "compress javascript with yui-compressor") do
|
20
|
+
options[:compress] = true
|
21
|
+
end
|
22
|
+
|
23
|
+
# Version
|
24
|
+
o.on_tail("-v", "--version", "show version") do
|
25
|
+
#puts "coffeebundler " + CoffeeBundler.version
|
26
|
+
exit
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.parse! # Parse arguments into `options` hash
|
31
|
+
|
32
|
+
# Get source from command line
|
33
|
+
files = []
|
34
|
+
ARGV.each do |arg|
|
35
|
+
if arg[0] == "-"
|
36
|
+
break
|
37
|
+
else
|
38
|
+
tags = (options[:compress]) ? 'build.min' : 'build'
|
39
|
+
if File.directory?(arg)
|
40
|
+
destination = [arg]+tags+["js"].join(".")
|
41
|
+
else
|
42
|
+
filename = File.basename(arg)
|
43
|
+
destination = filename.split(".").insert(-2,tags).join('.')
|
44
|
+
end
|
45
|
+
# TODO: Find a cleaner way to do this. I know there has to be one.
|
46
|
+
files << [ File.expand_path(File.join(ENV["PWD"],arg)),
|
47
|
+
File.expand_path(File.join(ENV["PWD"],File.dirname(arg),destination))]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
unless options[:individual] || files.length < 1
|
52
|
+
CoffeeBundler.new(files.map { |m| m[0] }).save(files.first[1],:compress => options[:compress])
|
53
|
+
end
|
data/bin/buildcss
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'rubygems' unless ENV['NO_RUBYGEMS']
|
5
|
+
require File.expand_path(File.join(File.dirname(__FILE__),'..','lib','asset_build'))
|
6
|
+
|
7
|
+
# Argument defaults
|
8
|
+
options = {
|
9
|
+
:individual => false,
|
10
|
+
:compress => false
|
11
|
+
}
|
12
|
+
|
13
|
+
# Get arguments
|
14
|
+
opts = OptionParser.new do |o|
|
15
|
+
o.banner = "usage: buildcss source [destination] [--compress]"
|
16
|
+
o.separator ""
|
17
|
+
|
18
|
+
# Use YUI compression?
|
19
|
+
o.on("-c", "--compress", "compress css with yui-compressor") do
|
20
|
+
options[:compress] = true
|
21
|
+
end
|
22
|
+
|
23
|
+
# Process files individually?
|
24
|
+
o.on("--individual", "process each file individually rather than merge together") do
|
25
|
+
options[:individual] = true
|
26
|
+
end
|
27
|
+
|
28
|
+
# Version
|
29
|
+
o.on_tail("-v", "--version", "show version") do
|
30
|
+
#puts "cssbuild " + CSSReader.version
|
31
|
+
exit
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
opts.parse! # Parse arguments into `options` hash
|
36
|
+
|
37
|
+
# Get source from command line
|
38
|
+
files = []
|
39
|
+
ARGV.each do |arg|
|
40
|
+
if arg[0] == "-"
|
41
|
+
break
|
42
|
+
else
|
43
|
+
filename = File.basename(arg)
|
44
|
+
tags = (options[:compress]) ? 'build.min' : 'build'
|
45
|
+
destination = filename.split(".").insert(-2,tags).join('.')
|
46
|
+
# TODO: Find a cleaner way to do this. I know there has to be one.
|
47
|
+
files << [ File.expand_path(File.join(ENV["PWD"],arg)),
|
48
|
+
File.expand_path(File.join(ENV["PWD"],File.dirname(arg),destination))]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
unless options[:individual] || files.length < 1
|
53
|
+
CSSReader.new(files.map { |m| m[0] }).save(files.first[1],:compress => options[:compress])
|
54
|
+
end
|
data/demo/assetbuild.yml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
main.js:
|
2
|
+
type: coffeescript
|
3
|
+
source: coffee_bundle
|
4
|
+
compress: true
|
5
|
+
|
6
|
+
stand_alone.js:
|
7
|
+
type: coffeescript
|
8
|
+
source: stand_alone.coffee
|
9
|
+
desintation: coffee_bundle/
|
10
|
+
compress: true
|
11
|
+
|
12
|
+
assets.css:
|
13
|
+
type: stylesheet
|
14
|
+
source: test.css
|
15
|
+
compress: true
|
data/demo/assets.css
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*{border:0;margin:0;padding:0;}body{font:75% "Lucida Grande","Trebuchet MS",Verdana,sans-serif;}#basic{box-shadow:3px 2px blur color/#000/rgba(0,0,0,.5);-o-box-shadow:3px 2px blur color/#000/rgba(0,0,0,.5);-icab-box-shadow:3px 2px blur color/#000/rgba(0,0,0,.5);-khtml-box-shadow:3px 2px blur color/#000/rgba(0,0,0,.5);-moz-box-shadow:3px 2px blur color/#000/rgba(0,0,0,.5);-webkit-box-shadow:3px 2px blur color/#000/rgba(0,0,0,.5);}#more{border:1px solid #999;}#primary_content{left:50%;position:absolute;top:50%;width:100px;}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Assignment:
|
2
|
+
number: 42
|
3
|
+
opposite_day: true
|
4
|
+
|
5
|
+
# Conditions:
|
6
|
+
number: -42 if opposite_day
|
7
|
+
|
8
|
+
# Functions:
|
9
|
+
square: (x) -> x * x
|
10
|
+
|
11
|
+
# Arrays:
|
12
|
+
list: [1, 2, 3, 4, 5]
|
13
|
+
|
14
|
+
# Objects:
|
15
|
+
math: {
|
16
|
+
root: Math.sqrt
|
17
|
+
square: square
|
18
|
+
cube: (x) -> x * square x
|
19
|
+
}
|
20
|
+
|
21
|
+
# Splats:
|
22
|
+
race: (winner, runners...) ->
|
23
|
+
print winner, runners
|
24
|
+
|
25
|
+
# Existence:
|
26
|
+
alert "I knew it!" if elvis?
|
27
|
+
|
28
|
+
# Array comprehensions:
|
29
|
+
cubed_list: math.cube num for num in list
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Animal
|
2
|
+
move: (meters) ->
|
3
|
+
alert @name + " moved " + meters + "m."
|
4
|
+
|
5
|
+
class Snake extends Animal
|
6
|
+
constructor: (name) ->
|
7
|
+
@name: name
|
8
|
+
|
9
|
+
move: ->
|
10
|
+
alert "Slithering..."
|
11
|
+
super 5
|
12
|
+
|
13
|
+
class Horse extends Animal
|
14
|
+
constructor: (name) ->
|
15
|
+
@name: name
|
16
|
+
|
17
|
+
move: ->
|
18
|
+
alert "Galloping..."
|
19
|
+
super 45
|
20
|
+
|
21
|
+
sam: new Snake "Sammy the Python"
|
22
|
+
tom: new Horse "Tommy the Palomino"
|
23
|
+
|
24
|
+
sam.move()
|
25
|
+
tom.move()
|
data/demo/main.js
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
(function(){var _a,_b,_c,_d,cubed_list,list,math,num,number,opposite_day,race,square;number=42;opposite_day=true;if(opposite_day){number=-42}square=function square(x){return x*x};list=[1,2,3,4,5];math={root:Math.sqrt,square:square,cube:function cube(x){return x*square(x)}};race=function race(winner){var runners;runners=Array.prototype.slice.call(arguments,1);return print(winner,runners)};if((typeof elvis!=="undefined"&&elvis!==null)){alert("I knew it!")}cubed_list=(function(){_a=[];_b=list;for(_c=0,_d=_b.length;_c<_d;_c++){num=_b[_c];_a.push(math.cube(num))}return _a}).call(this)})();(function(){var Animal,Horse,Snake,sam,tom;var __extends=function(child,parent){var ctor=function(){};ctor.prototype=parent.prototype;child.__superClass__=parent.prototype;child.prototype=new ctor();child.prototype.constructor=child};Animal=function Animal(){};Animal.prototype.move=function move(meters){return alert(this.name+" moved "+meters+"m.")};Snake=function Snake(name){this.name=name;return this};__extends(Snake,Animal);Snake.prototype.move=function move(){alert("Slithering...");return Snake.__superClass__.move.call(this,5)};Horse=function Horse(name){this.name=name;return this};__extends(Horse,Animal);Horse.prototype.move=function move(){alert("Galloping...");return Horse.__superClass__.move.call(this,45)};sam=new Snake("Sammy the Python");tom=new Horse("Tommy the Palomino");sam.move();tom.move()})();
|
data/demo/secondary.css
ADDED
data/demo/stand_alone.js
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
(function(){var _a,_b,_c,city,futurists,poet,street;futurists={sculptor:"Umberto Boccioni",painter:"Vladimir Burliuk",poet:{name:"F.T. Marinetti",address:["Via Roma 42R","Bellagio, Italy 22021"]}};_a=futurists;_b=_a.poet;poet=_b.name;_c=_b.address;street=_c[0];city=_c[1]})();
|
@@ -0,0 +1,14 @@
|
|
1
|
+
/* Basic Stuff
|
2
|
+
Updated: Thu 10.18.07 @ 5:15 p.m.
|
3
|
+
Author: OK ok..
|
4
|
+
----------------------------------------------------*/
|
5
|
+
#basic {
|
6
|
+
box-shadow: 3px 2px blur color/#000/rgba(0,0,0,.5);
|
7
|
+
-o-box-shadow: 3px 2px blur color/#000/rgba(0,0,0,.5);
|
8
|
+
-icab-box-shadow: 3px 2px blur color/#000/rgba(0,0,0,.5);
|
9
|
+
-khtml-box-shadow: 3px 2px blur color/#000/rgba(0,0,0,.5);
|
10
|
+
-moz-box-shadow: 3px 2px blur color/#000/rgba(0,0,0,.5);
|
11
|
+
-webkit-box-shadow: 3px 2px blur color/#000/rgba(0,0,0,.5);
|
12
|
+
}
|
13
|
+
|
14
|
+
@import "more_stuff.css";
|
data/demo/test.css
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
/* KEEP OUR CSS CLEAN
|
2
|
+
Some guidelines to follow:
|
3
|
+
1. Break code down into sections.
|
4
|
+
2. Keep your rules alphabetically sorted.
|
5
|
+
3. Only put one selector per line for a block of rules that apply to multiple selectors.
|
6
|
+
4. Indent your rules, only one rule per line.
|
7
|
+
5. Indent proprietary properties with two spaces. Keep these properties directly below the proposed property.
|
8
|
+
|
9
|
+
example:
|
10
|
+
|
11
|
+
element#id,
|
12
|
+
element.class {
|
13
|
+
rule1: value;
|
14
|
+
-webkit-rule2: value;
|
15
|
+
-moz-rule2: value;
|
16
|
+
rule2: value;
|
17
|
+
top: value;
|
18
|
+
}
|
19
|
+
*/
|
20
|
+
/* =IMPORT DEPENDENCIES
|
21
|
+
------------------------------------------------------ */
|
22
|
+
@import "styles/reset.css";
|
23
|
+
|
24
|
+
/* =PRIMARY_CONTENT
|
25
|
+
------------------------------------------------------ */
|
26
|
+
#primary_content {
|
27
|
+
left: 50%;
|
28
|
+
position: absolute;
|
29
|
+
top: 50%;
|
30
|
+
width: 100px;
|
31
|
+
}
|
data/lib/asset_build.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'asset_build/coffee_bundler'
|
2
|
+
require 'asset_build/css_reader'
|
3
|
+
|
4
|
+
class AssetBuild
|
5
|
+
attr_accessor :manifest
|
6
|
+
|
7
|
+
def initialize(path)
|
8
|
+
@manifest = YAML::load(File.open(path).readlines.join(""))
|
9
|
+
@path = File.dirname(path)
|
10
|
+
end
|
11
|
+
|
12
|
+
def process_files!
|
13
|
+
@manifest.each do |destination,options|
|
14
|
+
compressed = options["compress"] || false
|
15
|
+
if options["type"] == "coffeescript"
|
16
|
+
coffee_bundler = CoffeeBundler.new(File.join(@path,options["source"]))
|
17
|
+
coffee_bundler.save(File.join(@path,destination),:compress => compressed)
|
18
|
+
puts File.join(@path,destination)
|
19
|
+
elsif options["type"] == "stylesheet"
|
20
|
+
css_reader = CSSReader.new(File.join(@path,options["source"]))
|
21
|
+
css_reader.save(File.join(@path,destination),:compress => compressed)
|
22
|
+
puts File.join(@path,destination)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "yui/compressor"
|
3
|
+
|
4
|
+
class CoffeeBundler
|
5
|
+
def initialize(*args)
|
6
|
+
@@yui = YUI::JavaScriptCompressor.new
|
7
|
+
@files = {}
|
8
|
+
@processed_js = []
|
9
|
+
append(*args)
|
10
|
+
end
|
11
|
+
|
12
|
+
def append(*args)
|
13
|
+
unless args.nil? || args.length < 1
|
14
|
+
if args.length == 1
|
15
|
+
args = args[0] if args.class == Array
|
16
|
+
args = [args] if args.class == String
|
17
|
+
end
|
18
|
+
for path in args
|
19
|
+
if File.directory?(path)
|
20
|
+
for inner_path in Dir.glob(File.join(path,'*.coffee')).to_a
|
21
|
+
process_path(inner_path)
|
22
|
+
end
|
23
|
+
else
|
24
|
+
process_path(path)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_javascript
|
31
|
+
@files.sort{|a,b| a[1][:position]<=>b[1][:position]}.map{ |path,values| values[:contents] }.join("")
|
32
|
+
end
|
33
|
+
|
34
|
+
def compressed
|
35
|
+
@@yui.compress(to_javascript)
|
36
|
+
end
|
37
|
+
|
38
|
+
def save(name,options={})
|
39
|
+
compress = options[:compress] || false
|
40
|
+
File.open(name,'w') {|f| f.write compress ? compressed : to_javascript }
|
41
|
+
end
|
42
|
+
|
43
|
+
protected
|
44
|
+
def compile(path)
|
45
|
+
%x(coffee -p #{path})
|
46
|
+
end
|
47
|
+
|
48
|
+
def process_path(path)
|
49
|
+
unless @files.keys.include?(path)
|
50
|
+
@files[path] = {
|
51
|
+
:name => File.basename(path),
|
52
|
+
:directory => File.dirname(path),
|
53
|
+
:contents => compile(path),
|
54
|
+
:position => @files.length
|
55
|
+
}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "yui/compressor"
|
3
|
+
|
4
|
+
class CSSReader
|
5
|
+
def initialize(*args)
|
6
|
+
@@yui = YUI::CssCompressor.new
|
7
|
+
@files = {}
|
8
|
+
@processed_css = []
|
9
|
+
append(*args)
|
10
|
+
end
|
11
|
+
|
12
|
+
def append(*args)
|
13
|
+
unless args.nil? || args.length < 1
|
14
|
+
if args.length == 1
|
15
|
+
args = args[0] if args.class == Array
|
16
|
+
args = [args] if args.class == String
|
17
|
+
end
|
18
|
+
for path in args
|
19
|
+
file = File.open(path)
|
20
|
+
unless @files.keys.include?(path)
|
21
|
+
process_imports( @files[path] = {
|
22
|
+
:name => File.basename(path),
|
23
|
+
:directory => File.dirname(path),
|
24
|
+
:contents => file.readlines,
|
25
|
+
:position => @files.length } )
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def stylesheets
|
32
|
+
@files.map { |path,values| values[:name] }
|
33
|
+
end
|
34
|
+
|
35
|
+
def normal
|
36
|
+
@processed_css.join("")
|
37
|
+
end
|
38
|
+
|
39
|
+
def compressed
|
40
|
+
@@yui.compress(normal)
|
41
|
+
end
|
42
|
+
|
43
|
+
def save(name,options={})
|
44
|
+
compress = options[:compress] || false
|
45
|
+
File.open(name,'w') {|f| f.write compress ? compressed : normal }
|
46
|
+
end
|
47
|
+
|
48
|
+
protected
|
49
|
+
def process_imports(file)
|
50
|
+
file[:contents].each do |line|
|
51
|
+
if line =~ /@import.*;/
|
52
|
+
file_name = eval(line.match(/".*?"/)[0])
|
53
|
+
file_path = [file[:directory],file_name].join("/")
|
54
|
+
append(file_path)
|
55
|
+
else
|
56
|
+
@processed_css << line
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__),'..','lib','asset_build'))
|
2
|
+
|
3
|
+
describe AssetBuild do
|
4
|
+
it "should be defined" do
|
5
|
+
defined?(AssetBuild).nil?.should be(false)
|
6
|
+
end
|
7
|
+
|
8
|
+
before(:all) do
|
9
|
+
@manifest_path = File.expand_path(File.join(File.dirname(__FILE__),'..','demo','assetbuild.yml'))
|
10
|
+
@asset_build = AssetBuild.new(@manifest_path)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "initialize" do
|
14
|
+
it "should know where to put destination files" do
|
15
|
+
@asset_build.process_files!
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__),'..','lib','asset_build'))
|
2
|
+
|
3
|
+
describe CoffeeBundler do
|
4
|
+
it "should be defined" do
|
5
|
+
defined?(CoffeeBundler).nil?.should be(false)
|
6
|
+
end
|
7
|
+
|
8
|
+
before(:all) do
|
9
|
+
@bundle_path = File.expand_path(File.join(File.dirname(__FILE__),'..','demo','coffee_bundle'))
|
10
|
+
@coffee_bundler = CoffeeBundler.new(@bundle_path)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "to_javascript" do
|
14
|
+
it "should compile to javascript" do
|
15
|
+
(@coffee_bundler.to_javascript.index("function()") > 0).should be(true)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should have 'cubed_list' before 'Animal'" do
|
19
|
+
(@coffee_bundler.to_javascript.index("cubed_list") < @coffee_bundler.to_javascript.index("Animal")).should be(true)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should retain comments as javascript" do
|
23
|
+
(@coffee_bundler.to_javascript.index("//") > 0).should be(true)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should be able to process a stand alone file" do
|
27
|
+
@coffee_bundler = CoffeeBundler.new(File.expand_path(File.join(File.dirname(__FILE__),'..','demo','stand_alone.coffee')))
|
28
|
+
(@coffee_bundler.to_javascript.index("var _a, _b, _c, city, futurists, poet, street;") > 0).should be(true)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "compressed" do
|
33
|
+
it "should not retain comments when compressed" do
|
34
|
+
(@coffee_bundler.compressed.index("//").nil?).should be(true)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__),'..','lib','asset_build'))
|
2
|
+
|
3
|
+
describe CSSReader do
|
4
|
+
it "should be defined" do
|
5
|
+
defined?(CSSReader).nil?.should be(false)
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "stylesheets" do
|
9
|
+
before(:all) do
|
10
|
+
@test_path = File.expand_path(File.join(File.dirname(__FILE__),'..','demo','test.css'))
|
11
|
+
@secondary_path = File.expand_path(File.join(File.dirname(__FILE__),'..','demo','secondary.css'))
|
12
|
+
@css_reader = CSSReader.new(@test_path)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should include test.css" do
|
16
|
+
@css_reader.stylesheets.include?("test.css").should be(true)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should include reset.css" do
|
20
|
+
@css_reader.stylesheets.include?("reset.css").should be(true)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should include typography.css" do
|
24
|
+
@css_reader.stylesheets.include?("typography.css").should be(true)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should include basic_stuff.css" do
|
28
|
+
@css_reader.stylesheets.include?("basic_stuff.css").should be(true)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should include basic_stuff.css" do
|
32
|
+
@css_reader.stylesheets.include?("more_stuff.css").should be(true)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should not include secondary.css" do
|
36
|
+
@css_reader.stylesheets.include?("secondary.css").should be(false)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should include secondary.css if we append it" do
|
40
|
+
@css_reader.append(@secondary_path)
|
41
|
+
@css_reader.stylesheets.include?("secondary.css").should be(true)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should include secondary.css if we open multiple docs on initialize" do
|
45
|
+
@css_reader = CSSReader.new(@test_path,@secondary_path)
|
46
|
+
@css_reader.stylesheets.include?("secondary.css").should be(true)
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "normal" do
|
50
|
+
before(:all) do
|
51
|
+
@css_text = @css_reader.normal
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should have '\#basic' before '\#more'" do
|
55
|
+
(@css_text.index("\#basic") < @css_text.index("\#more")).should be(true)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should 'body' before '\#basic'" do
|
59
|
+
(@css_text.index("body") < @css_text.index("\#basic")).should be(true)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should 'border: 0;' before 'body'" do
|
63
|
+
(@css_text.index("border: 0;") < @css_text.index("body")).should be(true)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should have '\#basic' before '\#primary_content'" do
|
67
|
+
(@css_text.index("\#basic") < @css_text.index("\#primary_content")).should be(true)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should not contain and @import statements" do
|
71
|
+
@css_text.match(/@import./).should be(nil)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should have new lines" do
|
75
|
+
@css_text.match(/\n/).nil?.should be(false)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should have comments" do
|
79
|
+
@css_text.match(/\/\*.*/).nil?.should be(false)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "compressed" do
|
84
|
+
before(:all) do
|
85
|
+
@css_text = @css_reader.compressed
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should not have any new lines" do
|
89
|
+
@css_text.match(/\n/).should be(nil)
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should not have any comments" do
|
93
|
+
@css_text.match(/\/\*.*/).should be(nil)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "save" do
|
98
|
+
before(:all) do
|
99
|
+
@normal = File.expand_path(File.join(File.dirname(__FILE__),'..','demo','normal.css'))
|
100
|
+
@compressed = File.expand_path(File.join(File.dirname(__FILE__),'..','demo','compressed.css'))
|
101
|
+
@css_reader.save(@normal)
|
102
|
+
@css_reader.save(@compressed, :compress => true)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should create a new file with the name 'normal.css'" do
|
106
|
+
File.exists?(@normal).should be(true)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should create a new file with the name 'compressed.css'" do
|
110
|
+
File.exists?(@compressed).should be(true)
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "compressed file" do
|
114
|
+
before(:all) do
|
115
|
+
@css_text = File.open(@compressed,"r").readlines.join("\n")
|
116
|
+
end
|
117
|
+
it "should not have any new lines" do
|
118
|
+
@css_text.match(/\n/).should be(nil)
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should not have any comments" do
|
122
|
+
@css_text.match(/\/\*.*/).should be(nil)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "normal file" do
|
127
|
+
before(:all) do
|
128
|
+
@css_text = File.open(@normal,"r").readlines.join("\n")
|
129
|
+
end
|
130
|
+
it "should have new lines" do
|
131
|
+
@css_text.match(/\n/).nil?.should be(false)
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should have comments" do
|
135
|
+
@css_text.match(/\/\*.*/).nil?.should be(false)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: assetbuild
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Jim Jeffers
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-04-08 00:00:00 +10:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: Easily merge and compress multiple asset files together (currently supports CSS and coffee-script).
|
22
|
+
email: shout@jimjeffers.com
|
23
|
+
executables:
|
24
|
+
- assetbuild
|
25
|
+
- buildcoffee
|
26
|
+
- buildcss
|
27
|
+
extensions: []
|
28
|
+
|
29
|
+
extra_rdoc_files:
|
30
|
+
- README
|
31
|
+
files:
|
32
|
+
- .gitignore
|
33
|
+
- Manifest
|
34
|
+
- README
|
35
|
+
- Rakefile
|
36
|
+
- VERSION
|
37
|
+
- bin/assetbuild
|
38
|
+
- bin/buildcoffee
|
39
|
+
- bin/buildcss
|
40
|
+
- demo/assetbuild.yml
|
41
|
+
- demo/assets.css
|
42
|
+
- demo/coffee_bundle/demo.coffee
|
43
|
+
- demo/coffee_bundle/demo2.coffee
|
44
|
+
- demo/main.js
|
45
|
+
- demo/secondary.css
|
46
|
+
- demo/stand_alone.coffee
|
47
|
+
- demo/stand_alone.js
|
48
|
+
- demo/styles/reset.css
|
49
|
+
- demo/styles/special/basic_stuff.css
|
50
|
+
- demo/styles/special/more_stuff.css
|
51
|
+
- demo/styles/typography.css
|
52
|
+
- demo/test.css
|
53
|
+
- lib/asset_build.rb
|
54
|
+
- lib/asset_build/coffee_bundler.rb
|
55
|
+
- lib/asset_build/css_reader.rb
|
56
|
+
- spec/asset_build_spec.rb
|
57
|
+
- spec/coffee_bundler_spec.rb
|
58
|
+
- spec/css_reader_spec.rb
|
59
|
+
has_rdoc: true
|
60
|
+
homepage: http://github.com/jimjeffers/assetbuild
|
61
|
+
licenses: []
|
62
|
+
|
63
|
+
post_install_message:
|
64
|
+
rdoc_options:
|
65
|
+
- --charset=UTF-8
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
segments:
|
80
|
+
- 0
|
81
|
+
version: "0"
|
82
|
+
requirements: []
|
83
|
+
|
84
|
+
rubyforge_project:
|
85
|
+
rubygems_version: 1.3.6
|
86
|
+
signing_key:
|
87
|
+
specification_version: 3
|
88
|
+
summary: Easily merge and compress multiple asset files together (currently supports CSS and coffee-script).
|
89
|
+
test_files:
|
90
|
+
- spec/asset_build_spec.rb
|
91
|
+
- spec/coffee_bundler_spec.rb
|
92
|
+
- spec/css_reader_spec.rb
|