distil 0.10.4 → 0.11.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 (63) hide show
  1. data/Rakefile +2 -1
  2. data/VERSION +1 -1
  3. data/assets/distil.js +359 -0
  4. data/bin/distil +33 -10
  5. data/distil.gemspec +35 -24
  6. data/lib/distil/configurable/file-set.rb +86 -0
  7. data/lib/distil/configurable/interpolated.rb +36 -0
  8. data/lib/distil/configurable/output-path.rb +25 -0
  9. data/lib/distil/configurable/project-path.rb +25 -0
  10. data/lib/distil/configurable.rb +164 -0
  11. data/lib/distil/error-reporter.rb +63 -0
  12. data/lib/distil/product/concatenated.rb +85 -0
  13. data/lib/distil/product/css-product.rb +37 -0
  14. data/lib/distil/product/debug.rb +34 -0
  15. data/lib/distil/product/javascript-base-product.rb +35 -0
  16. data/lib/distil/product/javascript-doc-product.rb +61 -0
  17. data/lib/distil/product/javascript-product.rb +131 -0
  18. data/lib/distil/product/minified.rb +32 -0
  19. data/lib/distil/product.rb +97 -0
  20. data/lib/distil/project/distil-project.rb +99 -0
  21. data/lib/distil/project/external-project.rb +53 -0
  22. data/lib/distil/project.rb +78 -0
  23. data/lib/distil/source-file/css-file.rb +14 -0
  24. data/lib/distil/source-file/html-file.rb +14 -0
  25. data/lib/distil/source-file/javascript-file.rb +17 -0
  26. data/lib/distil/source-file/json-file.rb +16 -0
  27. data/lib/distil/source-file.rb +172 -0
  28. data/lib/distil/target.rb +235 -0
  29. data/lib/distil/task/css-dependency-task.rb +64 -0
  30. data/lib/distil/task/jsl-dependency-task.rb +49 -0
  31. data/lib/distil/task/nib-task.rb +72 -0
  32. data/lib/distil/task/validate-js-task.rb +75 -0
  33. data/lib/distil/task.rb +50 -0
  34. data/lib/distil.rb +72 -0
  35. data/lib/jsl.conf +4 -0
  36. data/vendor/jsl-0.3.0/src/Makefile.ref +16 -6
  37. data/vendor/jsl-0.3.0/src/config.mk +32 -2
  38. data/vendor/jsl-0.3.0/src/fdlibm/Makefile.ref +1 -2
  39. data/vendor/jsl-0.3.0/src/jsl.c +124 -13
  40. data/vendor/jsl-0.3.0/src/rules.mk +2 -1
  41. metadata +49 -28
  42. data/lib/bootstrap-template.js +0 -58
  43. data/lib/configurable.rb +0 -161
  44. data/lib/file-set.rb +0 -49
  45. data/lib/file-types/css-file.rb +0 -12
  46. data/lib/file-types/html-file.rb +0 -11
  47. data/lib/file-types/javascript-file.rb +0 -24
  48. data/lib/file-types/json-file.rb +0 -17
  49. data/lib/filter.rb +0 -41
  50. data/lib/filters/css-filter.rb +0 -58
  51. data/lib/filters/file-reference-filter.rb +0 -30
  52. data/lib/filters/jsl-dependency-filter.rb +0 -44
  53. data/lib/project.rb +0 -174
  54. data/lib/source-file.rb +0 -197
  55. data/lib/target.rb +0 -102
  56. data/lib/task.rb +0 -212
  57. data/lib/tasks/copy-task.rb +0 -17
  58. data/lib/tasks/css-task.rb +0 -12
  59. data/lib/tasks/javascript-task.rb +0 -206
  60. data/lib/tasks/multiple-output-task.rb +0 -140
  61. data/lib/tasks/output-task.rb +0 -76
  62. data/lib/tasks/single-output-task.rb +0 -104
  63. data/lib/tasks/test-task.rb +0 -280
@@ -0,0 +1,164 @@
1
+ module Kernel
2
+
3
+ def Boolean(string)
4
+ return true if string == true || string =~ /^true$/i
5
+ return false if string == false || string.nil? || string =~ /^false$/i
6
+ raise ArgumentError.new("invalid value for Boolean: \"#{string}\"")
7
+ end
8
+
9
+ end
10
+
11
+ class ValidationError < StandardError
12
+ end
13
+
14
+
15
+ class Configurable
16
+ attr_reader :options
17
+
18
+ @@options= {}
19
+
20
+ def get_option(name)
21
+ return nil if !@options.respond_to?(name)
22
+ value=@options[name]
23
+ value.respond_to?(:value_of) ? value.value_of(self) : value
24
+ end
25
+
26
+ def get_options(settings=nil, parent=nil)
27
+ keys= @@options.keys
28
+ values= @@options.map { |k,v| convert_type(v[:type], v[:value]) }
29
+
30
+ s= Struct.new(*keys).new(*values)
31
+ return s if !settings
32
+
33
+ setting_keys= settings.keys.map { |key| key.to_s }
34
+
35
+ @@options.each { |key, value|
36
+
37
+ intersect= value[:aliases] & setting_keys
38
+ next if !parent && intersect.empty?
39
+
40
+ if (intersect.empty?)
41
+ s[key]= parent[key]
42
+ next
43
+ end
44
+
45
+ if (intersect.length>1)
46
+ raise ArgumentError, "Multiple variants for #{key.to_s} defined: #{intersect.join(", ")}"
47
+ end
48
+
49
+ setting_key= intersect[0]
50
+ setting_value= settings[setting_key]
51
+ settings.delete(setting_key)
52
+
53
+ # decide if any type conversions are needed...
54
+ setting_value= convert_type(value[:type], setting_value)
55
+
56
+ if (value.has_key?(:valid_values) && !value[:valid_values].include?(setting_value))
57
+ raise ValidationError, "Invalid value for '#{setting_key}': #{setting_value}"
58
+ end
59
+
60
+ s[key]= setting_value
61
+
62
+ }
63
+
64
+ s
65
+ end
66
+
67
+ # option name, [type], [default], [options]
68
+ def self.option(name, *rest)
69
+
70
+ name_string= name.to_s
71
+
72
+ info= {
73
+ :aliases=>[name_string, name_string.gsub('_', '-'), name_string.gsub('_', ' ')].uniq
74
+ }
75
+
76
+ arg= rest.shift
77
+
78
+ if (arg.is_a?(Class))
79
+ info[:type]= arg
80
+ info[:value]= nil
81
+ arg= rest.shift
82
+ end
83
+
84
+ if (!arg.nil? && !arg.is_a?(Hash))
85
+ info[:value]= arg
86
+ info[:type]= arg.class if !info.has_key?(:type)
87
+ arg= rest.shift
88
+ end
89
+
90
+ # handle named arguments
91
+ if (arg.is_a?(Hash))
92
+ if arg.has_key?(:aliases)
93
+ info[:aliases].concat(arg[:aliases]).uniq!
94
+ arg.delete(:aliases)
95
+ end
96
+ info.merge!(arg)
97
+ end
98
+
99
+ if @@options.has_key?(name)
100
+ orig= @@options[name]
101
+ if orig.has_key?(:type) && info.has_key?(:type) && info[:type]!=orig[:type]
102
+ raise ArgumentError, "Redefinition of option #{self}##{name} changes type"
103
+ end
104
+ if orig.has_key?(:value) && !info[:value].nil? && info[:value]!=orig[:value]
105
+ raise ArgumentError, "Redefinition of option #{name} changes value"
106
+ end
107
+ orig[:type]||=info[:type]
108
+ orig[:value]||=info[:value]
109
+ orig[:aliases].concat(info[:aliases]).uniq!
110
+ else
111
+ @@options[name]= info
112
+ end
113
+
114
+ self.send :define_method, name do
115
+ value=@options[name]
116
+ value.respond_to?(:value_of) ? value.value_of(self) : value
117
+ end
118
+
119
+ self.send :define_method, "#{name}=" do |value|
120
+ @options[name]= convert_type(@@options[name][:type], value)
121
+ end
122
+
123
+ # self.send :protected, "#{name}=".to_s
124
+
125
+ end
126
+
127
+ def initialize(options={}, parent=nil)
128
+ if (parent.is_a?(Configurable))
129
+ parent_options= parent.options
130
+ end
131
+ @options= get_options(options, parent_options)
132
+ @extras= options
133
+ end
134
+
135
+ private
136
+
137
+ def convert_type(type, value)
138
+ case
139
+ when FalseClass==type || TrueClass==type
140
+ Boolean(value)
141
+ when Array==type
142
+ value.is_a?(String) ? value.split(/\s*,\s*/) : value
143
+ when Fixnum==type
144
+ value.to_i
145
+ when nil==type || NilClass==type
146
+ value
147
+ when String==type
148
+ value ? value.to_s : nil;
149
+ when value.nil?
150
+ value
151
+ else
152
+ if type.respond_to?(:from_options)
153
+ type.from_options(value, self)
154
+ else
155
+ type.new(value)
156
+ end
157
+ end
158
+ end
159
+
160
+ end
161
+
162
+ Dir.glob("#{File.dirname(__FILE__)}/configurable/*.rb") { |file|
163
+ require file
164
+ }
@@ -0,0 +1,63 @@
1
+ module Distil
2
+ module ErrorReporter
3
+
4
+ @@warning_count=0
5
+ @@error_count=0
6
+ @@ignore_warnings= false
7
+
8
+ def ignore_warnings
9
+ @@ignore_warnings
10
+ end
11
+
12
+ def ignore_warnings=(ignore)
13
+ @@ignore_warnings=ignore
14
+ end
15
+
16
+ def self.error(message, file=nil, line_number=nil)
17
+ @@error_count+=1
18
+ if (file && line_number)
19
+ printf("%s:%d: error: %s\n", file, line_number, message)
20
+ else
21
+ printf("error: %s\n", message)
22
+ end
23
+ end
24
+
25
+ def error(message, file=nil, line_number=nil)
26
+ @@error_count+=1
27
+ if (file && line_number)
28
+ printf("%s:%d: error: %s\n", file, line_number, message)
29
+ else
30
+ printf("error: %s\n", message)
31
+ end
32
+ end
33
+
34
+ def self.warning(message, file=nil, line_number=nil)
35
+ @@warning_count+=1
36
+ return if (ignore_warnings)
37
+ if (file && line_number)
38
+ printf("%s:%d: warning: %s\n", file, line_number, message)
39
+ else
40
+ printf("warning: %s\n", message)
41
+ end
42
+ end
43
+
44
+ def warning(message, file=nil, line_number=nil)
45
+ @@warning_count+=1
46
+ return if (ignore_warnings)
47
+ if (file && line_number)
48
+ printf("%s:%d: warning: %s\n", file, line_number, message)
49
+ else
50
+ printf("warning: %s\n", message)
51
+ end
52
+ end
53
+
54
+ def report
55
+ puts "\n" if (@@error_count>0 || @@warning_count>0)
56
+ puts "#{@@error_count} error(s), #{@@warning_count} warning(s)#{ignore_warnings ? " ignored" : ""}"
57
+ end
58
+
59
+ end
60
+
61
+ end
62
+
63
+
@@ -0,0 +1,85 @@
1
+ module Distil
2
+
3
+ # Mix in for concatenating products
4
+ module Concatenated
5
+
6
+ # files -> an enumerable collection of SourceFiles
7
+ # join_string -> a string to use to join the files together
8
+ # target -> the container of the files
9
+
10
+ def before_files(f)
11
+ end
12
+
13
+ def after_files(f)
14
+ end
15
+
16
+ def before_externals(f)
17
+ end
18
+
19
+ def after_externals(f)
20
+ end
21
+
22
+ def before_file(f, file)
23
+ end
24
+
25
+ def after_file(f, file)
26
+ end
27
+
28
+ def filename
29
+ concatenated_name
30
+ end
31
+
32
+ def external_files
33
+ return @external_files if @external_files
34
+ @external_files= []
35
+
36
+ target.project.external_projects.each { |ext|
37
+ next if STRONG_LINKAGE!=ext.linkage
38
+
39
+ @external_files << ext.product_name(:concatenated, File.extname(filename)[1..-1])
40
+ }
41
+ @external_files
42
+ end
43
+
44
+ def write_output
45
+ return if up_to_date
46
+ @up_to_date= true
47
+
48
+ File.open(filename, "w") { |f|
49
+ f.write(target.notice_text)
50
+
51
+ f.write("\n\n")
52
+ before_externals(f)
53
+ f.write("\n\n")
54
+
55
+ external_files.each { |ext|
56
+ next if !File.exist?(ext)
57
+ f.write(join_string)
58
+ f.write(target.get_content_for_file(ext))
59
+ }
60
+
61
+ f.write("\n\n")
62
+ after_externals(f)
63
+ f.write("\n\n")
64
+
65
+ f.write("\n\n")
66
+ before_files(f)
67
+ f.write("\n\n")
68
+
69
+ files.each { |file|
70
+ f.write(join_string)
71
+ before_file(f, file)
72
+ f.write(target.get_content_for_file(file))
73
+ after_file(f, file)
74
+ }
75
+
76
+ f.write("\n\n")
77
+ after_files(f)
78
+ f.write("\n\n");
79
+
80
+ }
81
+ end
82
+
83
+ end
84
+
85
+ end
@@ -0,0 +1,37 @@
1
+ module Distil
2
+
3
+ class CssProduct < Product
4
+ include Concatenated
5
+ extension "css"
6
+ end
7
+
8
+ class CssMinifiedProduct < Product
9
+ include Minified
10
+ extension "css"
11
+ end
12
+
13
+ class CssDebugProduct < Product
14
+ include Debug
15
+ extension "css"
16
+
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)
23
+
24
+ external_files.each { |ext|
25
+ next if !File.exist?(ext)
26
+ f.write("@import url(\"#{relative_path(ext)});\n")
27
+ }
28
+
29
+ files.each { |file|
30
+ f.write("@import url(\"#{relative_path(file)}\");\n")
31
+ }
32
+ }
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,34 @@
1
+ module Distil
2
+
3
+ # Mix in for concatenating products
4
+ module Debug
5
+
6
+ # files -> an enumerable collection of SourceFiles
7
+ # join_string -> a string to use to join the files together
8
+ # target -> the container of the files
9
+
10
+ def before_files(f)
11
+ end
12
+
13
+ def after_files(f)
14
+ end
15
+
16
+ def filename
17
+ debug_name
18
+ end
19
+
20
+ def external_files
21
+ return @external_files if @external_files
22
+ @external_files= []
23
+
24
+ target.project.external_projects.each { |ext|
25
+ next if STRONG_LINKAGE!=ext.linkage
26
+
27
+ @external_files << ext.product_name(:debug, File.extname(filename)[1..-1])
28
+ }
29
+ @external_files
30
+ end
31
+
32
+ end
33
+
34
+ end
@@ -0,0 +1,35 @@
1
+ module Distil
2
+
3
+ class JavascriptBaseProduct < Product
4
+ option :bootstrap_script, "#{ASSETS_DIR}/distil.js"
5
+ option :bootstrap
6
+
7
+ def initialize(settings, target)
8
+ super(settings, target)
9
+
10
+ @join_string=<<-eos
11
+
12
+ /*jsl:ignore*/;/*jsl:end*/
13
+
14
+ eos
15
+
16
+ if bootstrap.nil?
17
+ self.bootstrap= (APP_TYPE==target.target_type)
18
+ end
19
+ end
20
+
21
+ def can_embed_file?(file)
22
+ ["html", "js"].include?(file.content_type)
23
+ end
24
+
25
+ def bootstrap_source
26
+ @bootstrap_source||=File.read(bootstrap_script).strip
27
+ end
28
+
29
+ def copy_bootstrap_script
30
+ FileUtils.cp bootstrap_script, target.project.output_folder if !bootstrap
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,61 @@
1
+ module Distil
2
+
3
+ JSDOC_COMMAND= "#{VENDOR_DIR}/jsdoc-toolkit/jsrun.sh"
4
+
5
+ class JavascriptDocProduct < Product
6
+
7
+ option :jsdoc_conf, "#{LIB_DIR}/jsdoc.conf"
8
+ option :jsdoc_template, "#{VENDOR_DIR}/jsdoc-extras/templates/coherent"
9
+ option :jsdoc_plugins, "#{VENDOR_DIR}/jsdoc-extras/plugins"
10
+ option :doc_folder, Interpolated, "$(path)/doc"
11
+
12
+ extension "js"
13
+
14
+ def filename
15
+ File.join(doc_folder, 'index.html')
16
+ end
17
+
18
+ def write_output
19
+ return if up_to_date
20
+ @up_to_date= true
21
+
22
+ return if (!File.exists?(JSDOC_COMMAND))
23
+
24
+ tmp= Tempfile.new("jsdoc.conf")
25
+
26
+ template= File.read(jsdoc_conf)
27
+ doc_files= []
28
+
29
+ files.each { |f|
30
+ next if !handles_file?(f)
31
+ p= f.file_path || f.to_s
32
+ doc_files << "\"#{p}\""
33
+ }
34
+
35
+ conf= replace_tokens(template, {
36
+ "DOC_FILES"=>doc_files.join(",\n"),
37
+ "DOC_OUTPUT_DIR"=>doc_folder,
38
+ "DOC_TEMPLATE_DIR"=>jsdoc_template,
39
+ "DOC_PLUGINS_DIR"=>jsdoc_plugins
40
+ })
41
+
42
+ tmp << conf
43
+ tmp.close()
44
+
45
+ command= "#{JSDOC_COMMAND} -c=#{tmp.path}"
46
+
47
+ stdin, stdout, stderr= Open3.popen3(command)
48
+ stdin.close
49
+ output= stdout.read
50
+ errors= stderr.read
51
+
52
+ tmp.delete
53
+
54
+ puts errors
55
+ puts output
56
+
57
+ end
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,131 @@
1
+ module Distil
2
+
3
+ class JavascriptProduct < JavascriptBaseProduct
4
+ include Concatenated
5
+
6
+ extension "js"
7
+
8
+ option :global_export, :aliases=>['export']
9
+ option :additional_globals, [], :aliases=>['globals']
10
+
11
+ def initialize(settings, target)
12
+ super(settings, target)
13
+
14
+ @options.global_export=target.name if true==global_export
15
+ end
16
+
17
+ def before_externals(f)
18
+ f.puts("/*#nocode+*/")
19
+ f.puts(bootstrap_source) if bootstrap
20
+ end
21
+
22
+ def after_externals(f)
23
+ end
24
+
25
+ def before_files(f)
26
+
27
+ if 0 != assets.length
28
+ asset_references= []
29
+ asset_map= []
30
+ assets.each { |a|
31
+ if can_embed_file?(a)
32
+ content= target.get_content_for_file(a)
33
+ content= content.gsub("\\", "\\\\").gsub("\n", "\\n").gsub("\"", "\\\"").gsub("'", "\\\\'")
34
+ asset_references << "\"#{target.alias_for_asset(a)}\": \"#{content}\""
35
+ else
36
+ asset_alias= target.alias_for_asset(a)
37
+ asset_path= relative_path(a)
38
+ next if asset_alias==asset_path
39
+ asset_map << "'#{asset_alias}': '#{asset_path}'"
40
+ end
41
+ }
42
+
43
+ f << <<-EOS
44
+
45
+ distil.module('#{target.name}', {
46
+ folder: '',
47
+ asset_map: {
48
+ #{asset_map.join(",\n ")}
49
+ },
50
+ assets: {
51
+ #{asset_references.join(",\n ")}
52
+ }
53
+ });
54
+
55
+
56
+ EOS
57
+ end
58
+
59
+ if global_export
60
+ exports= [global_export, *additional_globals].join(", ")
61
+ f.puts "(function(#{exports}){"
62
+ end
63
+ end
64
+
65
+ def after_files(f)
66
+ if global_export
67
+ exports= ["window.#{global_export}={}", *additional_globals].join(", ")
68
+ f.puts "})(#{exports});"
69
+ end
70
+
71
+ f.puts "\n\n/*#nocode-*/\n\n"
72
+
73
+ f.puts "distil.kick();" if bootstrap
74
+
75
+ end
76
+
77
+ end
78
+
79
+ class JavascriptMinifiedProduct < Product
80
+ include Minified
81
+ extension "js"
82
+ end
83
+
84
+ class JavascriptDebugProduct < JavascriptBaseProduct
85
+ include Debug
86
+ extension "js"
87
+
88
+ def write_output
89
+ return if up_to_date
90
+ @up_to_date= true
91
+
92
+ copy_bootstrap_script
93
+
94
+ required_files= files.map { |file| "'#{relative_path(file)}'" }
95
+ asset_map= []
96
+ assets.each { |a|
97
+ asset_alias= target.alias_for_asset(a)
98
+ asset_path= relative_path(a)
99
+ next if asset_alias==asset_path
100
+ asset_map << "'#{asset_alias}': '#{asset_path}'"
101
+ }
102
+
103
+ external_files.each { |ext|
104
+ next if !File.exist?(ext)
105
+ required_files.unshift("'#{relative_path(ext)}'")
106
+ }
107
+
108
+ File.open(filename, "w") { |f|
109
+ f.write(target.notice_text)
110
+ f.write("#{bootstrap_source}\n\n") if bootstrap
111
+ files.each { |file|
112
+ f.write("/*jsl:import #{relative_path(file)}*/\n")
113
+ }
114
+ f.write(<<-EOS)
115
+ //distil.debug= true;
116
+
117
+ distil.module('#{target.name}', {
118
+ folder: '',
119
+ required: [#{required_files.join(", ")}],
120
+ asset_map: {
121
+ #{asset_map.join(",\n ")}
122
+ }
123
+ });
124
+ EOS
125
+ }
126
+
127
+ end
128
+
129
+ end
130
+
131
+ end
@@ -0,0 +1,32 @@
1
+ module Distil
2
+
3
+ COMPRESSOR= File.expand_path("#{VENDOR_DIR}/yuicompressor-2.4.2.jar")
4
+
5
+ module Minified
6
+
7
+ def filename
8
+ minified_name
9
+ end
10
+
11
+ def external_files
12
+ []
13
+ end
14
+
15
+ def write_output
16
+ return if up_to_date
17
+ @up_to_date= true
18
+
19
+ # Run the Y!UI Compressor
20
+ system "java -jar #{COMPRESSOR} #{concatenated_name} -o #{filename}"
21
+
22
+ if 'css'==extension
23
+ buffer= File.read(filename)
24
+ File.open(filename, "w") { |f|
25
+ f.write(buffer.gsub(/\}/,"}\n").gsub(/.*@import url\(\".*\"\);/,''))
26
+ }
27
+ end
28
+ end
29
+
30
+ end
31
+
32
+ end