distil 0.13.6 → 0.14.0.b

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/Rakefile +1 -0
  2. data/VERSION +1 -1
  3. data/assets/distil.js +9 -7
  4. data/bin/distil +36 -60
  5. data/distil.gemspec +17 -32
  6. data/distil.tmproj +46 -15
  7. data/lib/distil/browser.rb +30 -26
  8. data/lib/distil/configurable.rb +64 -153
  9. data/lib/distil/error-reporter.rb +22 -20
  10. data/lib/distil/file-vendor.rb +29 -0
  11. data/lib/distil/hash-additions.rb +45 -0
  12. data/lib/distil/javascript-code.rb +12 -0
  13. data/lib/distil/{task/validate-js-task.rb → javascript-file-validator.rb} +19 -23
  14. data/lib/distil/library.rb +243 -0
  15. data/lib/distil/product/cache-manifest-product.rb +21 -0
  16. data/lib/distil/product/css-product.rb +41 -23
  17. data/lib/distil/product/html-product.rb +20 -0
  18. data/lib/distil/product/javascript-product.rb +122 -111
  19. data/lib/distil/product.rb +90 -76
  20. data/lib/distil/project.rb +370 -104
  21. data/lib/distil/recursive-http-fetcher.rb +72 -0
  22. data/lib/distil/server.rb +43 -0
  23. data/lib/distil/source-file/css-file.rb +56 -3
  24. data/lib/distil/source-file/html-file.rb +5 -6
  25. data/lib/distil/source-file/javascript-file.rb +96 -8
  26. data/lib/distil/source-file/json-file.rb +2 -4
  27. data/lib/distil/source-file/yui-minifiable-file.rb +19 -0
  28. data/lib/distil/source-file.rb +50 -92
  29. data/lib/distil/subclass-tracker.rb +13 -0
  30. data/lib/distil.rb +21 -37
  31. metadata +40 -39
  32. data/assets/mime.types +0 -1240
  33. data/lib/distil/configurable/file-set.rb +0 -85
  34. data/lib/distil/configurable/interpolated.rb +0 -36
  35. data/lib/distil/configurable/output-path.rb +0 -25
  36. data/lib/distil/configurable/project-path.rb +0 -25
  37. data/lib/distil/product/concatenated.rb +0 -83
  38. data/lib/distil/product/debug.rb +0 -32
  39. data/lib/distil/product/javascript-base-product.rb +0 -35
  40. data/lib/distil/product/javascript-doc-product.rb +0 -61
  41. data/lib/distil/product/minified.rb +0 -41
  42. data/lib/distil/product/page-product.rb +0 -27
  43. data/lib/distil/product/pdoc-product.rb +0 -42
  44. data/lib/distil/project/distil-project.rb +0 -157
  45. data/lib/distil/project/external-project.rb +0 -58
  46. data/lib/distil/project/remote-project.rb +0 -43
  47. data/lib/distil/target.rb +0 -251
  48. data/lib/distil/task/css-dependency-task.rb +0 -64
  49. data/lib/distil/task/jsl-dependency-task.rb +0 -50
  50. data/lib/distil/task/nib-task.rb +0 -72
  51. data/lib/distil/task.rb +0 -50
  52. data/lib/jsdoc.conf +0 -18
  53. data/lib/test/HtmlTestReporter.js +0 -127
  54. data/lib/test/Test.js +0 -248
  55. data/lib/test/TestReporter.js +0 -79
  56. data/lib/test/TestRunner.js +0 -132
  57. data/lib/test/browser.rb +0 -97
  58. data/lib/test/scriptwrapper.html +0 -10
  59. data/lib/test/unittest.html +0 -127
@@ -0,0 +1,243 @@
1
+ module Distil
2
+
3
+ LIBRARY_CACHE_FOLDER= File.expand_path("~/.distil/library_cache")
4
+
5
+ class Library < Configurable
6
+
7
+ attr_reader :name, :path, :href, :version, :include_path, :project
8
+ attr_reader :build_command, :revision, :protocol
9
+
10
+ def initialize(config, project)
11
+ @project= project
12
+
13
+ if config.is_a?(String)
14
+ config= {
15
+ :href=>config
16
+ }
17
+ end
18
+
19
+ configure_with(config) do |c|
20
+
21
+ c.with :href do |href|
22
+ @href= URI.parse(href)
23
+ case when svn_url?
24
+ @protocol= :svn
25
+ when git_url?
26
+ @protocol= :git
27
+ when http_folder?
28
+ @protocol= :http_recursive
29
+ else
30
+ @protocol= :http
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+ @name ||= File.basename(href.path, ".*")
37
+
38
+ if @path.nil?
39
+ parts= [LIBRARY_CACHE_FOLDER, href.host, File.dirname(href.path)]
40
+ case when svn_url? || git_url?
41
+ parts << File.basename(href.path, ".*")
42
+ when http_folder?
43
+ parts << File.basename(href.path)
44
+ end
45
+ @path= File.join(*parts)
46
+ @path << "-#{@version}" unless @version.nil?
47
+ end
48
+
49
+ @path= File.expand_path(@path)
50
+
51
+ update if !up_to_date?
52
+
53
+ Dir.chdir(path) do
54
+ case
55
+ when File.exist?("Buildfile") || File.exists?("buildfile") || File.exist?("#{name}.jsproj")
56
+ @build_command= APP_SCRIPT
57
+ remote_project= Project.find(path)
58
+ output_folder= remote_project ? remote_project.output_folder : 'build'
59
+ @product_path= File.join(path, output_folder)
60
+ when File.exist?("Makefile") || File.exist?("makefile")
61
+ @build_command= "make"
62
+ when File.exists?("Rakefile") || File.exists?("rakefile")
63
+ @build_command= "rake"
64
+ when File.exists?("Jakefile") || File.exists?("jakefile")
65
+ @build_command= "jake"
66
+ else
67
+ @build_command= ""
68
+ end
69
+ end
70
+
71
+ build
72
+ end
73
+
74
+ def to_s
75
+ "Library: #{name} @ #{path}"
76
+ end
77
+
78
+ def include_path
79
+ File.join(path, @include_path||"")
80
+ end
81
+
82
+ def product_path
83
+ @product_path || path
84
+ end
85
+
86
+ def svn_url?
87
+ "#{@href}" =~ /svn(?:\+ssh)?:\/\/*/
88
+ end
89
+
90
+ def git_url?
91
+ "#{@href}" =~ /^git:\/\// || "#{@href}" =~ /\.git$/
92
+ end
93
+
94
+ def http_folder?
95
+ File.extname(href.path).empty?
96
+ end
97
+
98
+ def require_git
99
+ begin
100
+ `git --version 2>/dev/null`
101
+ rescue
102
+ nil
103
+ end
104
+ if $?.nil? || !$?.success?
105
+ raise ValidationError.new("The git version control tool is required to pull this repository: #{uri}")
106
+ end
107
+ end
108
+
109
+ def fetch_with_git
110
+ require_git
111
+ FileUtils.mkdir_p(path)
112
+ Dir.chdir path do
113
+ clone_cmd = "git clone"
114
+ clone_cmd += " -b #{version}" unless version.nil?
115
+ clone_cmd += " #{href} ."
116
+ clone_cmd += " -q"
117
+ if !system(clone_cmd)
118
+ raise ValidationError.new("Failed to clone external project: #{href}")
119
+ end
120
+ end
121
+ end
122
+
123
+ def fetch_with_http
124
+ if !href.respond_to?(:read)
125
+ raise ValidationError, "Cannot read from project source url: #{href}"
126
+ end
127
+
128
+ FileUtils.mkdir_p(path)
129
+ begin
130
+ text= href.read
131
+ rescue OpenURI::HTTPError => http_error
132
+ raise ValidationError, "Unable to fetch remote project: status=#{http_error.io.status[0]} url=#{href}"
133
+ end
134
+ File.open(File.join(path, File.basename(href.path)), "w") { |output|
135
+ output.write text
136
+ }
137
+ end
138
+
139
+ def fetch_with_http_recursive
140
+ dir= File.dirname(path)
141
+ FileUtils.mkdir_p(dir)
142
+ fetcher= Distil::RecursiveHTTPFetcher.new(href, 1, dir)
143
+ fetcher.fetch
144
+ end
145
+
146
+ def fetch
147
+ self.send "fetch_with_#{@protocol}"
148
+ end
149
+
150
+ def update_with_git
151
+ require_git
152
+ Dir.chdir path do
153
+ command = "git pull"
154
+ command << " origin #{version}" if version
155
+ `#{command}`
156
+ end
157
+ end
158
+
159
+ def update_with_http
160
+ fetch_with_http
161
+ end
162
+
163
+ def update
164
+ if File.exists?(path)
165
+ self.send "update_with_#{@protocol}"
166
+ else
167
+ fetch
168
+ end
169
+ end
170
+
171
+ def output_path
172
+ @output_path||= File.join(project.output_path, name)
173
+ end
174
+
175
+ def up_to_date?
176
+ return false unless File.exists?(path)
177
+ return @up_to_date unless @up_to_date.nil?
178
+
179
+ case protocol
180
+ when :git
181
+ require_git
182
+ Dir.chdir path do
183
+ current_sha1= `git rev-parse #{version}`
184
+ origin_sha1= `git ls-remote #{href} #{version}`
185
+ if $?.exitstatus!=0
186
+ project.error("Could not determine whether library is up to date: #{name}")
187
+ return @up_to_date=true
188
+ end
189
+ origin_sha1= origin_sha1.split(/\s/)[0]
190
+ return @up_to_date= (current_sha1.strip==origin_sha1.strip)
191
+ end
192
+ else
193
+ @up_to_date= true
194
+ end
195
+ end
196
+
197
+ def build
198
+ update unless up_to_date?
199
+
200
+ unless build_command.empty?
201
+ Dir.chdir(path) do
202
+ exit 1 if !system("#{build_command}")
203
+ end
204
+ end
205
+
206
+ File.unlink(output_path) if File.symlink?(output_path)
207
+
208
+ # FileUtils.rm_rf(project_path) if File.directory?(project_path)
209
+ File.symlink(project.relative_output_path_for(product_path), output_path)
210
+ end
211
+
212
+ def content_for(content_type, variant=RELEASE_VARIANT)
213
+ file= file_for(content_type, variant)
214
+ return nil if !file
215
+ File.read(file)
216
+ end
217
+
218
+ def file_for(content_type, language=nil, variant=RELEASE_VARIANT)
219
+ if language
220
+ file= File.join(output_path, "#{name}-#{language}-#{variant}.#{content-type}")
221
+ return file if File.exists?(file)
222
+ file= File.join(output_path, "#{name}-#{language}-release.#{content-type}")
223
+ return file if File.exists?(file)
224
+ file= File.join(output_path, "#{name}-#{language}.#{content-type}")
225
+ return file if File.exists?(file)
226
+ end
227
+
228
+ file= File.join(output_path, "#{name}-#{variant}.#{content_type}")
229
+ return file if File.exists?(file)
230
+ file= File.join(output_path, "#{name}-release.#{content_type}")
231
+ return file if File.exists?(file)
232
+ file= File.join(output_path, "#{name}.#{content_type}")
233
+ return file if File.exists?(file)
234
+
235
+ candidates= Dir.glob(File.join(output_path, "*.#{content_type}"))
236
+ return candidates.first if 1==candidates.length
237
+
238
+ nil
239
+ end
240
+
241
+ end
242
+
243
+ end
@@ -0,0 +1,21 @@
1
+ module Distil
2
+
3
+ class CacheManifestProduct < Product
4
+ content_type "manifest"
5
+ variants [RELEASE_VARIANT]
6
+
7
+ def build
8
+ FileUtils.mkdir_p(File.dirname(output_path))
9
+ File.open(output_path, "w") { |output|
10
+ output.puts "CACHE MANIFEST"
11
+ output.puts "# generated @ #{Time.new.rfc2822}"
12
+ output.puts
13
+ project.assets.each { |a|
14
+ output.puts project.relative_output_path_for(a)
15
+ }
16
+ }
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -1,34 +1,52 @@
1
1
  module Distil
2
-
2
+
3
3
  class CssProduct < Product
4
- include Concatenated
5
- extension "css"
6
- end
4
+ content_type "css"
5
+ variants [RELEASE_VARIANT, DEBUG_VARIANT]
7
6
 
8
- class CssMinifiedProduct < Product
9
- include Minified
10
- extension "css"
11
- end
7
+ def build_debug
8
+ File.open(output_path, "w") { |output|
9
+
10
+ output.puts notice_comment
11
+ output_files= []
12
+
13
+ libraries.each { |l|
14
+ f= project.file_from_path(l.file_for(content_type, language, variant))
15
+ output_files << f if f
16
+ }
17
+
18
+ output_files += files
19
+
20
+ output_files.each { |f|
21
+ output.puts "@import url(\"#{f.relative_path}\");"
22
+ }
23
+
24
+ }
25
+ end
26
+
27
+ def build_release
28
+ File.open(output_path, "w") { |output|
12
29
 
13
- class CssDebugProduct < Product
14
- include Debug
15
- extension "css"
30
+ output.puts notice_comment
16
31
 
17
- def write_output
18
- return if up_to_date
19
- @up_to_date= true
20
-
21
- File.open(filename, "w") { |f|
22
- f.write(target.notice_text)
32
+ output_files= []
23
33
 
24
- external_files.each { |ext|
25
- next if !File.exist?(ext)
26
- f.write("@import url(\"#{relative_path(ext)}\");\n")
34
+ libraries.each { |l|
35
+ f= project.file_from_path(l.file_for(content_type, language, variant))
36
+ output_files << f if f
27
37
  }
28
-
29
- files.each { |file|
30
- f.write("@import url(\"#{relative_path(file)}\");\n")
38
+
39
+ output_files += files
40
+
41
+ output_files.each { |f|
42
+ content= f.rewrite_content_relative_to_path(nil)
43
+ next if !content || content.empty?
44
+
45
+ output.puts "/* #{f.relative_path} */"
46
+ output.puts content
47
+ output.puts ""
31
48
  }
49
+
32
50
  }
33
51
  end
34
52
 
@@ -0,0 +1,20 @@
1
+ module Distil
2
+
3
+ class HtmlProduct < Product
4
+ content_type "html"
5
+ variants [RELEASE_VARIANT]
6
+
7
+ def build
8
+ folder= File.dirname(output_path)
9
+ FileUtils.mkdir_p(folder)
10
+
11
+ files.each { |f|
12
+ product_path= File.join(folder, File.basename(f))
13
+ FileUtils.rm product_path if File.exists? product_path
14
+ File.symlink f.path_relative_to(folder), product_path
15
+ }
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -1,139 +1,150 @@
1
1
  module Distil
2
2
 
3
- class JavascriptProduct < JavascriptBaseProduct
4
- include Concatenated
5
-
6
- extension "js"
3
+ BOOTSTRAP_SCRIPT= "#{ASSETS_DIR}/distil.js"
4
+ FILE_SEPARATOR= " /*jsl:ignore*/;/*jsl:end*/"
5
+
6
+ class JavascriptProduct < Product
7
+ content_type "js"
8
+ variants [RELEASE_VARIANT, DEBUG_VARIANT]
7
9
 
8
- option :global_export
9
- option :additional_globals, [], :aliases=>['globals']
10
+ include ErrorReporter
10
11
 
11
- def before_externals(f)
12
- f.puts("/*#nocode+*/")
13
- f.puts(bootstrap_source) if bootstrap
12
+ MODULE_TEMPLATE= ERB.new %q{
13
+ distil.module("<%=project.name%>", <%=json_for(definition)%>);
14
+ }.gsub(/^\s*/, '')
15
+
16
+ def can_embed_as_content(file)
17
+ ["css", "html", "json"].include?(file.extension)
14
18
  end
15
19
 
16
- def after_externals(f)
20
+ def escape_embeded_content(file)
21
+ content= file.rewrite_content_relative_to_path(nil)
22
+ file.minified_content(content)
23
+ end
24
+
25
+ def json_for(obj)
26
+ JSON.generate(obj)
17
27
  end
18
28
 
19
- def before_files(f)
29
+ def module_definition
30
+ asset_paths= {}
31
+ asset_data= {}
32
+ definition= {}
33
+ required_files= []
34
+
35
+ libraries.each { |l|
36
+ f= l.file_for(content_type, language, variant)
37
+ required_files << project.relative_output_path_for(f)
38
+ }
39
+
40
+ files.each { |f|
41
+ required_files << project.relative_output_path_for(f)
42
+ }
43
+
44
+ assets.each { |asset|
45
+ next if project.source_files.include?(asset)
20
46
 
21
- if 0 != assets.length
22
- asset_references= []
23
- asset_map= []
24
- assets.each { |a|
25
- if can_embed_file?(a)
26
- next if @files.include?(a)
27
- content= a.minified_content(target.get_content_for_file(a))
28
- content= content.gsub("\\", "\\\\").gsub("\n", "\\n").gsub("\"", "\\\"").gsub("'", "\\\\'")
29
- asset_references << "\"#{target.alias_for_asset(a)}\": \"#{content}\""
30
- else
31
- asset_alias= target.alias_for_asset(a)
32
- asset_path= relative_path(a)
33
- next if asset_alias==asset_path
34
- asset_map << "'#{asset_alias}': '#{asset_path}'"
47
+ if RELEASE_VARIANT==variant
48
+ key= project.asset_aliases[asset]||asset.relative_path
49
+ if can_embed_as_content(asset)
50
+ asset_data[key]= escape_embeded_content(asset)
35
51
  end
36
- }
52
+ else
53
+ key= project.asset_aliases[asset]
54
+ asset_paths[key]= project.relative_output_path_for(asset) if key
55
+ end
56
+ }
57
+
58
+ definition[:asset_map]= asset_paths
59
+ if RELEASE_VARIANT==variant
60
+ definition[:assets]= asset_data
61
+ else
62
+ definition[:required]= required_files
63
+ end
64
+
65
+ MODULE_TEMPLATE.result binding
66
+ end
37
67
 
38
- f << <<-EOS
68
+ def build_release
69
+ File.open(output_path, "w") { |output|
70
+
71
+ output.puts notice_comment
39
72
 
40
- distil.module('#{target.name}', {
41
- folder: '',
42
- asset_map: {
43
- #{asset_map.join(",\n ")}
44
- },
45
- assets: {
46
- #{asset_references.join(",\n ")}
47
- }
48
- });
73
+ if (APPLICATION_TYPE==project.project_type)
74
+ output.puts File.read(BOOTSTRAP_SCRIPT)
75
+ output.puts FILE_SEPARATOR
76
+ end
49
77
 
78
+ # emit remote assets first
79
+ libraries.each { |l|
80
+ f= project.file_from_path(l.file_for(content_type, language, variant))
81
+ next if !f
82
+
83
+ content= f.rewrite_content_relative_to_path(nil)
84
+ next if !content || content.empty?
85
+
86
+ output.puts content
87
+ output.puts FILE_SEPARATOR
88
+ }
50
89
 
51
- EOS
52
- end
90
+ output.puts module_definition
53
91
 
54
- if global_export
55
- exports= [global_export, *additional_globals].join(", ")
56
- f.puts "(function(#{exports}){"
57
- end
58
- end
59
-
60
- def after_files(f)
61
- if global_export
62
- exports= ["window.#{global_export}=window.#{global_export}||{}", *additional_globals].join(", ")
63
- f.puts "})(#{exports});"
64
- end
92
+ if project.global_export
93
+ exports= [project.global_export, *project.additional_globals].join(", ")
94
+ output.puts "(function(#{exports}){"
95
+ end
65
96
 
66
- f.puts "\n\n/*#nocode-*/\n\n"
67
-
68
- f.puts "distil.kick();" if bootstrap
69
-
70
- end
71
-
72
- end
97
+ files.each { |f|
98
+ content= f.rewrite_content_relative_to_path(nil)
73
99
 
74
- class JavascriptMinifiedProduct < Product
75
- include Minified
76
- extension "js"
77
- end
100
+ next if !content || content.empty?
101
+
102
+ output.puts content
103
+ output.puts ""
104
+ output.puts FILE_SEPARATOR
105
+ }
106
+
107
+ if project.global_export
108
+ exports= ["window.#{project.global_export}=window.#{project.global_export}||{}", *project.additional_globals].join(", ")
109
+ output.puts "})(#{exports});"
110
+ end
111
+
112
+ output.puts "distil.moduleDidLoad('#{project.name}');"
113
+ }
114
+ end
78
115
 
79
- class JavascriptDebugProduct < JavascriptBaseProduct
80
- include Debug
81
- extension "js"
116
+ def build_debug
117
+ File.open(output_path, "w") { |output|
82
118
 
83
- option :global_export
84
- option :synchronous_load, false, :aliases=>['sync']
85
-
86
- def write_output
87
- return if up_to_date
88
- @up_to_date= true
89
-
90
- copy_bootstrap_script
91
-
92
- required_files= files.map { |file| "'#{relative_path(file)}'" }
93
- asset_map= []
94
- assets.each { |a|
95
- asset_alias= target.alias_for_asset(a)
96
- asset_path= relative_path(a)
97
- next if asset_alias==asset_path
98
- asset_map << "'#{asset_alias}': '#{asset_path}'"
99
- }
100
-
101
- external_files.each { |ext|
102
- next if !File.exist?(ext)
103
- required_files.unshift("'#{relative_path(ext)}'")
104
- }
105
-
106
- File.open(filename, "w") { |f|
107
- f.write(target.notice_text)
108
- f.write("#{bootstrap_source}\n\n") if bootstrap
119
+ output.puts notice_comment
109
120
 
110
- if global_export
111
- f.write("window.#{global_export}=window.#{global_export}||{};");
112
- f.write("\n\n");
121
+ if (APPLICATION_TYPE==project.project_type)
122
+ output.puts File.read(BOOTSTRAP_SCRIPT)
113
123
  end
114
124
 
115
- files.each { |file|
116
- f.write("/*jsl:import #{relative_path(file)}*/\n")
117
- }
118
-
119
- if (APP_TYPE==target.target_type && synchronous_load)
120
- f.puts "distil.sync= #{Kernel::Boolean(synchronous_load)};"
125
+ if project.global_export
126
+ output.puts
127
+ output.puts "window.#{project.global_export}=window.#{project.global_export}||{};"
128
+ output.puts
121
129
  end
130
+
131
+ libraries.each { |l|
132
+ path= project.relative_output_path_for(l.file_for(content_type, language, variant))
133
+ next if !path
134
+ output.puts "/*jsl:import #{path}*/"
135
+ }
122
136
 
123
- f.write(<<-EOS)
137
+ files.each { |f|
138
+ path= project.relative_output_path_for(f)
139
+ next if !path
140
+ output.puts "/*jsl:import #{path}*/"
141
+ }
124
142
 
125
- distil.module('#{target.name}', {
126
- folder: '',
127
- required: [#{required_files.join(", ")}],
128
- asset_map: {
129
- #{asset_map.join(",\n ")}
130
- }
131
- });
132
- EOS
143
+ output.puts module_definition
144
+
133
145
  }
134
-
135
146
  end
136
-
137
- end
138
147
 
139
- end
148
+ end
149
+
150
+ end