distil 0.13.6 → 0.14.0.b

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 (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