bunch 0.2.2 → 1.0.0pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -6
- data/Gemfile +3 -1
- data/Guardfile +5 -0
- data/LICENSE.txt +22 -0
- data/Rakefile +7 -12
- data/bin/bunch +2 -5
- data/bunch.gemspec +30 -23
- data/lib/bunch.rb +37 -81
- data/lib/bunch/cli.rb +40 -74
- data/lib/bunch/combiner.rb +121 -0
- data/lib/bunch/compiler.rb +52 -0
- data/lib/bunch/compilers/coffee_script.rb +23 -0
- data/lib/bunch/compilers/ejs.rb +28 -0
- data/lib/bunch/compilers/jade.rb +28 -0
- data/lib/bunch/compilers/jst.rb +38 -0
- data/lib/bunch/compilers/null.rb +19 -0
- data/lib/bunch/compilers/sass.rb +55 -0
- data/lib/bunch/content_hash.rb +37 -0
- data/lib/bunch/css_minifier.rb +121 -0
- data/lib/bunch/file.rb +18 -0
- data/lib/bunch/file_cache.rb +159 -0
- data/lib/bunch/file_tree.rb +153 -0
- data/lib/bunch/ignorer.rb +38 -0
- data/lib/bunch/js_minifier.rb +38 -0
- data/lib/bunch/middleware.rb +16 -67
- data/lib/bunch/pipeline.rb +30 -0
- data/lib/bunch/server.rb +56 -0
- data/lib/bunch/simple_cache.rb +36 -0
- data/lib/bunch/tree_merge.rb +29 -0
- data/lib/bunch/version.rb +3 -1
- data/spec/bunch/cli_spec.rb +85 -0
- data/spec/bunch/combiner_spec.rb +107 -0
- data/spec/bunch/compiler_spec.rb +73 -0
- data/spec/bunch/compilers/coffee_script_spec.rb +23 -0
- data/spec/bunch/compilers/ejs_spec.rb +27 -0
- data/spec/bunch/compilers/jade_spec.rb +28 -0
- data/spec/bunch/compilers/sass_spec.rb +120 -0
- data/spec/bunch/css_minifier_spec.rb +31 -0
- data/spec/bunch/file_cache_spec.rb +151 -0
- data/spec/bunch/file_tree_spec.rb +127 -0
- data/spec/bunch/ignorer_spec.rb +26 -0
- data/spec/bunch/js_minifier_spec.rb +35 -0
- data/spec/bunch/middleware_spec.rb +41 -0
- data/spec/bunch/pipeline_spec.rb +31 -0
- data/spec/bunch/server_spec.rb +90 -0
- data/spec/bunch/simple_cache_spec.rb +55 -0
- data/spec/bunch/tree_merge_spec.rb +30 -0
- data/spec/bunch_spec.rb +6 -0
- data/spec/example_tree/directory/_combine +2 -0
- data/{example/js/test1.js → spec/example_tree/directory/file1} +0 -0
- data/{example/js/test2/test2a.js → spec/example_tree/directory/file2} +0 -0
- data/{example/js/test2/test2c.js → spec/example_tree/file3} +0 -0
- data/spec/spec_helper.rb +38 -0
- metadata +224 -102
- data/.yardopts +0 -1
- data/README.md +0 -4
- data/config.ru +0 -6
- data/example/config.ru +0 -6
- data/example/css/test1.css +0 -1
- data/example/css/test2/test2a.scss +0 -1
- data/example/css/test2/test2b.css +0 -1
- data/example/js/.bunchignore +0 -1
- data/example/js/test2/_.yml +0 -2
- data/example/js/test2/foo.js +0 -1
- data/example/js/test2/test2b.js +0 -1
- data/example/js/test3/test3a.js +0 -1
- data/example/js/test3/test3b/_.yml +0 -1
- data/example/js/test3/test3b/test3bi.js +0 -1
- data/example/js/test3/test3b/test3bii.js +0 -1
- data/example/js/test4/_.yml +0 -1
- data/example/js/test4/test4a.js +0 -1
- data/example/js/test4/test4b.coffee +0 -1
- data/example/js/test4/test4c.coffee +0 -1
- data/example/js/test5/test5a.jst.ejs +0 -1
- data/lib/bunch/abstract_node.rb +0 -25
- data/lib/bunch/cache.rb +0 -40
- data/lib/bunch/coffee_node.rb +0 -39
- data/lib/bunch/directory_node.rb +0 -82
- data/lib/bunch/ejs_node.rb +0 -50
- data/lib/bunch/file_node.rb +0 -25
- data/lib/bunch/jade_node.rb +0 -50
- data/lib/bunch/null_node.rb +0 -11
- data/lib/bunch/rack.rb +0 -38
- data/lib/bunch/sass_node.rb +0 -39
- data/test/middleware_test.rb +0 -26
- data/test/rack_test.rb +0 -93
- data/test/test_helper.rb +0 -21
data/.yardopts
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
--markup markdown --private
|
data/README.md
DELETED
data/config.ru
DELETED
data/example/config.ru
DELETED
data/example/css/test1.css
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
body { a: 1; }
|
@@ -1 +0,0 @@
|
|
1
|
-
body { b: 2; }
|
@@ -1 +0,0 @@
|
|
1
|
-
body { c: 3; }
|
data/example/js/.bunchignore
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
foo
|
data/example/js/test2/_.yml
DELETED
data/example/js/test2/foo.js
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
foo;
|
data/example/js/test2/test2b.js
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
4
|
data/example/js/test3/test3a.js
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
5
|
@@ -1 +0,0 @@
|
|
1
|
-
- test3bii
|
@@ -1 +0,0 @@
|
|
1
|
-
7
|
@@ -1 +0,0 @@
|
|
1
|
-
6
|
data/example/js/test4/_.yml
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
- test4c
|
data/example/js/test4/test4a.js
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
9
|
@@ -1 +0,0 @@
|
|
1
|
-
10
|
@@ -1 +0,0 @@
|
|
1
|
-
8
|
@@ -1 +0,0 @@
|
|
1
|
-
11
|
data/lib/bunch/abstract_node.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
module Bunch
|
2
|
-
class AbstractNode
|
3
|
-
attr_accessor :options
|
4
|
-
|
5
|
-
def content
|
6
|
-
raise NotImplementedError
|
7
|
-
end
|
8
|
-
alias name content
|
9
|
-
alias target_extension content
|
10
|
-
|
11
|
-
def write_to_dir(dir)
|
12
|
-
write_to_file(File.join(dir, name))
|
13
|
-
end
|
14
|
-
|
15
|
-
def write_to_file(fn)
|
16
|
-
out_file = "#{fn}#{target_extension}"
|
17
|
-
File.open(out_file, 'w') { |f| f.write(content) }
|
18
|
-
end
|
19
|
-
|
20
|
-
protected
|
21
|
-
def fetch(fn, &blk)
|
22
|
-
Cache.fetch(fn, &blk)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
data/lib/bunch/cache.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
module Bunch
|
2
|
-
module Cache
|
3
|
-
end
|
4
|
-
|
5
|
-
class << Cache
|
6
|
-
def init
|
7
|
-
@cache = Hash.new { |h, k| h[k] = {} }
|
8
|
-
end
|
9
|
-
|
10
|
-
def stored?(fn)
|
11
|
-
@cache.keys.include?(fn)
|
12
|
-
end
|
13
|
-
|
14
|
-
def read(fn)
|
15
|
-
@cache[fn][:content]
|
16
|
-
end
|
17
|
-
|
18
|
-
def mtime(fn)
|
19
|
-
@cache[fn][:mtime]
|
20
|
-
end
|
21
|
-
|
22
|
-
def write(fn, mtime, content)
|
23
|
-
@cache[fn] = {:mtime => mtime, :content => content}
|
24
|
-
end
|
25
|
-
|
26
|
-
def fetch(fn, &blk)
|
27
|
-
current_mtime = File.mtime(fn)
|
28
|
-
|
29
|
-
if stored?(fn) && mtime(fn) == current_mtime
|
30
|
-
read(fn)
|
31
|
-
else
|
32
|
-
content = blk.call
|
33
|
-
write(fn, current_mtime, content)
|
34
|
-
content
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
Cache.init
|
40
|
-
end
|
data/lib/bunch/coffee_node.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
module Bunch
|
2
|
-
class CoffeeNode < FileNode
|
3
|
-
def initialize(fn)
|
4
|
-
CoffeeNode.require_coffee
|
5
|
-
@filename = fn
|
6
|
-
end
|
7
|
-
|
8
|
-
def content
|
9
|
-
@content ||= fetch(@filename) { CoffeeScript.compile(File.read(@filename), :bare => CoffeeNode.bare) }
|
10
|
-
rescue => e
|
11
|
-
raise CompileError.new(e, @filename)
|
12
|
-
end
|
13
|
-
|
14
|
-
def name
|
15
|
-
File.basename(@filename, '.coffee')
|
16
|
-
end
|
17
|
-
|
18
|
-
def target_extension
|
19
|
-
'.js'
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
class << CoffeeNode
|
24
|
-
attr_writer :bare
|
25
|
-
|
26
|
-
def require_coffee
|
27
|
-
unless @required
|
28
|
-
require 'coffee-script'
|
29
|
-
@required = true
|
30
|
-
end
|
31
|
-
rescue LoadError
|
32
|
-
raise "'gem install coffee-script' to compile .coffee files."
|
33
|
-
end
|
34
|
-
|
35
|
-
def bare
|
36
|
-
defined?(@bare) ? @bare : (@bare = false)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
data/lib/bunch/directory_node.rb
DELETED
@@ -1,82 +0,0 @@
|
|
1
|
-
module Bunch
|
2
|
-
class DirectoryNode < AbstractNode
|
3
|
-
attr_reader :root
|
4
|
-
|
5
|
-
def initialize(fn)
|
6
|
-
@root = Pathname.new(fn)
|
7
|
-
end
|
8
|
-
|
9
|
-
def filenames
|
10
|
-
Dir[@root.join("*")].select { |f| f !~ /_\.yml$/ }
|
11
|
-
end
|
12
|
-
|
13
|
-
def children
|
14
|
-
@children ||= begin
|
15
|
-
children = filenames.map do |filename|
|
16
|
-
Bunch.tree_for(filename, @options)
|
17
|
-
end
|
18
|
-
|
19
|
-
ordering_file = @root.join('_.yml')
|
20
|
-
|
21
|
-
if File.exist?(ordering_file)
|
22
|
-
ordering = YAML.load_file(ordering_file)
|
23
|
-
ordered, unordered = children.partition { |c| ordering.include?(c.name) }
|
24
|
-
|
25
|
-
(ordering - ordered.map(&:name)).each do |f|
|
26
|
-
$stderr.puts "WARNING: directory #{ full_name } has no object #{ f }"
|
27
|
-
end
|
28
|
-
|
29
|
-
ordered.sort_by { |c| ordering.index(c.name) } + unordered.sort_by(&:name)
|
30
|
-
else
|
31
|
-
children.sort_by(&:name)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def target_extension
|
37
|
-
@target_extension ||= begin
|
38
|
-
exts = children.map(&:target_extension).compact.uniq
|
39
|
-
if exts.count == 1
|
40
|
-
exts.first
|
41
|
-
elsif exts.count > 1
|
42
|
-
raise "Directory #{name} contains non-homogeneous nodes: #{exts.inspect}"
|
43
|
-
else
|
44
|
-
nil
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def content
|
50
|
-
@content ||= children.map(&:content).join
|
51
|
-
end
|
52
|
-
|
53
|
-
def name
|
54
|
-
File.basename(@root)
|
55
|
-
end
|
56
|
-
|
57
|
-
def full_name
|
58
|
-
@root
|
59
|
-
end
|
60
|
-
|
61
|
-
def write_to_file(dir)
|
62
|
-
return if filenames.count == 0
|
63
|
-
super
|
64
|
-
end
|
65
|
-
|
66
|
-
def write_to_dir(dir)
|
67
|
-
super
|
68
|
-
|
69
|
-
if @options[:recurse]
|
70
|
-
directory_name = File.join(dir, name)
|
71
|
-
FileUtils.mkdir(directory_name)
|
72
|
-
children.each do |child|
|
73
|
-
child.write_to_dir(directory_name)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def inspect
|
79
|
-
"#<DirectoryNode @root=#{@root.inspect} @children=#{children.inspect}>"
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
data/lib/bunch/ejs_node.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
module Bunch
|
2
|
-
class EJSNode < FileNode
|
3
|
-
def initialize(fn)
|
4
|
-
EJSNode.require_ejs
|
5
|
-
@filename = fn
|
6
|
-
end
|
7
|
-
|
8
|
-
def content
|
9
|
-
@content ||= fetch(@filename) {
|
10
|
-
<<-JAVASCRIPT
|
11
|
-
(function() {
|
12
|
-
this.JST || (this.JST = {});
|
13
|
-
this.JST['#{template_name}'] = #{EJS.compile(File.read(@filename))};
|
14
|
-
})();
|
15
|
-
JAVASCRIPT
|
16
|
-
}
|
17
|
-
rescue => e
|
18
|
-
raise CompileError.new(e, @filename)
|
19
|
-
end
|
20
|
-
|
21
|
-
def name
|
22
|
-
File.basename(@filename, '.ejs')
|
23
|
-
end
|
24
|
-
|
25
|
-
def template_name
|
26
|
-
name = @filename.sub(/\.jst\.ejs$/, '')
|
27
|
-
|
28
|
-
if @options[:root]
|
29
|
-
name.sub(/^#{Regexp.escape(@options[:root].to_s)}\//, '')
|
30
|
-
else
|
31
|
-
name
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def target_extension
|
36
|
-
'.js'
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
class << EJSNode
|
41
|
-
def require_ejs
|
42
|
-
unless @required
|
43
|
-
require 'ejs'
|
44
|
-
@required = true
|
45
|
-
end
|
46
|
-
rescue LoadError
|
47
|
-
raise "'gem install ejs' to compile .ejs files."
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
data/lib/bunch/file_node.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
module Bunch
|
2
|
-
class FileNode < AbstractNode
|
3
|
-
attr_accessor :name, :target_extension
|
4
|
-
|
5
|
-
def initialize(fn)
|
6
|
-
@filename = fn
|
7
|
-
|
8
|
-
if fn =~ /\.[^.]*$/
|
9
|
-
@name = File.basename($`)
|
10
|
-
@target_extension = $&
|
11
|
-
else
|
12
|
-
@name = File.basename(@filename)
|
13
|
-
@target_extension = nil
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def content
|
18
|
-
File.read(@filename)
|
19
|
-
end
|
20
|
-
|
21
|
-
def inspect
|
22
|
-
@filename.inspect
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
data/lib/bunch/jade_node.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
module Bunch
|
2
|
-
class JadeNode < FileNode
|
3
|
-
def initialize(fn)
|
4
|
-
JadeNode.require_jade
|
5
|
-
@filename = fn
|
6
|
-
end
|
7
|
-
|
8
|
-
def content
|
9
|
-
@content ||= fetch(@filename) {
|
10
|
-
<<-JAVASCRIPT
|
11
|
-
(function() {
|
12
|
-
this.JST || (this.JST = {});
|
13
|
-
this.JST['#{template_name}'] = #{Jade.compile(File.read(@filename))};
|
14
|
-
})();
|
15
|
-
JAVASCRIPT
|
16
|
-
}
|
17
|
-
rescue => e
|
18
|
-
raise CompileError.new(e, @filename)
|
19
|
-
end
|
20
|
-
|
21
|
-
def name
|
22
|
-
File.basename(@filename, '.jade')
|
23
|
-
end
|
24
|
-
|
25
|
-
def template_name
|
26
|
-
name = @filename.sub(/\.jst\.jade/, '')
|
27
|
-
|
28
|
-
if @options[:root]
|
29
|
-
name.sub(/^#{Regexp.escape(@options[:root].to_s)}\//, '')
|
30
|
-
else
|
31
|
-
name
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def target_extension
|
36
|
-
'.js'
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
class << JadeNode
|
41
|
-
def require_jade
|
42
|
-
unless @required
|
43
|
-
require 'ruby-jade'
|
44
|
-
@required = true
|
45
|
-
end
|
46
|
-
rescue LoadError
|
47
|
-
raise "'gem install ruby-jade' to compile .jade files."
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
data/lib/bunch/null_node.rb
DELETED
data/lib/bunch/rack.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
module Bunch
|
2
|
-
class Rack
|
3
|
-
def initialize(path, opts={})
|
4
|
-
@root = Pathname.new(path)
|
5
|
-
@headers = {}
|
6
|
-
|
7
|
-
if opts.delete(:no_cache)
|
8
|
-
@headers['Cache-Control'] = 'private, max-age=0, must-revalidate'
|
9
|
-
@headers['Pragma'] = 'no-cache'
|
10
|
-
@headers['Expires'] = 'Thu, 01 Dec 1994 16:00:00 GMT'
|
11
|
-
end
|
12
|
-
|
13
|
-
Bunch.load_ignores(@root)
|
14
|
-
end
|
15
|
-
|
16
|
-
def call(env)
|
17
|
-
path = @root.join(env['PATH_INFO'].sub(/^\//, '')).to_s
|
18
|
-
type = MIME::Types.type_for(path).first || 'text/plain'
|
19
|
-
|
20
|
-
[200, headers(type), [content_for(path)]]
|
21
|
-
rescue => e
|
22
|
-
[500, headers('text/plain'), [error_log(e)]]
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
def content_for(path)
|
27
|
-
Bunch.content_for(path, :root => @root)
|
28
|
-
end
|
29
|
-
|
30
|
-
def headers(mime_type)
|
31
|
-
@headers.merge('Content-Type' => mime_type.to_s)
|
32
|
-
end
|
33
|
-
|
34
|
-
def error_log(e)
|
35
|
-
"#{e.class}: #{e.message}\n #{e.backtrace.join("\n ")}"
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|