bunch 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/Rakefile +1 -0
- data/bin/bunch +7 -0
- data/bunch.gemspec +23 -0
- data/config.ru +6 -0
- data/example/config.ru +6 -0
- data/example/css/test1.css +1 -0
- data/example/css/test2/test2a.scss +1 -0
- data/example/css/test2/test2b.css +1 -0
- data/example/js/test1.js +1 -0
- data/example/js/test2/_.yml +2 -0
- data/example/js/test2/test2a.js +1 -0
- data/example/js/test2/test2b.js +1 -0
- data/example/js/test2/test2c.js +1 -0
- data/example/js/test3/test3a.js +1 -0
- data/example/js/test3/test3b/_.yml +1 -0
- data/example/js/test3/test3b/test3bi.js +1 -0
- data/example/js/test3/test3b/test3bii.js +1 -0
- data/example/js/test4/_.yml +1 -0
- data/example/js/test4/test4a.js +1 -0
- data/example/js/test4/test4b.coffee +1 -0
- data/example/js/test4/test4c.coffee +1 -0
- data/lib/bunch.rb +37 -0
- data/lib/bunch/cli.rb +76 -0
- data/lib/bunch/coffee_node.rb +26 -0
- data/lib/bunch/directory_node.rb +51 -0
- data/lib/bunch/file_node.rb +24 -0
- data/lib/bunch/rack.rb +33 -0
- data/lib/bunch/sass_node.rb +26 -0
- data/lib/bunch/version.rb +3 -0
- metadata +100 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/bunch
ADDED
data/bunch.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "bunch/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "bunch"
|
7
|
+
s.version = Bunch::VERSION
|
8
|
+
s.authors = ["Ryan Fitzgerald"]
|
9
|
+
s.email = ["rwfitzge@gmail.com"]
|
10
|
+
s.homepage = "http://rynftz.gr"
|
11
|
+
s.summary = %q{Simple, directory-structure-based asset bundling.}
|
12
|
+
s.description = %q{Simple, directory-structure-based asset bundling.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "bunch"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_runtime_dependency "mime-types"
|
22
|
+
s.add_runtime_dependency "slop"
|
23
|
+
end
|
data/config.ru
ADDED
data/example/config.ru
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
body { a: 1; }
|
@@ -0,0 +1 @@
|
|
1
|
+
body { b: 2; }
|
@@ -0,0 +1 @@
|
|
1
|
+
body { c: 3; }
|
data/example/js/test1.js
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1
|
@@ -0,0 +1 @@
|
|
1
|
+
2
|
@@ -0,0 +1 @@
|
|
1
|
+
4
|
@@ -0,0 +1 @@
|
|
1
|
+
3
|
@@ -0,0 +1 @@
|
|
1
|
+
5
|
@@ -0,0 +1 @@
|
|
1
|
+
- test3bii
|
@@ -0,0 +1 @@
|
|
1
|
+
7
|
@@ -0,0 +1 @@
|
|
1
|
+
6
|
@@ -0,0 +1 @@
|
|
1
|
+
- test4c
|
@@ -0,0 +1 @@
|
|
1
|
+
9
|
@@ -0,0 +1 @@
|
|
1
|
+
10
|
@@ -0,0 +1 @@
|
|
1
|
+
8
|
data/lib/bunch.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'pathname'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
require 'mime/types'
|
6
|
+
require 'slop'
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'v8'
|
10
|
+
rescue LoadError
|
11
|
+
$stderr.puts "WARNING: 'gem install therubyracer' for much faster CoffeeScript compilation."
|
12
|
+
end
|
13
|
+
|
14
|
+
require 'bunch/version'
|
15
|
+
require 'bunch/directory_node'
|
16
|
+
require 'bunch/file_node'
|
17
|
+
require 'bunch/coffee_node'
|
18
|
+
require 'bunch/sass_node'
|
19
|
+
require 'bunch/rack'
|
20
|
+
|
21
|
+
module Bunch
|
22
|
+
end
|
23
|
+
|
24
|
+
class << Bunch
|
25
|
+
def Tree(fn)
|
26
|
+
case
|
27
|
+
when File.directory?(fn)
|
28
|
+
Bunch::DirectoryNode.new(fn)
|
29
|
+
when fn =~ /\.coffee$/
|
30
|
+
Bunch::CoffeeNode.new(fn)
|
31
|
+
when fn =~ /\.s(a|c)ss$/
|
32
|
+
Bunch::SassNode.new(fn)
|
33
|
+
else
|
34
|
+
Bunch::FileNode.new(fn)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/bunch/cli.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
module Bunch
|
2
|
+
class CLI
|
3
|
+
def initialize(input, output, opts)
|
4
|
+
@input = Pathname.new(input)
|
5
|
+
@output = output ? Pathname.new(output) : nil
|
6
|
+
@opts = opts
|
7
|
+
end
|
8
|
+
|
9
|
+
def process!
|
10
|
+
tree = Bunch::Tree(@input.to_s)
|
11
|
+
|
12
|
+
if @output
|
13
|
+
FileUtils.mkdir_p(@output.to_s)
|
14
|
+
end
|
15
|
+
|
16
|
+
if @opts[:all]
|
17
|
+
if @output
|
18
|
+
write(@output.join("all.#{tree.target_extension}"), tree.contents)
|
19
|
+
else
|
20
|
+
puts tree.contents
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
if @opts[:individual]
|
25
|
+
tree.children.each do |child|
|
26
|
+
write(@output.join("#{child.name}.#{child.target_extension}"), child.contents)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def write(fn, contents)
|
33
|
+
File.open(fn, 'w') { |f| f.write(contents) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class << CLI
|
38
|
+
def process!
|
39
|
+
opts = Slop.parse! do
|
40
|
+
banner 'Usage: bunch [options] INPUT_PATH [OUTPUT_PATH]'
|
41
|
+
|
42
|
+
on :i, :individual, 'Create one output file for each file or directory in the input path (default)', :default => true
|
43
|
+
on :a, :all, 'Create an all.[extension] file combining all inputs'
|
44
|
+
on :h, :help, 'Show this message' do
|
45
|
+
display_help = true
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
if ARGV.count < 1
|
50
|
+
$stderr.puts "ERROR: Must give an input path."
|
51
|
+
display_help = true
|
52
|
+
end
|
53
|
+
|
54
|
+
if ARGV.count < 2 && opts[:individual]
|
55
|
+
$stderr.puts "ERROR: Must give an output path unless --no-individual is provided."
|
56
|
+
display_help = true
|
57
|
+
end
|
58
|
+
|
59
|
+
if display_help
|
60
|
+
$stderr.puts "\n#{opts}"
|
61
|
+
exit
|
62
|
+
end
|
63
|
+
|
64
|
+
input = ARGV.shift
|
65
|
+
output = ARGV.shift
|
66
|
+
|
67
|
+
CLI.new(input, output, opts).process!
|
68
|
+
rescue Exception => e
|
69
|
+
if ENV['BUNCH_DEBUG']
|
70
|
+
raise
|
71
|
+
else
|
72
|
+
$stderr.puts "ERROR: #{e.message}"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Bunch
|
2
|
+
class CoffeeNode
|
3
|
+
def initialize(fn)
|
4
|
+
require 'coffee-script'
|
5
|
+
@filename = fn
|
6
|
+
rescue LoadError
|
7
|
+
$stderr.puts "ERROR: 'gem install coffee-script' to compile .coffee files."
|
8
|
+
end
|
9
|
+
|
10
|
+
def contents
|
11
|
+
@contents ||= CoffeeScript.compile(File.read(@filename), :bare => false)
|
12
|
+
end
|
13
|
+
|
14
|
+
def name
|
15
|
+
File.basename(@filename, '.coffee')
|
16
|
+
end
|
17
|
+
|
18
|
+
def target_extension
|
19
|
+
'js'
|
20
|
+
end
|
21
|
+
|
22
|
+
def inspect
|
23
|
+
@filename.inspect
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Bunch
|
2
|
+
class DirectoryNode
|
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 &Bunch.method(:Tree)
|
16
|
+
ordering_file = @root.join('_.yml')
|
17
|
+
|
18
|
+
if File.exist?(ordering_file)
|
19
|
+
ordering = YAML.load_file(ordering_file)
|
20
|
+
ordered, unordered = children.partition { |c| ordering.include?(c.name) }
|
21
|
+
ordered.sort_by { |c| ordering.index(c.name) } + unordered.sort_by(&:name)
|
22
|
+
else
|
23
|
+
children.sort_by(&:name)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def target_extension
|
29
|
+
@target_extension ||= begin
|
30
|
+
exts = children.map(&:target_extension).compact.uniq
|
31
|
+
if exts.count == 1
|
32
|
+
exts.first
|
33
|
+
else
|
34
|
+
raise "Directory contains non-homogeneous nodes: #{exts.inspect}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def contents
|
40
|
+
@contents ||= children.map(&:contents).join
|
41
|
+
end
|
42
|
+
|
43
|
+
def name
|
44
|
+
File.basename(@root)
|
45
|
+
end
|
46
|
+
|
47
|
+
def inspect
|
48
|
+
"#<Node @root=#{@root.inspect} @children=#{children.inspect}>"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Bunch
|
2
|
+
class FileNode
|
3
|
+
attr_reader :name, :target_extension
|
4
|
+
|
5
|
+
def initialize(fn)
|
6
|
+
@filename = fn
|
7
|
+
|
8
|
+
if fn =~ %r(\.([^/]*?)$)
|
9
|
+
@name = File.basename($`)
|
10
|
+
@target_extension = $1
|
11
|
+
else
|
12
|
+
@name = File.basename(@filename)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def contents
|
17
|
+
File.read(@filename)
|
18
|
+
end
|
19
|
+
|
20
|
+
def inspect
|
21
|
+
@filename.inspect
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/bunch/rack.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module Bunch
|
2
|
+
class Rack
|
3
|
+
def initialize(path)
|
4
|
+
@root = Pathname.new(path)
|
5
|
+
end
|
6
|
+
|
7
|
+
def call(env)
|
8
|
+
path = @root.join(env['PATH_INFO'].sub(/^\//, '')).to_s
|
9
|
+
type = MIME::Types.type_for(path).first || 'text/plain'
|
10
|
+
|
11
|
+
[ 200, { 'Content-Type' => type.to_s }, [ generate(path) ] ]
|
12
|
+
rescue => e
|
13
|
+
[ 500, { 'Content-Type' => 'text/plain' }, [ error_log(e) ] ]
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def generate(path)
|
18
|
+
if File.exist?(path)
|
19
|
+
Bunch::Tree(path).contents
|
20
|
+
elsif File.exist?(chopped_path = path.sub(%r(\.[^/]*?$), ''))
|
21
|
+
Bunch::Tree(chopped_path).contents
|
22
|
+
elsif File.basename(path).start_with?('all.')
|
23
|
+
Bunch::Tree(File.dirname(path)).contents
|
24
|
+
else
|
25
|
+
raise Errno::ENOENT, path
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def error_log(e)
|
30
|
+
"#{e.class}: #{e.message}\n #{e.backtrace.join("\n ")}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Bunch
|
2
|
+
class SassNode
|
3
|
+
def initialize(fn)
|
4
|
+
require 'sass'
|
5
|
+
@filename = fn
|
6
|
+
rescue LoadError
|
7
|
+
$stderr.puts "ERROR: 'gem install sass' to compile .coffee files."
|
8
|
+
end
|
9
|
+
|
10
|
+
def contents
|
11
|
+
@contents ||= Sass::Engine.for_file(@filename, {}).render
|
12
|
+
end
|
13
|
+
|
14
|
+
def name
|
15
|
+
File.basename(@filename).sub(/\.s(c|a)ss$/, '')
|
16
|
+
end
|
17
|
+
|
18
|
+
def target_extension
|
19
|
+
'css'
|
20
|
+
end
|
21
|
+
|
22
|
+
def inspect
|
23
|
+
@filename.inspect
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bunch
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ryan Fitzgerald
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-12-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: mime-types
|
16
|
+
requirement: &70324537243860 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70324537243860
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: slop
|
27
|
+
requirement: &70324537243440 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70324537243440
|
36
|
+
description: Simple, directory-structure-based asset bundling.
|
37
|
+
email:
|
38
|
+
- rwfitzge@gmail.com
|
39
|
+
executables:
|
40
|
+
- bunch
|
41
|
+
extensions: []
|
42
|
+
extra_rdoc_files: []
|
43
|
+
files:
|
44
|
+
- .gitignore
|
45
|
+
- Gemfile
|
46
|
+
- Rakefile
|
47
|
+
- bin/bunch
|
48
|
+
- bunch.gemspec
|
49
|
+
- config.ru
|
50
|
+
- example/config.ru
|
51
|
+
- example/css/test1.css
|
52
|
+
- example/css/test2/test2a.scss
|
53
|
+
- example/css/test2/test2b.css
|
54
|
+
- example/js/test1.js
|
55
|
+
- example/js/test2/_.yml
|
56
|
+
- example/js/test2/test2a.js
|
57
|
+
- example/js/test2/test2b.js
|
58
|
+
- example/js/test2/test2c.js
|
59
|
+
- example/js/test3/test3a.js
|
60
|
+
- example/js/test3/test3b/_.yml
|
61
|
+
- example/js/test3/test3b/test3bi.js
|
62
|
+
- example/js/test3/test3b/test3bii.js
|
63
|
+
- example/js/test4/_.yml
|
64
|
+
- example/js/test4/test4a.js
|
65
|
+
- example/js/test4/test4b.coffee
|
66
|
+
- example/js/test4/test4c.coffee
|
67
|
+
- lib/bunch.rb
|
68
|
+
- lib/bunch/cli.rb
|
69
|
+
- lib/bunch/coffee_node.rb
|
70
|
+
- lib/bunch/directory_node.rb
|
71
|
+
- lib/bunch/file_node.rb
|
72
|
+
- lib/bunch/rack.rb
|
73
|
+
- lib/bunch/sass_node.rb
|
74
|
+
- lib/bunch/version.rb
|
75
|
+
homepage: http://rynftz.gr
|
76
|
+
licenses: []
|
77
|
+
post_install_message:
|
78
|
+
rdoc_options: []
|
79
|
+
require_paths:
|
80
|
+
- lib
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ! '>='
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
+
none: false
|
89
|
+
requirements:
|
90
|
+
- - ! '>='
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
requirements: []
|
94
|
+
rubyforge_project: bunch
|
95
|
+
rubygems_version: 1.8.10
|
96
|
+
signing_key:
|
97
|
+
specification_version: 3
|
98
|
+
summary: Simple, directory-structure-based asset bundling.
|
99
|
+
test_files: []
|
100
|
+
has_rdoc:
|