jsus 0.3.3 → 0.3.4

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.
data/.document CHANGED
@@ -3,3 +3,4 @@ bin/*
3
3
  -
4
4
  features/**/*.feature
5
5
  UNLICENSE
6
+ CHANGELOG
data/.yardopts CHANGED
@@ -1,9 +1,8 @@
1
1
  --markup="markdown" lib/**/*.rb
2
2
  --no-private
3
- --no-protected
4
3
  --main README.md
5
4
  --hide-tag todo
6
5
  -
7
- LICENSE
6
+ UNLICENSE
8
7
  CHANGELOG
9
8
  docs/*.textile
data/CHANGELOG CHANGED
@@ -1,4 +1,19 @@
1
1
  = Jsus Changelog
2
+ == Version 0.3.4
3
+ Middleware changes:
4
+ * support for /compressed/ path component, which acts like /require/, but
5
+ compresses the result in the end.
6
+ * Cache result is now stored in subfolders of cache directory (easier to manage
7
+ with nginx and alike)
8
+ * Improved error reporting (choice of one of multiple modes in middleware settings)
9
+
10
+ CLI changes:
11
+ * --no-cycle-search option for CLI to improve compilation times
12
+
13
+ Other changes:
14
+ * Compression routines moved out to Jsus::Util::Compressor class. For now, only
15
+ yui-compressor method is available
16
+
2
17
  == Version 0.3.3
3
18
  * Unfortunate accident with rubygems
4
19
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.3
1
+ 0.3.4
data/bin/jsus CHANGED
@@ -73,6 +73,10 @@ module Jsus
73
73
  options[:compress] = true
74
74
  end
75
75
 
76
+ opts.on('--no-cycle-search', 'disables search for circular dependencies which may take quite some time during compilation') do
77
+ Jsus.look_for_cycles = false
78
+ end
79
+
76
80
  opts.on_tail('-v', '--verbose', 'verbose mode, shows various debug messages') do
77
81
  Jsus.verbose = true
78
82
  end
@@ -276,9 +280,7 @@ module Jsus
276
280
  end
277
281
 
278
282
  def compress_package
279
- require 'yui/compressor'
280
- compressor = YUI::JavaScriptCompressor.new(:munge => true)
281
- compressed_content = compressor.compress(@package_content)
283
+ compressed_content = Jsus::Util::Compressor.new(@package_content).result
282
284
  if compressed_content != ""
283
285
  @compression_ratio = compressed_content.size.to_f / @package_content.size.to_f
284
286
  compressed_file_name = @package.filename.sub(/.js$/, ".min.js")
@@ -289,8 +291,6 @@ module Jsus
289
291
  puts "Compressor command used: #{compressor.command.join(' ')}"
290
292
  end
291
293
  checkpoint(:compress)
292
- rescue LoadError
293
- puts 'ERROR: You need "yui-compressor" gem in order to use --compress option'
294
294
  end
295
295
 
296
296
  def generate_supplemental_files
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{jsus}
8
- s.version = "0.3.3"
8
+ s.version = "0.3.4"
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-06-19}
12
+ s.date = %q{2011-08-30}
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}
@@ -104,9 +104,11 @@ Gem::Specification.new do |s|
104
104
  "lib/jsus/tag.rb",
105
105
  "lib/jsus/util.rb",
106
106
  "lib/jsus/util/code_generator.rb",
107
+ "lib/jsus/util/compressor.rb",
107
108
  "lib/jsus/util/documenter.rb",
108
109
  "lib/jsus/util/file_cache.rb",
109
110
  "lib/jsus/util/inflection.rb",
111
+ "lib/jsus/util/logger.rb",
110
112
  "lib/jsus/util/tree.rb",
111
113
  "lib/jsus/util/validator.rb",
112
114
  "lib/jsus/util/validator/base.rb",
@@ -166,6 +168,8 @@ Gem::Specification.new do |s|
166
168
  "spec/data/JsonPackage/Source/SheetParser.CSS.js",
167
169
  "spec/data/JsonPackage/Source/sg-regex-tools.js",
168
170
  "spec/data/JsonPackage/package.json",
171
+ "spec/data/MissingDependencies/Source/Widget.js",
172
+ "spec/data/MissingDependencies/package.yml",
169
173
  "spec/data/MooforgeValidation/README",
170
174
  "spec/data/MooforgeValidation/app/javascripts/Orwik/Source/Library/InvalidNoAuthors.js",
171
175
  "spec/data/MooforgeValidation/app/javascripts/Orwik/Source/Library/InvalidNoLicense.js",
@@ -200,6 +204,7 @@ Gem::Specification.new do |s|
200
204
  "spec/jsus/util/documenter_spec.rb",
201
205
  "spec/jsus/util/file_cache_spec.rb",
202
206
  "spec/jsus/util/inflection_spec.rb",
207
+ "spec/jsus/util/logger_spec.rb",
203
208
  "spec/jsus/util/tree_spec.rb",
204
209
  "spec/jsus/util/validator/base_spec.rb",
205
210
  "spec/jsus/util/validator/mooforge_spec.rb",
@@ -22,6 +22,7 @@ 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
26
 
26
27
  # In verbose mode jsus shows a lot of warnings like missing dependencies.
27
28
  # Default: false
@@ -37,6 +38,7 @@ module Jsus
37
38
  # @api public
38
39
  def self.verbose=(verbose)
39
40
  @verbose = verbose
41
+ logger.level = verbose ? Logger::DEBUG : Logger::ERROR
40
42
  end
41
43
 
42
44
  # @return [String] Jsus version
@@ -63,4 +65,27 @@ module Jsus
63
65
  def self.look_for_cycles=(value)
64
66
  @look_for_cycles = value
65
67
  end
68
+
69
+ # Jsus logger used for all the output. By default uses Logger::ERROR level
70
+ # severity and screen as output device.
71
+ #
72
+ # @return [Jsus::Util::Logger]
73
+ def self.logger
74
+ Thread.current[:jsus_logger] ||= Jsus::Util::Logger.new(STDOUT).tap do |logger|
75
+ logger.level = Logger::ERROR
76
+ logger.formatter = lambda {|severity, time, progname, msg|
77
+ "[#{time.strftime("%Y-%m-%d %H:%M:%S")}] [JSUS:#{severity}] #{msg}\n"
78
+ }
79
+ end
80
+ end # self.logger
81
+
82
+ # Reassign jsus logger whenever needed (E.g. use rails logger)
83
+ #
84
+ # @param value Logger responding to #info, #warn, #debug, #error, #fatal,
85
+ # and #buffer
86
+ # @note In case you use non-jsus logger, you might want to extend it with
87
+ # Jsus::Util::Logger::Buffering module.
88
+ def self.logger=(value)
89
+ Thread.current[:jsus_logger] = value
90
+ end # self.logger=
66
91
  end
@@ -9,7 +9,7 @@ module Jsus
9
9
  class Container
10
10
  # Instantiates a container from given sources.
11
11
  #
12
- # @param [SourceFile]
12
+ # @param [*SourceFile] sources
13
13
  def initialize(*sources)
14
14
  sources.each do |source|
15
15
  push(source)
@@ -20,7 +20,7 @@ module Jsus
20
20
 
21
21
  # Pushes an item to the container
22
22
  #
23
- # @param [SourceFile] source pushed file
23
+ # @param [SourceFile] source source pushed file
24
24
  def push(source)
25
25
  if source
26
26
  if source.kind_of?(Array) || source.kind_of?(Container)
@@ -86,7 +86,7 @@ module Jsus
86
86
  #
87
87
  # Optionally accepts a filesystem point to calculate relative paths from.
88
88
  #
89
- # @param [String] root point from which the relative paths are calculated.
89
+ # @param [String] root root point from which the relative paths are calculated.
90
90
  # When omitted, full paths are returned.
91
91
  # @return [Array] ordered list of required files
92
92
  # @api public
@@ -131,18 +131,17 @@ module Jsus
131
131
  result = []
132
132
  if Jsus.look_for_cycles?
133
133
  cycles = graph.cycles
134
+ error_msg = []
134
135
  unless cycles.empty?
135
- puts "*" * 30
136
- puts "ACHTUNG! WARNING! ATTENTION!"
137
- puts "*" * 30
138
- puts "Jsus has discovered you have circular dependencies in your code."
139
- puts "Please resolve them immediately!"
140
- puts "List of circular dependencies:"
136
+ error_msg << "Jsus has discovered you have circular dependencies in your code."
137
+ error_msg << "Please resolve them immediately!"
138
+ error_msg << "List of circular dependencies:"
141
139
  cycles.each do |cycle|
142
- puts "-" * 30
143
- puts (cycle + [cycle.first]).map {|sf| sf.filename}.join(" => ")
140
+ error_msg << "-" * 30
141
+ error_msg << (cycle + [cycle.first]).map {|sf| sf.filename}.join(" => ")
144
142
  end
145
- puts "*" * 30
143
+ error_msg = error_msg.join("\n")
144
+ Jsus.logger.fatal(error_msg)
146
145
  end
147
146
  end
148
147
  graph.topsort_iterator.each { |item| result << item }
@@ -33,7 +33,7 @@ module Jsus
33
33
  #
34
34
  class Middleware
35
35
  include Rack
36
- class <<self
36
+ class << self
37
37
  # Default settings for Middleware
38
38
  DEFAULT_SETTINGS = {
39
39
  :packages_dir => ".",
@@ -41,7 +41,9 @@ module Jsus
41
41
  :cache_path => nil,
42
42
  :prefix => "jsus",
43
43
  :cache_pool => true,
44
- :includes_root => "."
44
+ :includes_root => ".",
45
+ :log_method => nil, # [:alert, :html, :console]
46
+ :postproc => [] # ["mooltie8", "moocompat12"]
45
47
  }.freeze
46
48
 
47
49
  # @return [Hash] Middleware current settings
@@ -94,7 +96,7 @@ module Jsus
94
96
  end # class <<self
95
97
 
96
98
  # Default rack initialization routine
97
- # @param [#call] rack chain caller
99
+ # @param [#call] app rack chain caller
98
100
  # @api public
99
101
  def initialize(app)
100
102
  @app = app
@@ -106,17 +108,23 @@ module Jsus
106
108
  # Jsus::Middleware#call method dups current rack app and executes
107
109
  # Jsus::Middleware#_call on it.
108
110
  #
109
- # @param [Hash] rack env
111
+ # @param [Hash] env rack env
110
112
  # @return [#each] rack response
111
113
  # @api semipublic
112
114
  def _call(env)
115
+ Jsus.logger.buffer.clear
113
116
  path = Utils.unescape(env["PATH_INFO"])
114
117
  return @app.call(env) unless handled_by_jsus?(path)
115
118
  path.sub!(path_prefix_regex, "")
116
119
  components = path.split("/")
117
120
  return @app.call(env) unless components.size >= 2
121
+
122
+ request_options[:path] = path
118
123
  if components[0] == "require"
119
124
  generate_requires(components[1])
125
+ elsif components[0] == "compressed"
126
+ request_options[:compress] = true
127
+ generate_requires(components[1])
120
128
  elsif components[0] == "include"
121
129
  generate_includes(components[1])
122
130
  else
@@ -126,7 +134,7 @@ module Jsus
126
134
 
127
135
  # Rack calling point
128
136
  #
129
- # @param [Hash] rack env
137
+ # @param [Hash] env rack env
130
138
  # @return [#each] rack response
131
139
  # @api public
132
140
  def call(env)
@@ -135,16 +143,39 @@ module Jsus
135
143
 
136
144
  protected
137
145
 
146
+ # Current request options
147
+ # @return [Hash]
148
+ def request_options
149
+ @options ||= {}
150
+ end # request_options
151
+
152
+ # Rack response of not found
153
+ # @return [#each] 404 response
154
+ # @api semipublic
155
+ def not_found!
156
+ [404, {"Content-Type" => "text/plain"}, ["Jsus doesn't know anything about this entity"]]
157
+ end # not_found!
158
+
159
+ # Respond with given text
160
+ # @param [String] text text to respond with
161
+ # @return [#each] 200 response
162
+ # @api semipublic
163
+ def respond_with(text)
164
+ response = formatted_errors + postproc(text)
165
+ cache_response!(response) if cache?
166
+ [200, {"Content-Type" => "text/javascript"}, [response]]
167
+ end # respond_with
168
+
138
169
  # Generates response for /require/ requests.
139
170
  #
140
- # @param [String] path component to required sources
171
+ # @param [String] path_string path component to required sources
141
172
  # @return [#each] rack response
142
173
  # @api semipublic
143
174
  def generate_requires(path_string)
144
175
  files = path_string_to_files(path_string)
145
176
  if !files.empty?
146
177
  response = Container.new(*files).map {|f| f.content }.join("\n")
147
- cache.write(escape_path_for_cache_key(path_string), response) if cache?
178
+ response = Jsus::Util::Compressor.new(response).result if request_options[:compress]
148
179
  respond_with(response)
149
180
  else
150
181
  not_found!
@@ -153,7 +184,7 @@ module Jsus
153
184
 
154
185
  # Generates response for /include/ requests.
155
186
  #
156
- # @param [String] path component to included sources
187
+ # @param [String] path_string path component to included sources
157
188
  # @return [#each] rack response
158
189
  # @api semipublic
159
190
  def generate_includes(path_string)
@@ -168,7 +199,7 @@ module Jsus
168
199
 
169
200
  # Returns list of exlcuded and included source files for given path strings.
170
201
  #
171
- # @param [String] string with + and ~
202
+ # @param [String] path_string string with + and ~
172
203
  # @return [Hash] hash with source files to include and to exclude
173
204
  # @api semipublic
174
205
  def path_string_to_files(path_string)
@@ -179,6 +210,26 @@ module Jsus
179
210
  files
180
211
  end # path_string_to_files
181
212
 
213
+ # Post-processes output (removes different compatibility tags)
214
+ #
215
+ # @param [String] source source to post-process
216
+ # @return [String] post-processed source
217
+ def postproc(source)
218
+ Array(self.class.settings[:postproc]).inject(source) do |result, processor|
219
+ case processor.strip
220
+ when /^moocompat12$/i
221
+ result.gsub(/\/\/<1.2compat>.*?\/\/<\/1.2compat>/m, '').
222
+ gsub(/\/\*<1.2compat>\*\/.*?\/\*<\/1.2compat>\*\//m, '')
223
+ when /^mooltie8$/i
224
+ result.gsub(/\/\/<ltIE8>.*?\/\/<\/ltIE8>/m, '').
225
+ gsub(/\/\*<ltIE8>\*\/.*?\/\*<\/ltIE8>\*\//m, '')
226
+ else
227
+ Jsus.logger.error "Unknown post-processor: #{processor}"
228
+ result
229
+ end
230
+ end
231
+ end
232
+
182
233
  # Parses human-readable string with + and ~ operations into a more usable hash.
183
234
  # @note + is a space after url decoding
184
235
  #
@@ -203,8 +254,9 @@ module Jsus
203
254
  end # parse_path_string
204
255
 
205
256
  # Returns a list of associated files for given source file or source package.
206
- # @param [String] canonical source file or source package name or wildcard
207
- # e.g. "Mootools.Core", "Mootools.Core/*", "Mootools.Core/Class", "**/*"
257
+ # @param [String] source_file_or_package canonical source file or source
258
+ # package name or wildcard. E.g. "Mootools.Core", "Mootools.Core/*",
259
+ # "Mootools.Core/Class", "**/*"
208
260
  # @return [Array] list of source files for given input
209
261
  # @api semipublic
210
262
  def get_associated_files(source_file_or_package)
@@ -225,24 +277,9 @@ module Jsus
225
277
  end
226
278
  end # get_associated_files
227
279
 
228
- # Rack response of not found
229
- # @return [#each] 404 response
230
- # @api semipublic
231
- def not_found!
232
- [404, {"Content-Type" => "text/plain"}, ["Jsus doesn't know anything about this entity"]]
233
- end # not_found!
234
-
235
- # Respond with given text
236
- # @param [String] text to respond with
237
- # @return [#each] 200 response
238
- # @api semipublic
239
- def respond_with(text)
240
- [200, {"Content-Type" => "text/javascript"}, [text]]
241
- end # respond_with
242
-
243
280
  # Check whether given path is handled by jsus middleware.
244
281
  #
245
- # @param [String] path
282
+ # @param [String] path path
246
283
  # @return [Boolean]
247
284
  # @api semipublic
248
285
  def handled_by_jsus?(path)
@@ -283,6 +320,13 @@ module Jsus
283
320
  self.class.cache
284
321
  end # cache
285
322
 
323
+ # Saves response into the filesystem
324
+ # @param [String] response text to store
325
+ # @return [String] filename
326
+ def cache_response!(response)
327
+ cache.write(escape_path_for_cache_key(request_options[:path]), response)
328
+ end # cache_response!
329
+
286
330
  # @return [Boolean] whether pool is shared between requests
287
331
  # @api semipublic
288
332
  def cache_pool?
@@ -292,11 +336,34 @@ module Jsus
292
336
  # You might or might not need to do some last minute conversions for your cache
293
337
  # key. Default behaviour is merely a nginx hack, you may have to use your own
294
338
  # function for your web-server.
295
- # @param [String] request path minus the prefix
339
+ # @param [String] path request path minus the prefix
296
340
  # @return [String] normalized cache key for given request path
297
341
  # @api semipublic
298
342
  def escape_path_for_cache_key(path)
299
343
  path.gsub(" ", "+")
300
344
  end # escape_path_for_cache_key
345
+
346
+ # Outputs errors in one or multiple ways.
347
+ # Set middleware setting :log_method to array with a combination of any of the following:
348
+ # :alert -- generates javascript alert with warning text
349
+ # :console -- generates console logging entry
350
+ # :html -- injects error / warning messages directly into html body
351
+ # @return [String] javascript code containing errors output for various methods
352
+ # @api semipublic
353
+ def formatted_errors
354
+ Array(self.class.settings[:log_method]).inject("") do |result, log_method|
355
+ result << errors.map do |severity, error|
356
+ case log_method
357
+ when :alert then "alert(#{error.inspect});"
358
+ when :console then "console.log(#{error.inspect});"
359
+ when :html then "document.body.innerHTML = '<font color=red>' + #{error.inspect} + '</font><br/>' + document.body.innerHTML;"
360
+ end
361
+ end.compact.join("\n") + "\n"
362
+ end
363
+ end # formatted_errors
364
+
365
+ def errors
366
+ Jsus.logger.buffer
367
+ end # errors
301
368
  end # class Middleware
302
369
  end # module Jsus
@@ -14,7 +14,7 @@ module Jsus
14
14
  #
15
15
  # Creates a package from given directory.
16
16
  #
17
- # @param [String] path to directory containing a package
17
+ # @param [String] directory path to directory containing a package
18
18
  # @param [Hash] options
19
19
  # @option options [Jsus::Pool] :pool which pool the package should belong to.
20
20
  # @raise an error when the given directory doesn't contain a package.yml or package.json
@@ -27,6 +27,7 @@ module Jsus
27
27
  elsif File.exists?(File.join(directory, 'package.json'))
28
28
  self.header = JSON.load(File.open(File.join(directory, 'package.json'), 'r:utf-8') {|f| f.read })
29
29
  else
30
+ Jsus::Middleware.errors << "Directory #{directory} does not contain a valid package.yml / package.json file!"
30
31
  raise "Directory #{directory} does not contain a valid package.yml / package.json file!"
31
32
  end
32
33
  Dir.chdir(directory) do
@@ -39,7 +40,7 @@ module Jsus
39
40
  source_files << source_file
40
41
  end
41
42
  else
42
- puts "Warning: #{source} is not found for #{name}" if Jsus.verbose?
43
+ Jsus.logger.warn "#{source} is not found for #{name}"
43
44
  end
44
45
  end
45
46
  end
@@ -130,7 +131,7 @@ module Jsus
130
131
  end
131
132
 
132
133
  # Compiles source files and linked external source files into a given category.
133
- # @param [String, nil] directory to output the result into
134
+ # @param [String, nil] directory directory to output the result into
134
135
  # @return [String] content of merged source files
135
136
  # @api public
136
137
  def compile(directory = ".")
@@ -139,8 +140,8 @@ module Jsus
139
140
  end
140
141
 
141
142
  # Generates tree structure for files in package into a json file.
142
- # @param [String] directory to output the result
143
- # @param [String] resulting filename
143
+ # @param [String] directory directory to output the result
144
+ # @param [String] filename resulting filename
144
145
  # @return [Hash] hash with tree structure
145
146
  # @api public
146
147
  def generate_tree(directory = ".", filename = "tree.json")
@@ -162,8 +163,8 @@ module Jsus
162
163
  end
163
164
 
164
165
  # Generates info about resulting compiled package into a json file.
165
- # @param [String] directory to output the result
166
- # @param [String] resulting filename
166
+ # @param [String] directory directory to output the result
167
+ # @param [String] filename resulting filename
167
168
  # @return [Hash] hash with scripts info
168
169
  # @api public
169
170
  def generate_scripts_info(directory = ".", filename = "scripts.json")
@@ -228,13 +229,13 @@ module Jsus
228
229
  # Private API
229
230
 
230
231
 
231
- # @param [Hash] parsed header
232
+ # @param [Hash] new_header parsed header
232
233
  # @api private
233
234
  def header=(new_header)
234
235
  @header = new_header
235
236
  end
236
237
 
237
- # @param [Enumerable] external dependencies
238
+ # @param [Enumerable] new_value external dependencies
238
239
  # @api private
239
240
  def linked_external_dependencies=(new_value)
240
241
  @linked_external_dependencies = new_value
@@ -12,7 +12,7 @@ module Jsus
12
12
  #
13
13
  # Inits packager with the given sources.
14
14
  #
15
- # @param [SourceFile] source files
15
+ # @param [*SourceFile] sources source files
16
16
  # @api public
17
17
  def initialize(*sources)
18
18
  self.container = Container.new(*sources)
@@ -27,7 +27,7 @@ module Jsus
27
27
  # Concatenates all the sources' contents into a single string.
28
28
  # If given a filename, outputs into a file.
29
29
  #
30
- # @param [String, nil] output file name
30
+ # @param [String, nil] output_file output file name
31
31
  # @return [String] concatenated source files
32
32
  # @api public
33
33
  def pack(output_file = nil)
@@ -12,7 +12,7 @@ module Jsus
12
12
  #
13
13
  # Basic constructor.
14
14
  #
15
- # @param [Array, String, nil] directory or list of directories to load source
15
+ # @param [Array, String, nil] dir_or_dirs directory or list of directories to load source
16
16
  # packages from.
17
17
  # @api public
18
18
  def initialize(dir_or_dirs = nil)
@@ -49,7 +49,7 @@ module Jsus
49
49
  #
50
50
  # If given a source file, returns the input.
51
51
  #
52
- # @param [String, Jsus::Tag, Jsus::SourceFile]
52
+ # @param [String, Jsus::Tag, Jsus::SourceFile] source_or_key
53
53
  # @return [Jsus::SourceFile]
54
54
  # @api public
55
55
  def lookup(source_or_key)
@@ -70,7 +70,7 @@ module Jsus
70
70
  #
71
71
  # Looks up for dependencies for given file recursively.
72
72
  #
73
- # @param [String, Jsus::Tag, Jsus::SourceFile]
73
+ # @param [String, Jsus::Tag, Jsus::SourceFile] source_or_source_key
74
74
  # @return [Jsus::Container] container with all the dependencies
75
75
  # @api public
76
76
  def lookup_dependencies(source_or_source_key)
@@ -87,7 +87,7 @@ module Jsus
87
87
  result.sort!
88
88
  end
89
89
 
90
- # @param [String, Jsus::Tag]
90
+ # @param [String, Jsus::Tag] tag_or_tag_key
91
91
  # @return [Array] array with source files with extensions for given tag.
92
92
  # @api public
93
93
  def lookup_extensions(tag_or_tag_key)
@@ -98,7 +98,8 @@ module Jsus
98
98
  #
99
99
  # Pushes an item into a pool.
100
100
  #
101
- # @param [Jsus::SourceFile, Jsus::Package, Array] items to push
101
+ # @param [Jsus::SourceFile, Jsus::Package, Array] source_or_sources_or_package
102
+ # items to push
102
103
  # @return [self]
103
104
  # @api public
104
105
  def <<(source_or_sources_or_package)
@@ -112,8 +113,8 @@ module Jsus
112
113
  extensions_map[source.extends] << source
113
114
  else
114
115
  source.provides.each do |p|
115
- if provides_map[p] && provides_map[p] != source && provides_map[p].filename != source.filename && Jsus.verbose?
116
- puts "Redeclared #{p.to_s} in #{source.filename} (previously declared in #{provides_map[p].filename})"
116
+ if provides_map[p] && provides_map[p] != source && provides_map[p].filename != source.filename
117
+ Jsus.logger.warn "Redeclared #{p.to_s} in #{source.filename} (previously declared in #{provides_map[p].filename})"
117
118
  end
118
119
  provides_map[p] = source
119
120
  end
@@ -147,7 +148,7 @@ module Jsus
147
148
  # You probably will find yourself using #include_dependencies instead.
148
149
  # This method caches results locally, use flush_cache! to drop.
149
150
  #
150
- # @param [String, Jsus::Tag, Jsus::SourceFile]
151
+ # @param [String, Jsus::Tag, Jsus::SourceFile] source_or_source_key
151
152
  # @return [Array] array of direct dependencies for given entity
152
153
  # @api private
153
154
  def lookup_direct_dependencies(source_or_source_key)
@@ -158,7 +159,7 @@ module Jsus
158
159
  #
159
160
  # Performs the actual lookup for #lookup_direct_dependencies
160
161
  #
161
- # @param [String, Jsus::Tag, Jsus::SourceFile]
162
+ # @param [String, Jsus::Tag, Jsus::SourceFile] source
162
163
  # @return [Array] array of direct dependencies for given entity
163
164
  # @api private
164
165
  def lookup_direct_dependencies!(source)
@@ -166,8 +167,8 @@ module Jsus
166
167
 
167
168
  source.dependencies.map do |dependency|
168
169
  result = provides_tree.glob("/#{dependency}")
169
- if (!result || (result.is_a?(Array) && result.empty?)) && Jsus.verbose?
170
- puts "#{source.filename} is missing #{dependency.is_a?(SourceFile) ? dependency.filename : dependency.to_s}"
170
+ if (!result || (result.is_a?(Array) && result.empty?))
171
+ Jsus.logger.warn "#{source.filename} is missing #{dependency.is_a?(SourceFile) ? dependency.filename : dependency.to_s}"
171
172
  end
172
173
  result
173
174
  end.flatten.map {|tag| lookup(tag) }
@@ -187,7 +188,7 @@ module Jsus
187
188
 
188
189
 
189
190
  # Registers the source in both trees
190
- # @param [Jsus::SourceFile]
191
+ # @param [Jsus::SourceFile] source
191
192
  # @api private
192
193
  def add_source_to_trees(source)
193
194
  if source.package
@@ -39,7 +39,7 @@ module Jsus
39
39
  #
40
40
  # Initializes a SourceFile given the filename and options
41
41
  #
42
- # @param [String]
42
+ # @param [String] filename
43
43
  # @param [Hash] options
44
44
  # @option options [Jsus::Pool] :pool owning pool
45
45
  # @option options [Jsus::Package] :package owning package
@@ -158,7 +158,7 @@ module Jsus
158
158
  extends && !extends.empty?
159
159
  end
160
160
 
161
- # @return [Array] array of included extensions for given source.
161
+ # @return [Array] new_value array of included extensions for given source.
162
162
  # @api public
163
163
  def extensions
164
164
  @extensions ||= []
@@ -166,7 +166,7 @@ module Jsus
166
166
  @extensions
167
167
  end
168
168
 
169
- # @param [Array] list of extensions for given file
169
+ # @param [Array] new_value list of extensions for given file
170
170
  # @api semipublic
171
171
  def extensions=(new_value)
172
172
  @extensions = new_value
@@ -219,7 +219,7 @@ module Jsus
219
219
  end
220
220
 
221
221
  # Parses header and gets info from it.
222
- # @param [String] header content
222
+ # @param [String] new_header header content
223
223
  # @api private
224
224
  def header=(new_header)
225
225
  @header = new_header
@@ -242,7 +242,7 @@ module Jsus
242
242
  end
243
243
  end
244
244
 
245
- # @param [String] file content
245
+ # @param [String] new_value file content
246
246
  # @api private
247
247
  def content=(new_value)
248
248
  @content = new_value
@@ -261,7 +261,7 @@ module Jsus
261
261
  @content
262
262
  end
263
263
 
264
- # @param [Enumerable] list of tags
264
+ # @param [Enumerable] tag_list list of tags
265
265
  # @return [Array] normalized tags list
266
266
  # @api private
267
267
  def parse_tag_list(tag_list)
@@ -284,7 +284,7 @@ module Jsus
284
284
 
285
285
  # Assigns an instance of Jsus::Pool to the source file.
286
286
  # Also performs push to that pool.
287
- # @param [Jsus::Pool]
287
+ # @param [Jsus::Pool] new_value
288
288
  # @api private
289
289
  def pool=(new_value)
290
290
  @pool = new_value
@@ -32,7 +32,7 @@ module Jsus
32
32
  # Between all those, tags b,c,d and e are equal, meaning they all use
33
33
  # the same spot in Hash or wherever else.
34
34
  #
35
- # @param [String] tag name
35
+ # @param [String] name tag name
36
36
  # @param [Hash] options
37
37
  # @option options [String] :package_name owner package name
38
38
  # @option options [Jsus::Package] :package :owner package
@@ -1,11 +1,13 @@
1
1
  module Jsus
2
2
  # Utility namespace.
3
3
  module Util
4
+ autoload :Compressor, 'jsus/util/compressor'
4
5
  autoload :Tree, 'jsus/util/tree'
5
6
  autoload :Documenter, 'jsus/util/documenter'
6
7
  autoload :Validator, 'jsus/util/validator'
7
8
  autoload :Inflection, 'jsus/util/inflection'
8
9
  autoload :FileCache, 'jsus/util/file_cache'
9
10
  autoload :CodeGenerator, 'jsus/util/code_generator'
11
+ autoload :Logger, 'jsus/util/logger'
10
12
  end # Util
11
13
  end # Jsus
@@ -3,6 +3,7 @@ module Jsus
3
3
  # Code generation routines.
4
4
  module CodeGenerator
5
5
  class <<self
6
+ # @param [Array] paths list of paths
6
7
  # @return [String] javascript for includes for a list of given paths
7
8
  # @api public
8
9
  def generate_includes(paths)
@@ -0,0 +1,21 @@
1
+ module Jsus
2
+ module Util
3
+ class Compressor
4
+ attr_reader :result
5
+ def initialize(source, options = {}) # todo - non-java compressor
6
+ @result = compress_with_yui(source)
7
+ end # initialize
8
+
9
+ def compress_with_yui(source)
10
+ begin
11
+ require 'yui/compressor'
12
+ compressor = YUI::JavaScriptCompressor.new(:munge => true)
13
+ compressed_content = compressor.compress(source)
14
+ rescue LoadError
15
+ Jsus.logger.fatal 'ERROR: You need "yui-compressor" gem in order to use --compress option'
16
+ end
17
+ compressed_content
18
+ end # compress_with_yui
19
+ end # class Compressor
20
+ end # module Util
21
+ end # module Jsus
@@ -24,7 +24,7 @@ module Jsus
24
24
 
25
25
  # Generates documentation tree into the given directory.
26
26
  #
27
- # @param [String] output directory
27
+ # @param [String] doc_dir output directory
28
28
  # @api public
29
29
  def generate(doc_dir = Dir.pwd)
30
30
  #FileUtils.rm_rf(doc_dir)
@@ -49,7 +49,7 @@ module Jsus
49
49
 
50
50
  # Adds a source file to the documented source tree
51
51
  #
52
- # @param [Jsus::SourceFile] pushed source
52
+ # @param [Jsus::SourceFile] source pushed source
53
53
  # @api public
54
54
  def <<(source) # :nodoc:
55
55
  filename = File.basename(source.filename)
@@ -88,7 +88,7 @@ module Jsus
88
88
 
89
89
  # Sets documenter to exclusive scope for documentation.
90
90
  # Exclusive scope overrides all the other scopes.
91
- # @param [Array, String] documentation scope
91
+ # @param [Array, String] scope documentation scope
92
92
  # @api public
93
93
  def only(scope)
94
94
  result = clone
@@ -99,7 +99,7 @@ module Jsus
99
99
  # Sets documenter to additive scope for documentation.
100
100
  # Additive scopes match any of the pathspecs given
101
101
  #
102
- # @param [Array, String] documentation scope
102
+ # @param [Array, String] scope documentation scope
103
103
  # @api public
104
104
  def or(scope)
105
105
  result = clone
@@ -56,11 +56,10 @@ module Jsus
56
56
 
57
57
  # Generates path by cache key.
58
58
  #
59
- # Default strategy: append key to cache directory
60
- # (slashes are replaced with dots)
59
+ # Default strategy: relative path references via ../ are escaped.
61
60
  # @api private
62
61
  def generate_path(key)
63
- key = key.gsub(File::SEPARATOR, ".")
62
+ key = key.gsub(%r{(^|/)\.\./}, ".")
64
63
  File.join(@path, key)
65
64
  end # generate_path
66
65
  end # class FileCache
@@ -0,0 +1,35 @@
1
+ require 'logger'
2
+ module Jsus
3
+ module Util
4
+ # Extension of ruby logger allowing for message buffering.
5
+ class Logger < ::Logger
6
+ module Buffering
7
+ # Buffer storing logged messages
8
+ def buffer
9
+ @buffer ||= []
10
+ end # buffer
11
+
12
+ def buffer=(value)
13
+ @buffer = value
14
+ end # buffer=
15
+
16
+ def add(severity, message = nil, progname = nil, &block)
17
+ unless @logdev.nil? or severity < @level
18
+ if message.nil?
19
+ if block_given?
20
+ message = yield
21
+ else
22
+ message = progname
23
+ progname = @progname
24
+ end
25
+ end
26
+ buffer << [severity, message]
27
+ end
28
+ super
29
+ end # add
30
+ end # module Buffering
31
+
32
+ include Buffering
33
+ end # class Logger
34
+ end # module Util
35
+ end # module Jsus
@@ -57,6 +57,9 @@ module Jsus
57
57
  attr_accessor :path_components
58
58
 
59
59
  # Initializes full path and value for the node
60
+ # @param [String] full_path full path to node
61
+ # @param [Object] value
62
+ # @api public
60
63
  def initialize(full_path, value = nil)
61
64
  self.full_path = full_path
62
65
  self.value = value
@@ -81,7 +84,7 @@ module Jsus
81
84
  @children ||= []
82
85
  end
83
86
 
84
- # @param [String] basename
87
+ # @param [String] name basename
85
88
  # @return [Jsus::Util::Tree::Node] direct node child with given basename
86
89
  # @api public
87
90
  def find_child(name)
@@ -89,7 +92,7 @@ module Jsus
89
92
  end
90
93
 
91
94
  # Creates a child with given name and value
92
- # @param [String] node name
95
+ # @param [String] name node name
93
96
  # @param [Object] value
94
97
  # @return [Jsus::Util::Tree::Node]
95
98
  # @api public
@@ -18,7 +18,8 @@ module Jsus
18
18
  end
19
19
  alias_method :sources, :source_files
20
20
 
21
- # @param [Jsus::Pool, Jsus::Container, Array] source files for validation
21
+ # @param [Jsus::Pool, Jsus::Container, Array] pool_or_array_or_container
22
+ # source files for validation
22
23
  # @api public
23
24
  def source_files=(pool_or_array_or_container)
24
25
  case pool_or_array_or_container
@@ -45,7 +46,7 @@ module Jsus
45
46
  end
46
47
 
47
48
  # Shortcut for creating and validating a list of items
48
- # @param [*Array] args for #new
49
+ # @param [*Array] args passed to #new
49
50
  # @api public
50
51
  def self.validate(*args)
51
52
  new(*args).validate
@@ -13,4 +13,12 @@ authors:
13
13
  provides: [Core]
14
14
 
15
15
  ...
16
- */
16
+ */
17
+
18
+ //<ltIE8>
19
+ var IE7 = true;
20
+ //</ltIE8>
21
+
22
+ //<1.2compat>
23
+ var compatibilityMode = true;
24
+ //</1.2compat>
@@ -0,0 +1,17 @@
1
+ /*
2
+ ---
3
+
4
+ script: Widget.js
5
+
6
+ description: An abstract class for all your widgets out there.
7
+
8
+ license: MIT-style license
9
+
10
+ authors:
11
+ - Mark Abramov
12
+
13
+ requires: [MissingDependency]
14
+ provides: [Widget]
15
+
16
+ ...
17
+ */
@@ -0,0 +1,9 @@
1
+ name: Package
2
+ filename: package.js
3
+ web: http://github.com/jsus/jsus
4
+ description: "Package with a missing dependency, raises an error"
5
+ license: MIT-Style License, http://mootools.net/license
6
+ copyright: "Mark Abramov"
7
+ authors: "Mark Abramov"
8
+ sources:
9
+ - "Source/Widget.js"
@@ -7,6 +7,8 @@ describe Jsus::Middleware do
7
7
  def new_server
8
8
  Sinatra.new do
9
9
  use Jsus::Middleware
10
+ Jsus.logger = Jsus::Util::Logger.new('/dev/null')
11
+ Jsus.verbose = true
10
12
  set :port, 4567
11
13
  set :raise_errors, true
12
14
  set :show_exceptions, false
@@ -24,6 +26,7 @@ describe Jsus::Middleware do
24
26
  before(:all) do
25
27
  @server = new_server
26
28
  @server_thread = Thread.new { suppress_output { @server.run! } }
29
+ Jsus::Middleware.settings = {:cache_pool => false}
27
30
  end
28
31
 
29
32
  after(:all) { @server_thread.kill }
@@ -256,14 +259,85 @@ describe Jsus::Middleware do
256
259
  end
257
260
 
258
261
  describe "caching" do
262
+ let(:packages_dir) { File.expand_path("spec/data/ComplexDependencies") }
259
263
  let(:cache_path) { "spec/tmp" }
260
- before(:each) { Jsus::Middleware.settings = {:cache => true, :cache_path => cache_path} }
264
+ before(:each) { Jsus::Middleware.settings = {:cache => true, :cache_path => cache_path, :packages_dir => packages_dir} }
261
265
  after(:each) { FileUtils.rm_rf(cache_path) }
262
266
  let(:path) { "/javascripts/jsus/require/Package.js" }
263
267
  it "should save output of requests to files" do
264
268
  result = get(path).body
265
- File.exists?("#{cache_path}/Package.js").should be_true
266
- File.read("#{cache_path}/Package.js").should == result
269
+ File.exists?("#{cache_path}/require/Package.js").should be_true
270
+ File.read("#{cache_path}/require/Package.js").should == result
271
+ end
272
+
273
+ it "should not allow relative file paths hacks" do
274
+ FileUtils.rm_f("/tmp/testzor")
275
+ new_path = path + "/../../../../../../../../../../../../../../../tmp/testzor"
276
+ result = get(new_path).body
277
+ File.exists?("/tmp/testzor").should be_false
267
278
  end
268
279
  end
280
+
281
+ describe "post processing" do
282
+ let(:packages_dir) { File.expand_path("spec/data/ComplexDependencies") }
283
+ before(:each) { Jsus::Middleware.settings = {:packages_dir => packages_dir} }
284
+ let("path") { "/javascripts/jsus/require/Package.js" }
285
+ it "should not do anything if postprocs setting is empty" do
286
+ Jsus::Middleware.settings = {:postproc => []}
287
+ get(path).body.should include("//<ltIE8>")
288
+ end
289
+
290
+ it "should not do anything if postprocs setting is nil" do
291
+ Jsus::Middleware.settings = {:postproc => nil}
292
+ get(path).body.should include("//<ltIE8>")
293
+ end
294
+
295
+ it "should remove <ltIE8> tags if postproc setting contains mooltIE8" do
296
+ get(path).body.should include("//<ltIE8>")
297
+ Jsus::Middleware.settings = {:postproc => "mooltIE8"}
298
+ get(path).body.should_not include("//<ltIE8>")
299
+ end
300
+
301
+ it "should remove <1.2compat> tags if postproc setting contains moocompat12" do
302
+ get(path).body.should include("//<1.2compat>")
303
+ Jsus::Middleware.settings = {:postproc => "moocompat12"}
304
+ get(path).body.should_not include("//<1.2compat>")
305
+ end
306
+ end # describe "post processing"
307
+
308
+ describe "errors logging" do
309
+ let(:packages_dir) { File.expand_path("spec/data/MissingDependencies") }
310
+ before(:each) { Jsus::Middleware.settings = {:packages_dir => packages_dir} }
311
+
312
+ let(:path) { "/javascripts/jsus/require/Package.js" }
313
+ context "by default" do
314
+ it "should not output errors" do
315
+ output = get(path).body
316
+ output.should_not include("console.log")
317
+ output.should_not include("alert")
318
+ output.should_not include("document.body.innerHTML")
319
+ end
320
+ end # context "by default"
321
+
322
+ context "with console log method" do
323
+ before(:each) { Jsus::Middleware.settings = {:log_method => [:console] } }
324
+ it "should output errors to js console" do
325
+ get(path).body.should include("console.log")
326
+ end
327
+ end # context "with console log method"
328
+
329
+ context "with alert method" do
330
+ before(:each) { Jsus::Middleware.settings = {:log_method => [:alert] } }
331
+ it "should output errors via js alerts" do
332
+ get(path).body.should include("alert")
333
+ end
334
+ end # context "with console log method"
335
+
336
+ context "with html method" do
337
+ before(:each) { Jsus::Middleware.settings = {:log_method => [:html] } }
338
+ it "should output errors via html modification" do
339
+ get(path).body.should include("document.body.innerHTML")
340
+ end
341
+ end # context "with console log method"
342
+ end # describe "errors logging"
269
343
  end
@@ -20,6 +20,13 @@ describe Jsus::Util::FileCache do
20
20
  fn = subject.write(key, value)
21
21
  File.exists?("/tmp/test").should be_false
22
22
  end
23
+
24
+ it "should allow creation of subfolders" do
25
+ key = "test/hello"
26
+ fn = subject.write(key, value)
27
+ File.exists?("#{cache_dir}/#{key}").should be_true
28
+ File.read("#{cache_dir}/#{key}").should == value
29
+ end
23
30
  end
24
31
 
25
32
  describe "#read" do
@@ -37,6 +44,11 @@ describe Jsus::Util::FileCache do
37
44
  File.open("/tmp/test", "w+") {|f| f.puts "Hello, world!" }
38
45
  subject.read(key).should == nil
39
46
  end
47
+
48
+ it "should allow to read from subfolders" do
49
+ fn = subject.write("test/hello", value)
50
+ subject.read("test/hello").should == fn
51
+ end
40
52
  end
41
53
 
42
54
  describe "#fetch" do
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Jsus::Util::Logger do
4
+ subject { described_class.new("/dev/null") }
5
+
6
+ context "buffering" do
7
+ it "should store incoming messages in the buffer" do
8
+ subject.info "Something happened"
9
+ subject.buffer.should == [[Logger::INFO, "Something happened"]]
10
+ end
11
+
12
+ it "should not store messages not crossing the threshold" do
13
+ subject.level = Logger::FATAL
14
+ subject.info "Something happened"
15
+ subject.buffer.should == []
16
+ end
17
+
18
+ it "should allow block form logging" do
19
+ subject.info { "Something happened" }
20
+ subject.buffer.should == [[Logger::INFO, "Something happened"]]
21
+ end
22
+ end # context "buffering"
23
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsus
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 27
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 3
9
- - 3
10
- version: 0.3.3
9
+ - 4
10
+ version: 0.3.4
11
11
  platform: ruby
12
12
  authors:
13
13
  - Mark Abramov
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-06-19 00:00:00 +04:00
18
+ date: 2011-08-30 00:00:00 +04:00
19
19
  default_executable: jsus
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -325,9 +325,11 @@ files:
325
325
  - lib/jsus/tag.rb
326
326
  - lib/jsus/util.rb
327
327
  - lib/jsus/util/code_generator.rb
328
+ - lib/jsus/util/compressor.rb
328
329
  - lib/jsus/util/documenter.rb
329
330
  - lib/jsus/util/file_cache.rb
330
331
  - lib/jsus/util/inflection.rb
332
+ - lib/jsus/util/logger.rb
331
333
  - lib/jsus/util/tree.rb
332
334
  - lib/jsus/util/validator.rb
333
335
  - lib/jsus/util/validator/base.rb
@@ -387,6 +389,8 @@ files:
387
389
  - spec/data/JsonPackage/Source/SheetParser.CSS.js
388
390
  - spec/data/JsonPackage/Source/sg-regex-tools.js
389
391
  - spec/data/JsonPackage/package.json
392
+ - spec/data/MissingDependencies/Source/Widget.js
393
+ - spec/data/MissingDependencies/package.yml
390
394
  - spec/data/MooforgeValidation/README
391
395
  - spec/data/MooforgeValidation/app/javascripts/Orwik/Source/Library/InvalidNoAuthors.js
392
396
  - spec/data/MooforgeValidation/app/javascripts/Orwik/Source/Library/InvalidNoLicense.js
@@ -421,6 +425,7 @@ files:
421
425
  - spec/jsus/util/documenter_spec.rb
422
426
  - spec/jsus/util/file_cache_spec.rb
423
427
  - spec/jsus/util/inflection_spec.rb
428
+ - spec/jsus/util/logger_spec.rb
424
429
  - spec/jsus/util/tree_spec.rb
425
430
  - spec/jsus/util/validator/base_spec.rb
426
431
  - spec/jsus/util/validator/mooforge_spec.rb