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,97 @@
1
+ module Distil
2
+
3
+ class Product < Configurable
4
+ option :concatenated_name, OutputPath, "$(name)-uncompressed.$(extension)", :aliases=>['concatenated']
5
+ option :debug_name, OutputPath, "$(name)-debug.$(extension)", :aliases=>['debug']
6
+ option :minified_name, OutputPath, "$(name).$(extension)", :aliases=>['minified']
7
+ option :compressed_name, OutputPath, "$(name).$(extension).gz", :aliases=>['compressed']
8
+
9
+ option :force, false
10
+
11
+ attr_accessor :assets, :target, :join_string
12
+ class_attr :extension
13
+
14
+ def initialize(settings, target)
15
+ @target= target
16
+ @files= []
17
+ @assets= Set.new
18
+ super(settings, target)
19
+ end
20
+
21
+ def can_embed_file?(file)
22
+ false
23
+ end
24
+
25
+ def handles_file?(file)
26
+ [extension].include?(file.extension)
27
+ end
28
+
29
+ def files
30
+ @files
31
+ end
32
+
33
+ def files=(fileset)
34
+ fileset.each { |f|
35
+ next if !handles_file?(f)
36
+ @files << f
37
+ @assets.merge(f.assets)
38
+ }
39
+ end
40
+
41
+ def up_to_date
42
+ return @up_to_date if !@up_to_date.nil?
43
+ return false if force
44
+
45
+ return @up_to_date=false if !File.exists?(filename)
46
+
47
+ output_modified= File.stat(filename).mtime
48
+ max_asset_modified= File.stat(target.project.project_file).mtime
49
+
50
+ assets.each { |f|
51
+ max_asset_modified= f.last_modified if f.last_modified > max_asset_modified
52
+ }
53
+
54
+ return @up_to_date=false if (output_modified < max_asset_modified)
55
+
56
+ external_files.each { |f|
57
+ next if !File.exist?(f)
58
+ last_modified= File.stat(f).mtime
59
+ max_asset_modified= last_modified if last_modified > max_asset_modified
60
+ }
61
+
62
+ return @up_to_date=false if (output_modified < max_asset_modified)
63
+
64
+ @up_to_date= true
65
+ end
66
+
67
+ def filename
68
+ raise NotImplementedError.new("This product does not implement the filename method.")
69
+ end
70
+
71
+ def write_output
72
+ raise NotImplementedError.new("No write_output method has been defined for this product.")
73
+ end
74
+
75
+ def relative_path(file)
76
+ file=SourceFile.from_path(file) if file.is_a?(String)
77
+
78
+ file_path= file.full_path
79
+ output_folder= target.project.output_folder
80
+ source_folder= target.project.source_folder
81
+
82
+ path=file.relative_to_folder(source_folder) if 0==file_path.index(source_folder)
83
+ path=file.relative_to_folder(output_folder) if 0==file_path.index(output_folder)
84
+ path
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+
91
+ require 'distil/product/concatenated'
92
+ require 'distil/product/debug'
93
+ require 'distil/product/minified'
94
+ require 'distil/product/css-product'
95
+ require 'distil/product/javascript-base-product'
96
+ require 'distil/product/javascript-product'
97
+ require 'distil/product/javascript-doc-product'
@@ -0,0 +1,99 @@
1
+ module Distil
2
+
3
+ class DistilProject < Project
4
+
5
+ attr_reader :project_file
6
+
7
+ option :ignore_warnings, false
8
+
9
+ option :external_projects, [], :aliases=>['external']
10
+ option :distileries, Array, :aliases=>['distilleries', 'distilery', 'distillery']
11
+
12
+
13
+ def initialize(project_file, settings={}, parent=nil)
14
+ @project_file= File.expand_path(project_file)
15
+ @projects_by_name={}
16
+
17
+ project_info= YAML.load_file(@project_file)
18
+ project_info.merge!(settings)
19
+ project_info["path"]= File.dirname(@project_file)
20
+
21
+ begin
22
+ super(project_info, parent)
23
+ rescue ValidationError
24
+ $stderr.print "#{APP_NAME}: #{project_file}: #{$!}\n"
25
+ exit 1
26
+ end
27
+
28
+ load_external_projects
29
+ end
30
+
31
+ def targets
32
+ @targets if @targets
33
+
34
+ @targets= []
35
+ target_list= @extras['targets']
36
+
37
+ if !target_list
38
+ @targets << Target.new(@extras.clone, self)
39
+ return @targets
40
+ end
41
+
42
+ @targets= target_list.map { |target|
43
+ Target.new(target, self)
44
+ }
45
+ end
46
+
47
+ def load_external_projects
48
+ return if !external_projects
49
+
50
+ self.external_projects= external_projects.map { |config|
51
+ project= Project.from_config(config, self)
52
+ next if !project
53
+ @projects_by_name[project.name]= project
54
+ }
55
+ end
56
+
57
+ def external_project_with_name(name)
58
+ @projects_by_name[name]
59
+ end
60
+
61
+ def build
62
+ FileUtils.mkdir_p(output_folder)
63
+ load_distileries
64
+ build_external_projects
65
+ build_targets
66
+ end
67
+
68
+ def load_distileries
69
+ return if distileries.nil?
70
+
71
+ distileries.each { |d|
72
+ if (File.exists?(d))
73
+ require d
74
+ next
75
+ end
76
+ path= Gem.required_location(d, 'distilery.rb')
77
+ if (path.nil?)
78
+ puts "Missing distilery: #{d}"
79
+ end
80
+ next if path.nil?
81
+ require path
82
+ }
83
+ end
84
+
85
+ def build_external_projects
86
+ external_projects.each { |project|
87
+ project.build
88
+ }
89
+ end
90
+
91
+ def build_targets
92
+ targets.each { |target|
93
+ target.build
94
+ }
95
+ report
96
+ end
97
+ end
98
+
99
+ end
@@ -0,0 +1,53 @@
1
+ module Distil
2
+
3
+ class ExternalProject < Project
4
+
5
+ option :name, String
6
+ option :repository
7
+ option :build_command, String, :aliases=>['build']
8
+ option :linkage, WEAK_LINKAGE, :valid_values=> [WEAK_LINKAGE, STRONG_LINKAGE, LAZY_LINKAGE]
9
+
10
+ option :import_name, OutputPath, "$(name)-debug.$(extension)", :aliases=>['import']
11
+ option :concatenated_name, OutputPath, "$(name)-uncompressed.$(extension)", :aliases=>['concatenated']
12
+ option :debug_name, OutputPath, "$(name)-debug.$(extension)", :aliases=>['debug']
13
+ option :minified_name, OutputPath, "$(name).$(extension)", :aliases=>['minified']
14
+ option :compressed_name, OutputPath, "$(name).$(extension).gz", :aliases=>['compressed']
15
+
16
+ def initialize(config, parent=nil)
17
+ if !config.has_key?("source_folder")
18
+ config["source_folder"]= "build/$(mode)"
19
+ end
20
+ super(config, parent)
21
+
22
+ @options.output_folder= File.join(parent.output_folder, name)
23
+ end
24
+
25
+ def product_name(product_type, extension)
26
+ info= Struct.new(:extension).new(extension)
27
+ name= self.send("#{product_type.to_s}_name")
28
+ Interpolated.value_of(name, info)
29
+ end
30
+
31
+ def build
32
+ wd= Dir.getwd
33
+ Dir.chdir(path)
34
+ system build_command
35
+ Dir.chdir(wd)
36
+
37
+ # external projects aren't included in the output when weak linked,
38
+ # they are just expected to be there, somehow. Like magic.
39
+ return if WEAK_LINKAGE==linkage
40
+
41
+ FileUtils.rm_r(output_folder) if File.directory?(output_folder)
42
+ FileUtils.unlink(output_folder) if File.symlink?(output_folder)
43
+
44
+ if DEBUG_MODE==mode
45
+ FileUtils.symlink(File.expand_path(source_folder), output_folder)
46
+ else
47
+ FileUtils.cp_r(File.expand_path(source_folder), output_folder)
48
+ end
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -0,0 +1,78 @@
1
+ module Distil
2
+
3
+ class Project < Configurable
4
+
5
+ include ErrorReporter
6
+
7
+ option :output_folder, ProjectPath, "build/$(mode)", :aliases=>['output']
8
+ option :source_folder, ProjectPath, ""
9
+
10
+ option :path, String
11
+ option :mode, DEBUG_MODE, :valid_values=>[DEBUG_MODE, RELEASE_MODE]
12
+ option :force
13
+
14
+ def build
15
+ end
16
+
17
+ def self.from_config(config, parent=nil)
18
+
19
+ if config.is_a?(String)
20
+ string= config
21
+ config= { "name" => File.basename(config, ".*") }
22
+ full_path= File.expand_path(string)
23
+ if File.exist?(full_path) && File.file?(full_path)
24
+ config["path"]= File.dirname(full_path)
25
+ else
26
+ config["path"]= full_path
27
+ end
28
+ end
29
+
30
+ config["mode"]||= parent.mode if parent
31
+
32
+ path= config["path"]
33
+ if !path
34
+ ErrorReporter.error "No path for project: #{config["name"]}"
35
+ return nil
36
+ end
37
+
38
+ if !File.directory?(path)
39
+ ErrorReporter.error "Path is not valid for project: #{config["name"]}"
40
+ return nil
41
+ end
42
+
43
+ basename= File.basename(path)
44
+
45
+ case
46
+ when exist?(path, "#{basename}.jsproj")
47
+ project_file= File.join(path, "#{basename}.jsproj")
48
+ project_info= YAML.load_file(project_file)
49
+ project_info.merge!(config)
50
+ project_info["path"]= path
51
+ project= ExternalProject.new(project_info, parent)
52
+ if parent
53
+ project.build_command ||= "distil --mode=#{parent.mode} --force=#{parent.force}"
54
+ else
55
+ project.build_command ||= "distil"
56
+ end
57
+ when exist?(path, "Makefile") || exist?(path, "makefile")
58
+ project= ExternalProject.new(config, parent)
59
+ project.build_command ||= "make"
60
+ when exist?(path, "Rakefile") || exist?(path, "rakefile")
61
+ project= ExternalProject.new(config, parent)
62
+ project.build_command ||= "rake"
63
+ when exist?(path, "Jakefile") || exist?(path, "jakefile")
64
+ project= ExternalProject.new(config, parent)
65
+ project.build_command ||= "jake"
66
+ else
67
+ ErrorReporter.error "Could not determine type for project: #{config["name"]}"
68
+ end
69
+ return project
70
+
71
+ end
72
+
73
+ end
74
+
75
+ end
76
+
77
+ require 'distil/project/external-project'
78
+ require 'distil/project/distil-project'
@@ -0,0 +1,14 @@
1
+ module Distil
2
+
3
+ class CssFile < SourceFile
4
+
5
+ extension "css"
6
+ content_type "css"
7
+
8
+ def minified_content(source)
9
+ super(source).gsub(/\}/,"}\n").gsub(/.*@import url\(\".*\"\);/,'')
10
+ end
11
+
12
+ end
13
+
14
+ end
@@ -0,0 +1,14 @@
1
+ module Distil
2
+
3
+ class HtmlFile < SourceFile
4
+
5
+ extension "html"
6
+ content_type "html"
7
+
8
+ def minified_content(source)
9
+ source.gsub(/>\s+</, "><")
10
+ end
11
+
12
+ end
13
+
14
+ end
@@ -0,0 +1,17 @@
1
+ module Distil
2
+
3
+ class JavascriptFile < SourceFile
4
+ extension 'js'
5
+ content_type 'js'
6
+
7
+ def can_embed_as_content(file)
8
+ [".css", ".html", ".json"].include?(file.extension)
9
+ end
10
+
11
+ def escape_embeded_content(content)
12
+ content.gsub("\\", "\\\\").gsub("\n", "\\n").gsub("\"", "\\\"").gsub("'", "\\\\'")
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,16 @@
1
+ require "distil/source-file/javascript-file"
2
+
3
+ module Distil
4
+
5
+ class JsonFile < JavascriptFile
6
+
7
+ extension 'json'
8
+ content_type 'js'
9
+
10
+ def minified_content(source)
11
+ super("(#{source})")[1..-3]
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,172 @@
1
+ require 'fileutils'
2
+
3
+ $compressor = File.expand_path("#{VENDOR_DIR}/yuicompressor-2.4.2.jar")
4
+
5
+ module Distil
6
+
7
+ class SourceFile
8
+ attr_accessor :parent_folder, :full_path
9
+ class_attr :extension
10
+ class_attr :content_type
11
+
12
+ include ErrorReporter
13
+
14
+ def initialize(filepath)
15
+ @full_path= File.expand_path(filepath)
16
+
17
+ @parent_folder= File.dirname(@full_path)
18
+ @dependencies= []
19
+ @assets= []
20
+
21
+ @@file_cache[@full_path]= self
22
+ end
23
+
24
+ def can_embed_as_content(file)
25
+ false
26
+ end
27
+
28
+ def warning(message, line=nil)
29
+ super(message, self, line)
30
+ end
31
+
32
+ def error(message, line=nil)
33
+ super(message, self, line)
34
+ end
35
+
36
+ @@file_types= []
37
+ def self.inherited(subclass)
38
+ @@file_types << subclass
39
+ end
40
+
41
+ def self.file_types
42
+ @@file_types
43
+ end
44
+
45
+ @@file_cache= Hash.new
46
+ def self.from_path(filepath)
47
+ full_path= File.expand_path(filepath)
48
+ file= @@file_cache[full_path]
49
+ return file if file
50
+
51
+ extension= File.extname(filepath)[1..-1]
52
+
53
+ @@file_types.each { |handler|
54
+ next if (handler.extension != extension)
55
+
56
+ return handler.new(filepath)
57
+ }
58
+
59
+ return SourceFile.new(filepath)
60
+ end
61
+
62
+ def to_s
63
+ @full_path
64
+ end
65
+
66
+ def to_str
67
+ @full_path
68
+ end
69
+
70
+ def basename(suffix=extension)
71
+ File.basename(@full_path, suffix)
72
+ end
73
+
74
+ def file_path
75
+ @file_path
76
+ end
77
+
78
+ def file_path=(path)
79
+ @file_path=path
80
+ end
81
+
82
+ def load_content
83
+ File.read(@full_path)
84
+ end
85
+
86
+ def escape_embeded_content(content)
87
+ content
88
+ end
89
+
90
+ def content
91
+ @content ||= load_content
92
+ end
93
+
94
+ def last_modified
95
+ @last_modified ||= File.stat(@full_path).mtime
96
+ end
97
+
98
+ def minified_content(source)
99
+ # Run the Y!UI Compressor
100
+ return source if !content_type
101
+ buffer= ""
102
+
103
+ IO.popen("java -jar #{$compressor} --type #{content_type}", "r+") { |pipe|
104
+ pipe.puts(source)
105
+ pipe.close_write
106
+ buffer= pipe.read
107
+ }
108
+
109
+ buffer
110
+ end
111
+
112
+ def self.path_relative_to_folder(path, folder)
113
+ outputFolder= File.expand_path(folder).to_s
114
+
115
+ # Remove leading slash and split into parts
116
+ file_parts= path.slice(1..-1).split('/');
117
+ output_parts= outputFolder.slice(1..-1).split('/');
118
+
119
+ common_prefix_length= 0
120
+
121
+ file_parts.each_index { |i|
122
+ common_prefix_length= i
123
+ break if file_parts[i]!=output_parts[i]
124
+ }
125
+
126
+ return '../'*(output_parts.length-common_prefix_length) + file_parts[common_prefix_length..-1].join('/')
127
+ end
128
+
129
+ def relative_to_folder(output_folder)
130
+ self.class.path_relative_to_folder(@full_path, output_folder)
131
+ end
132
+
133
+ def relative_to_file(source_file)
134
+ folder= File.dirname(File.expand_path(source_file))
135
+ self.relative_to_folder(folder)
136
+ end
137
+
138
+ def dependencies
139
+ content
140
+ @dependencies
141
+ end
142
+
143
+ def add_dependency(file)
144
+ return if @dependencies.include?(file)
145
+ @dependencies << file
146
+ end
147
+
148
+ def assets
149
+ content
150
+ @assets
151
+ end
152
+
153
+ def add_asset(file)
154
+ @assets << file
155
+ end
156
+
157
+ def copy_to(folder, prefix)
158
+ file_path= self.file_path || relative_to_folder(prefix||"")
159
+ final_target_folder= File.join(folder, File.dirname(file_path))
160
+ FileUtils.mkdir_p final_target_folder
161
+ FileUtils.cp self.full_path, final_target_folder
162
+ File.join(final_target_folder, File.basename(file_path))
163
+ end
164
+
165
+ end
166
+
167
+ end
168
+
169
+ # load all the other file types
170
+ Dir.glob("#{LIB_DIR}/distil/source-file/*-file.rb") { |file|
171
+ require file
172
+ }