assette 0.0.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/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +36 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +43 -0
- data/VERSION +1 -0
- data/assette.gemspec +113 -0
- data/examples/app/templates/foo/index.html.mustache +3 -0
- data/examples/config.ru +7 -0
- data/examples/defaults.rb +5 -0
- data/examples/defaults.yml +7 -0
- data/examples/public/images/test.pdf +0 -0
- data/examples/public/javascripts/foo.js +6 -0
- data/examples/public/javascripts/one.js +1 -0
- data/examples/public/javascripts/test.coffee +5 -0
- data/examples/public/javascripts/three.js +5 -0
- data/examples/public/javascripts/two.js +6 -0
- data/examples/public/stylesheets/one.css +1 -0
- data/examples/public/stylesheets/one1.sass +2 -0
- data/examples/public/stylesheets/two.css +7 -0
- data/examples/public/stylesheets/two2.scss +5 -0
- data/lib/assette.rb +24 -0
- data/lib/assette/compiled_file.rb +36 -0
- data/lib/assette/config.rb +35 -0
- data/lib/assette/file.rb +176 -0
- data/lib/assette/reader.rb +96 -0
- data/lib/assette/readers.rb +4 -0
- data/lib/assette/readers/coffee.rb +31 -0
- data/lib/assette/readers/css.rb +14 -0
- data/lib/assette/readers/js.rb +13 -0
- data/lib/assette/readers/sass.rb +18 -0
- data/lib/assette/readers/scss.rb +9 -0
- data/lib/assette/server.rb +83 -0
- data/lib/assette/template.rb +21 -0
- data/lib/assette/template_set.rb +76 -0
- data/spec/assette_spec.rb +5 -0
- data/spec/file_spec.rb +97 -0
- data/spec/reader_spec.rb +41 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/template_spec.rb +43 -0
- metadata +249 -0
data/lib/assette/file.rb
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
class Assette::File < ::File
|
2
|
+
extend Forwardable
|
3
|
+
|
4
|
+
def text
|
5
|
+
@text || (dependencies && @text)
|
6
|
+
end
|
7
|
+
|
8
|
+
def extension
|
9
|
+
m = path.match(/\.(\w+)$/)
|
10
|
+
m[1] if m
|
11
|
+
end
|
12
|
+
|
13
|
+
def reader_class
|
14
|
+
if klass = Assette::Reader::ALL[extension]
|
15
|
+
klass
|
16
|
+
else
|
17
|
+
raise "Can't find reader class Assette::Reader::#{extension.capitalize}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def target_class
|
22
|
+
return @target_class if @target_class
|
23
|
+
ex = reader_class.outputs
|
24
|
+
|
25
|
+
raise(Exception, "Define @outputs for #{reader_class.class}") unless ex
|
26
|
+
|
27
|
+
if @target_class = Assette::Reader::ALL[ex.to_s]
|
28
|
+
@target_class
|
29
|
+
else
|
30
|
+
raise "Can't find reader class Assette::Reader::#{ex.capitalize}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def mime_type
|
35
|
+
@mime_type ||= MIME::Types.type_for(path).first
|
36
|
+
end
|
37
|
+
|
38
|
+
def comment_str
|
39
|
+
target_class.comment_str
|
40
|
+
end
|
41
|
+
|
42
|
+
def code
|
43
|
+
reader_class.new(self).compile
|
44
|
+
end
|
45
|
+
|
46
|
+
def all_code_array
|
47
|
+
dep = Assette::CompiledFile.new(self)
|
48
|
+
|
49
|
+
if !templates.empty?
|
50
|
+
set = Assette::TemplateSet.new(templates)
|
51
|
+
|
52
|
+
dep << set.compile
|
53
|
+
end
|
54
|
+
|
55
|
+
dependencies.each {|d| dep.add_dependency(d)}
|
56
|
+
|
57
|
+
dep.add_dependency(self)
|
58
|
+
|
59
|
+
dep
|
60
|
+
end
|
61
|
+
|
62
|
+
def all_code
|
63
|
+
all_code_array.join("\n")
|
64
|
+
end
|
65
|
+
|
66
|
+
def dirname
|
67
|
+
File.dirname(path)
|
68
|
+
end
|
69
|
+
|
70
|
+
def filename
|
71
|
+
path.gsub(dirname,'').gsub(/^\//,'')
|
72
|
+
end
|
73
|
+
|
74
|
+
def puts *args
|
75
|
+
STDOUT.puts *args
|
76
|
+
end
|
77
|
+
|
78
|
+
def == other
|
79
|
+
if other.instance_of?(self.class)
|
80
|
+
other.path == path
|
81
|
+
else
|
82
|
+
super
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def read
|
87
|
+
@read ||= super
|
88
|
+
end
|
89
|
+
|
90
|
+
def dependencies
|
91
|
+
return @dependencies if @dependencies
|
92
|
+
|
93
|
+
@dependencies = []
|
94
|
+
|
95
|
+
read_config do |l|
|
96
|
+
m = l.match /@require(?:s)?\s+([\w\.\/-]+)/
|
97
|
+
next unless m
|
98
|
+
|
99
|
+
p = ::File.expand_path(::File.join(dirname,m[1]))
|
100
|
+
|
101
|
+
# Check for _filename if filename doesn't exist
|
102
|
+
unless ::File.exist?(p)
|
103
|
+
p2 = p.gsub /(.*\/)?(.+)/, '\1_\2'
|
104
|
+
if ::File.exist?(p2)
|
105
|
+
p = p2
|
106
|
+
else
|
107
|
+
raise "Cannot find dependancy #{p} or #{p2} as required in #{path}"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
f = Assette::File.open(p)
|
112
|
+
|
113
|
+
@dependencies << f
|
114
|
+
f.dependencies.each do |d|
|
115
|
+
@dependencies << d unless @dependencies.include?(d)
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
@dependencies
|
121
|
+
end
|
122
|
+
|
123
|
+
def templates
|
124
|
+
return @templates if @templates
|
125
|
+
|
126
|
+
@templates = []
|
127
|
+
|
128
|
+
read_config do |line|
|
129
|
+
m = line.match /@template(?:s)?\s+(\w+)/
|
130
|
+
next unless m
|
131
|
+
|
132
|
+
@templates << m[1]
|
133
|
+
end
|
134
|
+
|
135
|
+
dependencies.each do |dep|
|
136
|
+
dep.templates.each do |template|
|
137
|
+
@templates << template unless @templates.include?(template)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
@templates
|
142
|
+
end
|
143
|
+
|
144
|
+
def read_config
|
145
|
+
started = nil
|
146
|
+
@text = read
|
147
|
+
@text.each_line do |l|
|
148
|
+
next unless started ||= (l =~ /#{Assette::CONFIG_WRAPPER}/)
|
149
|
+
break if l =~ /\/#{Assette::CONFIG_WRAPPER}/
|
150
|
+
|
151
|
+
yield(l)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
class << self
|
156
|
+
|
157
|
+
def all_code_for *args
|
158
|
+
start = Time.now
|
159
|
+
f = open(*args)
|
160
|
+
code = f.all_code
|
161
|
+
code << "\n"
|
162
|
+
code << f.comment_str % "Time taken to generate: #{Time.now-start}s"
|
163
|
+
end
|
164
|
+
|
165
|
+
def rack_resp_if_exists path
|
166
|
+
return unless File.exist?(path)
|
167
|
+
start = Time.now
|
168
|
+
f = open(path)
|
169
|
+
code = f.all_code_array
|
170
|
+
code << "\n"
|
171
|
+
code << f.comment_str % "Time taken to generate: #{Time.now-start}s"
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Assette
|
2
|
+
module Reader
|
3
|
+
extend self
|
4
|
+
OUTPUTS = Hash.new {|h,k| h[k] = []}
|
5
|
+
ALL = {}
|
6
|
+
|
7
|
+
def possible_targets path
|
8
|
+
match = path.match(/(.+\.)([a-z]+)$/i)
|
9
|
+
return [] unless match
|
10
|
+
file = match[1]
|
11
|
+
ext = match[2]
|
12
|
+
|
13
|
+
OUTPUTS[ext.to_sym].collect { |cla| file + cla.extension }
|
14
|
+
end
|
15
|
+
|
16
|
+
class Base
|
17
|
+
attr_reader :file
|
18
|
+
def initialize(file)
|
19
|
+
@file = file
|
20
|
+
end
|
21
|
+
|
22
|
+
def text
|
23
|
+
@file.text
|
24
|
+
end
|
25
|
+
|
26
|
+
def compile
|
27
|
+
raise Exception, "You must implement the compile method for #{self.class.inspect}"
|
28
|
+
end
|
29
|
+
|
30
|
+
class << self
|
31
|
+
|
32
|
+
# Gets called twice currenlty, once on Class.new(Reader::Base)
|
33
|
+
# and once on the subclassing. Gotta fix that
|
34
|
+
def inherited subclass
|
35
|
+
return if subclass == Assette::Reader::Base || subclass.inspect =~ /#<Class/
|
36
|
+
|
37
|
+
if outputs
|
38
|
+
Assette::Reader::OUTPUTS[outputs] |= [subclass]
|
39
|
+
end
|
40
|
+
|
41
|
+
subclass.set_extension
|
42
|
+
end
|
43
|
+
|
44
|
+
def extension
|
45
|
+
if m = self.inspect.match(/::(\w+)$/i)
|
46
|
+
m[1].downcase
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def outputs
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
def set_outputs val
|
55
|
+
raise ArgumentError, 'must set outputs to a symbol' unless val.is_a?(Symbol)
|
56
|
+
|
57
|
+
instance_eval <<-RUBY
|
58
|
+
def outputs
|
59
|
+
#{val.inspect}
|
60
|
+
end
|
61
|
+
RUBY
|
62
|
+
val
|
63
|
+
end
|
64
|
+
|
65
|
+
def set_extension val = nil
|
66
|
+
if val
|
67
|
+
raise ArgumentError, 'must set extension to a symbol' unless val.is_a?(Symbol)
|
68
|
+
instance_eval <<-RUBY
|
69
|
+
def extension
|
70
|
+
#{val.inspect}
|
71
|
+
end
|
72
|
+
RUBY
|
73
|
+
end
|
74
|
+
|
75
|
+
if ex = extension
|
76
|
+
Assette::Reader::ALL[ex] = self
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def mime_type
|
81
|
+
@mime_type ||= MIME::Types.type_for("test.#{extension}").first
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.Reader(type)
|
91
|
+
c = Class.new(Reader::Base)
|
92
|
+
c.set_outputs(type)
|
93
|
+
c
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
class Assette::Reader::Coffee < Assette::Reader(:js)
|
4
|
+
|
5
|
+
def compile
|
6
|
+
self.class.compile_str text
|
7
|
+
end
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
def compile_str text
|
12
|
+
out = nil
|
13
|
+
|
14
|
+
Open3.popen3('coffee -sc') do |stdin, stdout, stderr|
|
15
|
+
stdin.puts(text)
|
16
|
+
stdin.close_write
|
17
|
+
out = stdout.read
|
18
|
+
end
|
19
|
+
|
20
|
+
out
|
21
|
+
end
|
22
|
+
|
23
|
+
def comment_str
|
24
|
+
'#'
|
25
|
+
end
|
26
|
+
|
27
|
+
def comment_str_end
|
28
|
+
''
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'haml'
|
2
|
+
require 'sass'
|
3
|
+
class Assette::Reader::Sass < Assette::Reader(:css)
|
4
|
+
|
5
|
+
def compile
|
6
|
+
engine = ::Sass::Engine.new(text,options)
|
7
|
+
engine.to_css
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def options
|
13
|
+
{
|
14
|
+
:syndtax => :sass,
|
15
|
+
:load_paths => [File.expand_path(@file.dirname)]|Assette.config.file_paths
|
16
|
+
}
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Assette
|
2
|
+
# Methods for finding files are ugly, should fix someday
|
3
|
+
class Server
|
4
|
+
attr_reader :path
|
5
|
+
def initialize(path)
|
6
|
+
@path = path
|
7
|
+
Assette.config.asset_path
|
8
|
+
end
|
9
|
+
|
10
|
+
def find_compiled_file
|
11
|
+
f = nil
|
12
|
+
Assette.config.file_paths.each do |p|
|
13
|
+
|
14
|
+
Assette::Reader.possible_targets(File.join(p,path)).each do |pp|
|
15
|
+
f = Assette::File.rack_resp_if_exists( pp )
|
16
|
+
break if f
|
17
|
+
end
|
18
|
+
|
19
|
+
break if f
|
20
|
+
end
|
21
|
+
f
|
22
|
+
end
|
23
|
+
|
24
|
+
def path_extension
|
25
|
+
m = path.match(/\.(\w+)$/)
|
26
|
+
m[1] if m
|
27
|
+
end
|
28
|
+
|
29
|
+
def has_registered_reader?
|
30
|
+
!Assette::Reader::OUTPUTS[path_extension.to_sym].empty?
|
31
|
+
end
|
32
|
+
|
33
|
+
def path_mime_type
|
34
|
+
@path_mime_type ||= MIME::Types.type_for(path).first
|
35
|
+
end
|
36
|
+
|
37
|
+
def content_type
|
38
|
+
path_mime_type ? path_mime_type.content_type : 'text/plain'
|
39
|
+
end
|
40
|
+
|
41
|
+
def find_file
|
42
|
+
f = nil
|
43
|
+
|
44
|
+
Assette.config.file_paths.each do |p|
|
45
|
+
new_path = File.join(p,path)
|
46
|
+
if File.exist?(new_path)
|
47
|
+
f = File.open(new_path)
|
48
|
+
# add in grabbing index.html files if no extension provided
|
49
|
+
end
|
50
|
+
|
51
|
+
break if f
|
52
|
+
end
|
53
|
+
|
54
|
+
f
|
55
|
+
end
|
56
|
+
|
57
|
+
def rack_resp
|
58
|
+
|
59
|
+
if has_registered_reader? && (f = find_compiled_file)
|
60
|
+
[200,{"Content-Type" => f.content_type},f]
|
61
|
+
elsif (f = find_file) && path_mime_type
|
62
|
+
puts content_type
|
63
|
+
[200,{"Content-Type" => content_type},f]
|
64
|
+
else
|
65
|
+
[404,{"Content-Type" => "text/plain"},["File Not Found"]]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class << self
|
70
|
+
|
71
|
+
def call(env)
|
72
|
+
s = new(env["PATH_INFO"])
|
73
|
+
|
74
|
+
s.rack_resp
|
75
|
+
# rescue => e
|
76
|
+
# [500,{"Content-Type" => "text/plain"},[e.inspect]]
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|