jsus 0.3.4 → 0.3.5

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.
@@ -21,4 +21,27 @@ Feature: compression
21
21
  And file "tmp/compression.min.js" should contain
22
22
  """
23
23
  var Color
24
- """
24
+ """
25
+
26
+ # It's more a sanity check than a real test.
27
+ Scenario: using the --compression-method option
28
+ When I run "jsus Compression tmp --compress --compression-method uglifier"
29
+ Then the following files should exist:
30
+ | tmp/compression.js |
31
+ | tmp/compression.min.js |
32
+ And file "tmp/compression.min.js" should not contain
33
+ """
34
+ /*
35
+ """
36
+ And file "tmp/compression.min.js" should not contain
37
+ """
38
+ */
39
+ """
40
+ And file "tmp/compression.min.js" should contain
41
+ """
42
+ Input
43
+ """
44
+ And file "tmp/compression.min.js" should contain
45
+ """
46
+ Color
47
+ """
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{jsus}
8
- s.version = "0.3.4"
8
+ s.version = "0.3.5"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Mark Abramov"]
12
- s.date = %q{2011-08-30}
12
+ s.date = %q{2011-09-15}
13
13
  s.default_executable = %q{jsus}
14
14
  s.description = %q{Javascript packager and dependency resolver}
15
15
  s.email = %q{markizko@gmail.com}
@@ -94,7 +94,10 @@ Gem::Specification.new do |s|
94
94
  "features/step_definitions/cli_steps.rb",
95
95
  "features/support/env.rb",
96
96
  "jsus.gemspec",
97
+ "lib/extensions/rgl.rb",
97
98
  "lib/jsus.rb",
99
+ "lib/jsus/cli.rb",
100
+ "lib/jsus/compiler.rb",
98
101
  "lib/jsus/container.rb",
99
102
  "lib/jsus/middleware.rb",
100
103
  "lib/jsus/package.rb",
@@ -113,9 +116,11 @@ Gem::Specification.new do |s|
113
116
  "lib/jsus/util/validator.rb",
114
117
  "lib/jsus/util/validator/base.rb",
115
118
  "lib/jsus/util/validator/mooforge.rb",
119
+ "lib/jsus/util/watcher.rb",
116
120
  "markup/index_template.haml",
117
121
  "markup/stylesheet.css",
118
122
  "markup/template.haml",
123
+ "spec/benchmarks/topsort.rb",
119
124
  "spec/data/Basic/README",
120
125
  "spec/data/Basic/app/javascripts/Orwik/Source/Library/Color.js",
121
126
  "spec/data/Basic/app/javascripts/Orwik/Source/Widget/Input/Input.Color.js",
@@ -194,6 +199,7 @@ Gem::Specification.new do |s|
194
199
  "spec/data/test_source_one.js",
195
200
  "spec/data/unicode_source.js",
196
201
  "spec/data/unicode_source_with_bom.js",
202
+ "spec/extensions/rgl_spec.rb",
197
203
  "spec/jsus/container_spec.rb",
198
204
  "spec/jsus/middleware_spec.rb",
199
205
  "spec/jsus/package_spec.rb",
@@ -201,6 +207,7 @@ Gem::Specification.new do |s|
201
207
  "spec/jsus/pool_spec.rb",
202
208
  "spec/jsus/source_file_spec.rb",
203
209
  "spec/jsus/tag_spec.rb",
210
+ "spec/jsus/util/compressor_spec.rb",
204
211
  "spec/jsus/util/documenter_spec.rb",
205
212
  "spec/jsus/util/file_cache_spec.rb",
206
213
  "spec/jsus/util/inflection_spec.rb",
@@ -208,10 +215,12 @@ Gem::Specification.new do |s|
208
215
  "spec/jsus/util/tree_spec.rb",
209
216
  "spec/jsus/util/validator/base_spec.rb",
210
217
  "spec/jsus/util/validator/mooforge_spec.rb",
218
+ "spec/jsus/util/watcher_spec.rb",
219
+ "spec/jsus/util_spec.rb",
211
220
  "spec/shared/class_stubs.rb",
212
221
  "spec/spec_helper.rb"
213
222
  ]
214
- s.homepage = %q{http://github.com/markiz/jsus}
223
+ s.homepage = %q{http://github.com/jsus/jsus}
215
224
  s.licenses = ["Public Domain"]
216
225
  s.require_paths = ["lib"]
217
226
  s.rubygems_version = %q{1.6.2}
@@ -226,13 +235,17 @@ Gem::Specification.new do |s|
226
235
  s.add_runtime_dependency(%q<rgl>, [">= 0"])
227
236
  s.add_development_dependency(%q<rake>, [">= 0"])
228
237
  s.add_development_dependency(%q<rspec>, [">= 0"])
229
- s.add_development_dependency(%q<cucumber>, [">= 0"])
238
+ s.add_development_dependency(%q<cucumber>, ["= 1.0.3"])
230
239
  s.add_development_dependency(%q<jeweler>, [">= 0"])
231
240
  s.add_development_dependency(%q<murdoc>, ["~> 0.1.11"])
232
241
  s.add_development_dependency(%q<ruby-debug19>, [">= 0"])
242
+ s.add_development_dependency(%q<linecache>, ["= 0.45"])
233
243
  s.add_development_dependency(%q<ruby-debug>, [">= 0"])
234
244
  s.add_development_dependency(%q<fssm>, [">= 0"])
235
- s.add_development_dependency(%q<yui-compressor>, [">= 0"])
245
+ s.add_development_dependency(%q<yuicompressor>, [">= 0"])
246
+ s.add_development_dependency(%q<uglifier>, [">= 0"])
247
+ s.add_development_dependency(%q<front-compiler>, [">= 0"])
248
+ s.add_development_dependency(%q<closure-compiler>, [">= 0"])
236
249
  s.add_development_dependency(%q<sinatra>, [">= 0"])
237
250
  s.add_development_dependency(%q<rack-test>, [">= 0"])
238
251
  s.add_development_dependency(%q<yard>, [">= 0"])
@@ -242,13 +255,17 @@ Gem::Specification.new do |s|
242
255
  s.add_dependency(%q<rgl>, [">= 0"])
243
256
  s.add_dependency(%q<rake>, [">= 0"])
244
257
  s.add_dependency(%q<rspec>, [">= 0"])
245
- s.add_dependency(%q<cucumber>, [">= 0"])
258
+ s.add_dependency(%q<cucumber>, ["= 1.0.3"])
246
259
  s.add_dependency(%q<jeweler>, [">= 0"])
247
260
  s.add_dependency(%q<murdoc>, ["~> 0.1.11"])
248
261
  s.add_dependency(%q<ruby-debug19>, [">= 0"])
262
+ s.add_dependency(%q<linecache>, ["= 0.45"])
249
263
  s.add_dependency(%q<ruby-debug>, [">= 0"])
250
264
  s.add_dependency(%q<fssm>, [">= 0"])
251
- s.add_dependency(%q<yui-compressor>, [">= 0"])
265
+ s.add_dependency(%q<yuicompressor>, [">= 0"])
266
+ s.add_dependency(%q<uglifier>, [">= 0"])
267
+ s.add_dependency(%q<front-compiler>, [">= 0"])
268
+ s.add_dependency(%q<closure-compiler>, [">= 0"])
252
269
  s.add_dependency(%q<sinatra>, [">= 0"])
253
270
  s.add_dependency(%q<rack-test>, [">= 0"])
254
271
  s.add_dependency(%q<yard>, [">= 0"])
@@ -259,13 +276,17 @@ Gem::Specification.new do |s|
259
276
  s.add_dependency(%q<rgl>, [">= 0"])
260
277
  s.add_dependency(%q<rake>, [">= 0"])
261
278
  s.add_dependency(%q<rspec>, [">= 0"])
262
- s.add_dependency(%q<cucumber>, [">= 0"])
279
+ s.add_dependency(%q<cucumber>, ["= 1.0.3"])
263
280
  s.add_dependency(%q<jeweler>, [">= 0"])
264
281
  s.add_dependency(%q<murdoc>, ["~> 0.1.11"])
265
282
  s.add_dependency(%q<ruby-debug19>, [">= 0"])
283
+ s.add_dependency(%q<linecache>, ["= 0.45"])
266
284
  s.add_dependency(%q<ruby-debug>, [">= 0"])
267
285
  s.add_dependency(%q<fssm>, [">= 0"])
268
- s.add_dependency(%q<yui-compressor>, [">= 0"])
286
+ s.add_dependency(%q<yuicompressor>, [">= 0"])
287
+ s.add_dependency(%q<uglifier>, [">= 0"])
288
+ s.add_dependency(%q<front-compiler>, [">= 0"])
289
+ s.add_dependency(%q<closure-compiler>, [">= 0"])
269
290
  s.add_dependency(%q<sinatra>, [">= 0"])
270
291
  s.add_dependency(%q<rack-test>, [">= 0"])
271
292
  s.add_dependency(%q<yard>, [">= 0"])
@@ -0,0 +1,37 @@
1
+ module RGL
2
+ class TopsortedGraphHasCycles < Exception; end
3
+ class DirectedAdjacencyGraph
4
+ # Returns array of topologically sorted vertices. Also checks if there are
5
+ # cycles.
6
+ #
7
+ # @note Default implementation of topsort iterator is a bit faster, but it doesn't
8
+ # check for that condition.
9
+ # @return [Array] sorted vertices list
10
+ # @raise [TopsortedGraphHasCycles] if graph has cycles
11
+ # @api public
12
+ def topsorted_vertices
13
+ result = []
14
+ available_vertices = []
15
+ reversed_graph = reverse
16
+ out_degrees = {}
17
+
18
+ vertices.each do |v|
19
+ out_degrees[v] = reversed_graph.out_degree(v)
20
+ available_vertices.push(v) if out_degrees[v] == 0
21
+ end
22
+
23
+ while available_vertices.size > 0
24
+ vertice = available_vertices.pop
25
+ result.push(vertice)
26
+ each_adjacent(vertice) do |dependent|
27
+ reversed_graph.remove_edge(dependent, vertice)
28
+ out_degrees[dependent] -= 1
29
+ available_vertices.push(dependent) if out_degrees[dependent] == 0
30
+ end
31
+ end
32
+
33
+ raise TopsortedGraphHasCycles unless result.size == vertices.size
34
+ result
35
+ end # topsorted_vertices
36
+ end # class DirectedAdjacencyGraph
37
+ end # module RGL
@@ -6,9 +6,9 @@ require 'active_support/ordered_hash'
6
6
  require 'active_support/core_ext/module/delegation'
7
7
  require 'rgl/adjacency'
8
8
  require 'rgl/topsort'
9
+ require 'extensions/rgl'
9
10
 
10
11
  require 'fileutils'
11
- require 'pathname'
12
12
 
13
13
  #
14
14
  # Jsus -- your better javascript packager.
@@ -22,7 +22,8 @@ module Jsus
22
22
  autoload :Pool, 'jsus/pool'
23
23
  autoload :Util, 'jsus/util'
24
24
  autoload :Middleware, 'jsus/middleware'
25
- autoload :Compressor, 'jsus/compressor'
25
+ autoload :CLI, 'jsus/cli'
26
+ autoload :Compiler, 'jsus/compiler'
26
27
 
27
28
  # In verbose mode jsus shows a lot of warnings like missing dependencies.
28
29
  # Default: false
@@ -71,7 +72,7 @@ module Jsus
71
72
  #
72
73
  # @return [Jsus::Util::Logger]
73
74
  def self.logger
74
- Thread.current[:jsus_logger] ||= Jsus::Util::Logger.new(STDOUT).tap do |logger|
75
+ @@logger ||= Jsus::Util::Logger.new($stdout).tap do |logger|
75
76
  logger.level = Logger::ERROR
76
77
  logger.formatter = lambda {|severity, time, progname, msg|
77
78
  "[#{time.strftime("%Y-%m-%d %H:%M:%S")}] [JSUS:#{severity}] #{msg}\n"
@@ -86,6 +87,6 @@ module Jsus
86
87
  # @note In case you use non-jsus logger, you might want to extend it with
87
88
  # Jsus::Util::Logger::Buffering module.
88
89
  def self.logger=(value)
89
- Thread.current[:jsus_logger] = value
90
+ @@logger = value
90
91
  end # self.logger=
91
92
  end
@@ -0,0 +1,206 @@
1
+ # TODO: document Cli class
2
+ module Jsus
3
+ class CLI
4
+ class << self
5
+ attr_accessor :cli_options
6
+
7
+ def run!(options)
8
+ self.cli_options = options
9
+ new.launch
10
+
11
+ if options[:watch]
12
+ input_dirs = [ options[:input_dir], options[:deps_dir] ].compact
13
+ Jsus.logger.info "Jsus enters watch mode, it will watch your files for changes and relaunch itself"
14
+ Jsus::Util::Watcher.watch(input_dirs) do |filename|
15
+ Jsus.logger.info "#{filename} changed, recompiling..."
16
+ new.launch
17
+ Jsus.logger.info "... done"
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ attr_accessor :options
24
+
25
+ def initialize(options = Jsus::CLI.cli_options)
26
+ @options = options
27
+ end
28
+
29
+ def setup_output_directory
30
+ output_dir = Pathname.new(options[:output_dir])
31
+ output_dir.mkpath
32
+ output_dir
33
+ end
34
+
35
+ def launch
36
+ checkpoint(:start)
37
+ @output_dir = setup_output_directory
38
+ @pool = preload_pool
39
+ @package = load_package
40
+ display_pool_stats(@pool) if options[:display_pool_stats]
41
+ @package_content = compile_package(@package)
42
+ post_process!(@package_content, options[:postproc]) if options[:postproc]
43
+
44
+ package_filename = @output_dir + @package.filename
45
+
46
+ if options[:compress]
47
+ File.open(package_filename.to_s.chomp(".js") + ".min.js", 'w') do |f|
48
+ f.write compress_package(@package_content)
49
+ end
50
+ end
51
+
52
+ package_filename.open('w') {|f| f << @package_content }
53
+
54
+ generate_supplemental_files
55
+ validate_sources
56
+ generate_includes if options[:generate_includes]
57
+ generate_docs if options[:documented_classes] && !options[:documented_classes].empty?
58
+ output_benchmarks
59
+ rescue Exception => e
60
+ output_benchmarks
61
+ end
62
+
63
+ def preload_pool
64
+ if options[:deps_dir]
65
+ Jsus::Pool.new(options[:deps_dir])
66
+ else
67
+ Jsus::Pool.new
68
+ end.tap { checkpoint(:pool) }
69
+ end
70
+
71
+ def load_package
72
+ package = Jsus::Package.new(Pathname.new(options[:input_dir]), :pool => @pool)
73
+ package.include_dependencies!
74
+ checkpoint(:dependencies)
75
+ package
76
+ end
77
+
78
+ def display_pool_stats(pool)
79
+ checkpoint(:pool_stats)
80
+ message = <<-EOF
81
+ Pool stats:
82
+ Main package:
83
+ #{display_package @package}
84
+
85
+ Supplementary packages:
86
+ #{pool.packages.map {|package| display_package package}.join }
87
+
88
+ EOF
89
+ Jsus.logger.info message
90
+ end
91
+
92
+ def display_package(package)
93
+ result = "Package: #{package.name}\n"
94
+ package.source_files.to_a.sort_by {|sf| sf.filename}.each do |sf|
95
+ result << " [#{sf.relative_filename}]\n"
96
+ result << " Provides: [#{sf.provides_names.join(", ")}]\n"
97
+ result << " Requires: [#{sf.requires_names.join(", ")}]\n"
98
+ end
99
+ result << "\n"
100
+ end
101
+
102
+ def compile_package(package)
103
+ package.compile(nil).tap { checkpoint(:compilation) }
104
+ end
105
+
106
+ # Modificate content string
107
+ def post_process!(content, postproc)
108
+ Compiler.post_process!(content, postproc)
109
+ checkpoint(:postproc)
110
+ end
111
+
112
+ def compress_package(content)
113
+ compression_method = options.fetch(:compression_method, :yui)
114
+ compressed_content = Jsus::Util::Compressor.compress(content, :method => compression_method)
115
+ if compressed_content != ""
116
+ @compression_ratio = compressed_content.size.to_f / content.size.to_f
117
+ else
118
+ @compression_ratio = 1.00
119
+ Jsus.logger.error "YUI compressor could not parse input. \n" <<
120
+ "Compressor command used: #{compressor.command.join(' ')}"
121
+ end
122
+ checkpoint(:compress)
123
+
124
+ compressed_content
125
+ end
126
+
127
+ def generate_supplemental_files
128
+ @package.generate_scripts_info(@output_dir) unless options[:without_scripts_info]
129
+ @package.generate_tree(@output_dir) unless options[:without_tree_info]
130
+ checkpoint(:supplemental_files)
131
+ end
132
+
133
+ def generate_includes
134
+ includes_root = Pathname.new(options[:includes_root] || @output_dir)
135
+ Compiler.generate_includes(@package, includes_root, @output_dir + "includes.js")
136
+ checkpoint(:includes)
137
+ end
138
+
139
+ def generate_docs
140
+ documenter = Jsus::Util::Documenter.new(:highlight_source => !options[:no_syntax_highlight])
141
+ @package.source_files.each {|source| documenter << source }
142
+ @pool.sources.each {|source| documenter << source }
143
+ documenter.only(options[:documented_classes]).generate(@output_dir + "/docs")
144
+ checkpoint(:documentation)
145
+ end
146
+
147
+ def validate_sources
148
+ validators_map = {"mooforge" => Jsus::Util::Validator::Mooforge}
149
+ (options[:validators] || []).each do |validator_name|
150
+ if validator = validators_map[validator_name]
151
+ errors = validator.new(@pool.sources.to_a & @package.source_files.to_a).validation_errors
152
+ unless errors.empty?
153
+ Jsus.logger.info "Validator #{validator_name} found errors: " <<
154
+ errors.map {|e| Jsus.logger.info " * #{e}"}.join("\n")
155
+ end
156
+ else
157
+ Jsus.logger.info "No such validator: #{validator_name}"
158
+ end
159
+ end
160
+ checkpoint(:validators)
161
+ end
162
+
163
+ def output_benchmarks
164
+ if options[:benchmark]
165
+ message = "Benchmarking results:\n"
166
+ message << "Total execution time: #{formatted_time_for(:all)}\n"
167
+ message << "\n"
168
+ message << "Of them:\n"
169
+ message << "Pool preloading time: #{formatted_time_for(:pool)}\n" if checkpoint?(:pool)
170
+ message << "Docs generation time: #{formatted_time_for(:documentation)}\n" if checkpoint?(:documentation)
171
+ message << "Total compilation time: #{formatted_time_for(:compilation)}\n" if checkpoint?(:compilation)
172
+ message << "Post-processing time: #{formatted_time_for(:postproc)}\n" if checkpoint?(:postproc)
173
+ message << "Compression time: #{formatted_time_for(:compress)}\n" if checkpoint?(:compress)
174
+ message << "\n"
175
+ message << "Compression ratio: #{sprintf("%.2f%%", @compression_ratio * 100)}\n" if Jsus.verbose? && @compression_ratio
176
+ Jsus.logger.info message
177
+ end
178
+ end
179
+
180
+ def checkpoint(checkpoint_name)
181
+ @checkpoints ||= {}
182
+ @time_for ||= {}
183
+ @checkpoints[checkpoint_name] = Time.now
184
+ if @last_checkpoint
185
+ @time_for[checkpoint_name] = @checkpoints[checkpoint_name] - @last_checkpoint
186
+ end
187
+ @last_checkpoint = Time.now
188
+ end
189
+
190
+ def checkpoint?(checkpoint_name)
191
+ @checkpoints[checkpoint_name]
192
+ end
193
+
194
+ def time_for(checkpoint_name)
195
+ if checkpoint_name == :all
196
+ @last_checkpoint - @checkpoints[:start]
197
+ else
198
+ @time_for[checkpoint_name]
199
+ end
200
+ end
201
+
202
+ def formatted_time_for(checkpoint_name)
203
+ "#{format("%.3f", time_for(checkpoint_name))}s"
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,28 @@
1
+ module Jsus::Compiler
2
+ # Handles main features of jsus
3
+ extend self
4
+
5
+ def post_process!(content, postproc)
6
+ postproc.each do |processor|
7
+ case processor.strip
8
+ when /^moocompat12$/i
9
+ content.gsub!(/\/\/<1.2compat>.*?\/\/<\/1.2compat>/m, '')
10
+ content.gsub!(/\/\*<1.2compat>\*\/.*?\/\*<\/1.2compat>\*\//m, '')
11
+ when /^mooltie8$/i
12
+ content.gsub!(/\/\/<ltIE8>.*?\/\/<\/ltIE8>/m, '')
13
+ content.gsub!(/\/\*<ltIE8>\*\/.*?\/\*<\/ltIE8>\*\//m, '')
14
+ else
15
+ Jsus.logger.error "Unknown post-processor: #{processor}"
16
+ end
17
+ end
18
+ end
19
+
20
+ def generate_includes(package, includes_root, output_file)
21
+ File.open(output_file, "w") do |f|
22
+ c = Jsus::Container.new(*(package.source_files.to_a + package.linked_external_dependencies.to_a))
23
+ paths = c.required_files(includes_root)
24
+ f.puts Jsus::Util::CodeGenerator.generate_includes(paths)
25
+ end
26
+ end
27
+
28
+ end