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.
Files changed (43) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +13 -0
  4. data/Gemfile.lock +36 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.rdoc +19 -0
  7. data/Rakefile +43 -0
  8. data/VERSION +1 -0
  9. data/assette.gemspec +113 -0
  10. data/examples/app/templates/foo/index.html.mustache +3 -0
  11. data/examples/config.ru +7 -0
  12. data/examples/defaults.rb +5 -0
  13. data/examples/defaults.yml +7 -0
  14. data/examples/public/images/test.pdf +0 -0
  15. data/examples/public/javascripts/foo.js +6 -0
  16. data/examples/public/javascripts/one.js +1 -0
  17. data/examples/public/javascripts/test.coffee +5 -0
  18. data/examples/public/javascripts/three.js +5 -0
  19. data/examples/public/javascripts/two.js +6 -0
  20. data/examples/public/stylesheets/one.css +1 -0
  21. data/examples/public/stylesheets/one1.sass +2 -0
  22. data/examples/public/stylesheets/two.css +7 -0
  23. data/examples/public/stylesheets/two2.scss +5 -0
  24. data/lib/assette.rb +24 -0
  25. data/lib/assette/compiled_file.rb +36 -0
  26. data/lib/assette/config.rb +35 -0
  27. data/lib/assette/file.rb +176 -0
  28. data/lib/assette/reader.rb +96 -0
  29. data/lib/assette/readers.rb +4 -0
  30. data/lib/assette/readers/coffee.rb +31 -0
  31. data/lib/assette/readers/css.rb +14 -0
  32. data/lib/assette/readers/js.rb +13 -0
  33. data/lib/assette/readers/sass.rb +18 -0
  34. data/lib/assette/readers/scss.rb +9 -0
  35. data/lib/assette/server.rb +83 -0
  36. data/lib/assette/template.rb +21 -0
  37. data/lib/assette/template_set.rb +76 -0
  38. data/spec/assette_spec.rb +5 -0
  39. data/spec/file_spec.rb +97 -0
  40. data/spec/reader_spec.rb +41 -0
  41. data/spec/spec_helper.rb +12 -0
  42. data/spec/template_spec.rb +43 -0
  43. metadata +249 -0
@@ -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,4 @@
1
+ fname = File.join(File.dirname(__FILE__),'readers','*.rb')
2
+ Dir[fname].each do |f|
3
+ require f
4
+ 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,14 @@
1
+ class Assette::Reader::Css < Assette::Reader(:css)
2
+
3
+ def compile
4
+ @file.text
5
+ end
6
+
7
+ class << self
8
+
9
+ def comment_str
10
+ @comment_str ||= '/* %s */'
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ class Assette::Reader::Js < Assette::Reader(:js)
2
+
3
+ def compile
4
+ @file.text
5
+ end
6
+
7
+ class << self
8
+
9
+ def comment_str
10
+ @comment_str ||= "// %s"
11
+ end
12
+ end
13
+ 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,9 @@
1
+ class Assette::Reader::Scss < Assette::Reader::Sass
2
+
3
+ private
4
+
5
+ def options
6
+ super.merge :syntax => :scss
7
+ end
8
+
9
+ 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