distil 0.10.4 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }