assetbuild 0.1.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/.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
|