jsus 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
data/.document CHANGED
@@ -1,5 +1,5 @@
1
1
  lib/**/*.rb
2
2
  bin/*
3
- -
3
+ -
4
4
  features/**/*.feature
5
5
  LICENSE.txt
data/.travis.yml CHANGED
@@ -1,4 +1,4 @@
1
- script: "rake"
1
+ script: "bundle exec rake"
2
2
  rvm:
3
3
  - 1.8.7
4
4
  - 1.9.2
data/.yardopts ADDED
@@ -0,0 +1,9 @@
1
+ --markup="markdown" lib/**/*.rb
2
+ --no-private
3
+ --no-protected
4
+ --main README.md
5
+ --hide-tag todo
6
+ -
7
+ LICENSE
8
+ CHANGELOG
9
+ docs/*.textile
data/CHANGELOG CHANGED
@@ -1,4 +1,25 @@
1
1
  = Jsus Changelog
2
+ == Version 0.3.2
3
+ Middleware changes:
4
+ * Fixed minor problem with middleware when package name and source file tag
5
+ are the same
6
+ * Settings are now shared between Jsus::Middleware and subclasses
7
+ * Middleware now also supports /include/ directive (generates includes file),
8
+ like -g option of CLI utility
9
+ * Hack for cache output paths to be recognizable by nginx
10
+
11
+ CLI changes:
12
+ * --very-verbose mode, outputs tree of your packages, very useful when debugging
13
+ missing dependencies.
14
+ * If you have circular dependencies in your code, jsus will detect them and issue
15
+ a huge warning message (WIP)
16
+
17
+ Shared changes:
18
+ * Pool instantiation will now follow symlinks one level deep
19
+ * Somewhat easier on eyes murdoc template
20
+ * Pool instantiation now also accepts array of directories as its argument
21
+ * YARD docs are now the default docs choice
22
+
2
23
  == Version 0.3.1
3
24
  * Added wildcard support for Jsus::Middleware
4
25
 
data/Gemfile CHANGED
@@ -6,7 +6,7 @@ gem "json_pure"
6
6
  gem "rgl"
7
7
 
8
8
  group :development do
9
- gem "bundler"
9
+ gem "rake"
10
10
  gem "rspec"
11
11
  gem "cucumber"
12
12
  gem "jeweler"
@@ -17,4 +17,5 @@ group :development do
17
17
  gem 'yui-compressor'
18
18
  gem 'sinatra'
19
19
  gem 'rack-test'
20
- end
20
+ gem 'yard'
21
+ end
@@ -9,7 +9,7 @@ Why?
9
9
  As a javascript programmer, you often need to split your code into
10
10
  multiple files. When you have 50+ different modules / libraries, you
11
11
  need some way to resolve complex dependencies and package all you need
12
- and nil you don't. Jsus is an utility that allows you to do just that:
12
+ and nil you don't. Jsus is an utility that allows you to do just that:
13
13
  package your libraries into one piece with all dependencies included.
14
14
 
15
15
  Features
@@ -21,17 +21,17 @@ Features
21
21
  headers denoting their requirements and what they provide.
22
22
  * Jsus automatically resolves dependencies, so you don't have to worry about
23
23
  order issues or anything else.
24
- * Jsus allows you to make "extensions". Extension is a monkey-patch you can
24
+ * Jsus allows you to make "extensions". Extension is a monkey-patch you can
25
25
  apply to any other library. Because sometimes you want to make project-specific
26
26
  change to a library you don't have control over and you want to be able to
27
27
  update this library without applying manual patches from their source.
28
- * Jsus uses [murdoc](https://github.com/markiz/murdoc) for doccu style docs
28
+ * Jsus uses [murdoc](https://github.com/markiz/murdoc) for doccu style docs
29
29
  generation.
30
30
  * Jsus generates special json files denoting source and resulting project
31
31
  structure which can be useful for later introspection.
32
32
  * Jsus can also generate a special js file with loader for your dependencies,
33
33
  so that you don't need to repackage everything during development cycle.
34
-
34
+
35
35
  Examples
36
36
  ========
37
37
 
@@ -42,6 +42,12 @@ Examples
42
42
  * `jsus . Output`
43
43
  * Look at what Output directory contains
44
44
 
45
+ Using with Rails / Sinatra / Whatever
46
+ =====================================
47
+
48
+ Jsus comes with a middleware in its backpack. See [rails example](https://github.com/jsus/jsus-rails-app)
49
+ and [sinatra example](https://github.com/jsus/jsus-sinatra-app).
50
+
45
51
  Plans
46
52
  =====
47
53
 
data/TODO CHANGED
@@ -1,3 +1 @@
1
- * Disallow circular dependencies
2
- * Rails integration
3
- * Cleanup jsus utility
1
+ * Disallow circular dependencies (mostly done)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.1
1
+ 0.3.2
data/bin/jsus CHANGED
@@ -77,6 +77,11 @@ module Jsus
77
77
  Jsus.verbose = true
78
78
  end
79
79
 
80
+ opts.on_tail('--very-verbose', 'very verbose mode, shows pool stats beside usual verbose stuff') do
81
+ Jsus.verbose = true
82
+ options[:display_pool_stats] = true
83
+ end
84
+
80
85
  opts.on_tail('-b', '--benchmark', 'shows time spent on various stages') do
81
86
  options[:benchmark] = true
82
87
  end
@@ -192,6 +197,7 @@ module Jsus
192
197
  setup_output_directory
193
198
  preload_pool
194
199
  load_package
200
+ display_pool_stats if options[:display_pool_stats]
195
201
  compile_package
196
202
  post_process if options[:postproc]
197
203
  compress_package if options[:compress]
@@ -224,6 +230,30 @@ module Jsus
224
230
  checkpoint(:dependencies)
225
231
  end
226
232
 
233
+ def display_pool_stats
234
+ checkpoint(:pool_stats)
235
+ puts ""
236
+ puts "Pool stats:"
237
+ puts ""
238
+ puts "Main package:"
239
+ display_package @package
240
+ puts "Supplementary packages:"
241
+ @pool.packages.each do |package|
242
+ display_package package
243
+ end
244
+ puts ""
245
+ end
246
+
247
+ def display_package(package)
248
+ puts "Package: #{package.name}"
249
+ package.source_files.to_a.sort_by {|sf| sf.filename}.each do |sf|
250
+ puts " [#{sf.relative_filename}]"
251
+ puts " Provides: [#{sf.provides_names.join(", ")}]"
252
+ puts " Requires: [#{sf.requires_names.join(", ")}]"
253
+ end
254
+ puts ""
255
+ end
256
+
227
257
  def compile_package
228
258
  @package_content = @package.compile(nil)
229
259
  checkpoint(:compilation)
@@ -273,15 +303,8 @@ module Jsus
273
303
  includes_root = options[:includes_root] || @output_dir
274
304
  File.open(File.join(@output_dir, "includes.js"), "w") do |f|
275
305
  c = Jsus::Container.new(*(@package.source_files.to_a + @package.linked_external_dependencies.to_a))
276
- script = %{
277
- (function(prefix, loader) {
278
- var sources = %sources%;
279
- if (!loader) loader = function(path) {
280
- document.write('<scr' + 'ipt src="' + (prefix || '') + path + '"></script>');
281
- }
282
- for (var i = 0, j = sources.length; i < j; i++) loader(sources[i]);
283
- })(window.prefix, window.loader);}.sub("%sources%", JSON.pretty_generate(c.required_files(includes_root)))
284
- f.puts script
306
+ paths = c.required_files(includes_root)
307
+ f.puts Jsus::Util::CodeGenerator.generate_includes(paths)
285
308
  end
286
309
  checkpoint(:includes)
287
310
  end
@@ -354,4 +377,4 @@ module Jsus
354
377
  end
355
378
  end
356
379
 
357
- Jsus::CLI.run!
380
+ Jsus::CLI.run!
data/jsus.gemspec CHANGED
@@ -5,27 +5,28 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{jsus}
8
- s.version = "0.3.1"
8
+ s.version = "0.3.2"
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-05-19}
12
+ s.date = %q{2011-06-19}
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}
16
16
  s.executables = ["jsus"]
17
17
  s.extra_rdoc_files = [
18
- "README",
18
+ "README.md",
19
19
  "TODO"
20
20
  ]
21
21
  s.files = [
22
22
  ".document",
23
23
  ".rspec",
24
24
  ".travis.yml",
25
+ ".yardopts",
25
26
  "CHANGELOG",
26
27
  "Gemfile",
27
28
  "Manifest",
28
- "README",
29
+ "README.md",
29
30
  "Rakefile",
30
31
  "TODO",
31
32
  "UNLICENSE",
@@ -102,6 +103,7 @@ Gem::Specification.new do |s|
102
103
  "lib/jsus/source_file.rb",
103
104
  "lib/jsus/tag.rb",
104
105
  "lib/jsus/util.rb",
106
+ "lib/jsus/util/code_generator.rb",
105
107
  "lib/jsus/util/documenter.rb",
106
108
  "lib/jsus/util/file_cache.rb",
107
109
  "lib/jsus/util/inflection.rb",
@@ -217,7 +219,7 @@ Gem::Specification.new do |s|
217
219
  s.add_runtime_dependency(%q<activesupport>, [">= 0"])
218
220
  s.add_runtime_dependency(%q<json_pure>, [">= 0"])
219
221
  s.add_runtime_dependency(%q<rgl>, [">= 0"])
220
- s.add_development_dependency(%q<bundler>, [">= 0"])
222
+ s.add_development_dependency(%q<rake>, [">= 0"])
221
223
  s.add_development_dependency(%q<rspec>, [">= 0"])
222
224
  s.add_development_dependency(%q<cucumber>, [">= 0"])
223
225
  s.add_development_dependency(%q<jeweler>, [">= 0"])
@@ -228,11 +230,12 @@ Gem::Specification.new do |s|
228
230
  s.add_development_dependency(%q<yui-compressor>, [">= 0"])
229
231
  s.add_development_dependency(%q<sinatra>, [">= 0"])
230
232
  s.add_development_dependency(%q<rack-test>, [">= 0"])
233
+ s.add_development_dependency(%q<yard>, [">= 0"])
231
234
  else
232
235
  s.add_dependency(%q<activesupport>, [">= 0"])
233
236
  s.add_dependency(%q<json_pure>, [">= 0"])
234
237
  s.add_dependency(%q<rgl>, [">= 0"])
235
- s.add_dependency(%q<bundler>, [">= 0"])
238
+ s.add_dependency(%q<rake>, [">= 0"])
236
239
  s.add_dependency(%q<rspec>, [">= 0"])
237
240
  s.add_dependency(%q<cucumber>, [">= 0"])
238
241
  s.add_dependency(%q<jeweler>, [">= 0"])
@@ -243,12 +246,13 @@ Gem::Specification.new do |s|
243
246
  s.add_dependency(%q<yui-compressor>, [">= 0"])
244
247
  s.add_dependency(%q<sinatra>, [">= 0"])
245
248
  s.add_dependency(%q<rack-test>, [">= 0"])
249
+ s.add_dependency(%q<yard>, [">= 0"])
246
250
  end
247
251
  else
248
252
  s.add_dependency(%q<activesupport>, [">= 0"])
249
253
  s.add_dependency(%q<json_pure>, [">= 0"])
250
254
  s.add_dependency(%q<rgl>, [">= 0"])
251
- s.add_dependency(%q<bundler>, [">= 0"])
255
+ s.add_dependency(%q<rake>, [">= 0"])
252
256
  s.add_dependency(%q<rspec>, [">= 0"])
253
257
  s.add_dependency(%q<cucumber>, [">= 0"])
254
258
  s.add_dependency(%q<jeweler>, [">= 0"])
@@ -259,6 +263,7 @@ Gem::Specification.new do |s|
259
263
  s.add_dependency(%q<yui-compressor>, [">= 0"])
260
264
  s.add_dependency(%q<sinatra>, [">= 0"])
261
265
  s.add_dependency(%q<rack-test>, [">= 0"])
266
+ s.add_dependency(%q<yard>, [">= 0"])
262
267
  end
263
268
  end
264
269
 
data/lib/jsus.rb CHANGED
@@ -11,10 +11,7 @@ require 'fileutils'
11
11
  require 'pathname'
12
12
 
13
13
  #
14
- # Jsus -- a library for packaging up your source files.
15
- #
16
- # For better understanding of jsus ideas start with http://github.com/Markiz/jsus-examples
17
- #
14
+ # Jsus -- your better javascript packager.
18
15
  #
19
16
  module Jsus
20
17
  autoload :SourceFile, 'jsus/source_file'
@@ -26,19 +23,44 @@ module Jsus
26
23
  autoload :Util, 'jsus/util'
27
24
  autoload :Middleware, 'jsus/middleware'
28
25
 
29
- # Returns whether or not jsus is in verbose mode
26
+ # In verbose mode jsus shows a lot of warnings like missing dependencies.
27
+ # Default: false
28
+ #
29
+ # @return [Boolean] jsus verbosity mode
30
+ # @api public
30
31
  def self.verbose?
31
32
  !!@verbose
32
33
  end
33
34
 
34
- # Sets verbose mode to on. In verbose mode jsus shows a lot of warnings
35
- # like missing dependencies.
35
+ # @see .verbose?
36
+ # @param [Boolean] verbose verbose verbosity mode
37
+ # @api public
36
38
  def self.verbose=(verbose)
37
39
  @verbose = verbose
38
40
  end
39
41
 
40
- # Returns current version
42
+ # @return [String] Jsus version
43
+ # @api public
41
44
  def self.version
42
45
  @version ||= File.read(File.dirname(__FILE__) + "/../VERSION")
43
46
  end
44
- end
47
+
48
+
49
+ # Circular dependencies cannot be resolved and lead to "impossible"
50
+ # situations and problems, like missing source files or incorrect ordering.
51
+ #
52
+ # However, checking for cycles is quite computationally expensive, which
53
+ # is why you may want to disable it in production mode.
54
+ #
55
+ # @return [Boolean]
56
+ # @api public
57
+ def self.look_for_cycles?
58
+ @look_for_cycles == nil ? true : @look_for_cycles
59
+ end
60
+
61
+ # @see .look_for_cycles?
62
+ # @param [Boolean]
63
+ def self.look_for_cycles=(value)
64
+ @look_for_cycles = value
65
+ end
66
+ end
@@ -4,10 +4,12 @@ module Jsus
4
4
  # from an array is the fact that container maintains topological
5
5
  # sort for the source files.
6
6
  #
7
+ # This class is mostly used internally.
8
+ #
7
9
  class Container
10
+ # Instantiates a container from given sources.
8
11
  #
9
- # Every argument for initializer is pushed into the container.
10
- #
12
+ # @param [SourceFile]
11
13
  def initialize(*sources)
12
14
  sources.each do |source|
13
15
  push(source)
@@ -16,7 +18,9 @@ module Jsus
16
18
 
17
19
  # Public API
18
20
 
19
- # Pushes an item to container
21
+ # Pushes an item to the container
22
+ #
23
+ # @param [SourceFile] source pushed file
20
24
  def push(source)
21
25
  if source
22
26
  if source.kind_of?(Array) || source.kind_of?(Container)
@@ -30,7 +34,9 @@ module Jsus
30
34
  end
31
35
  alias_method :<<, :push
32
36
 
33
- # Flattens the container items.
37
+ # Flattens the container items
38
+ #
39
+ # @return [Array]
34
40
  def flatten
35
41
  map {|item| item.respond_to?(:flatten) ? item.flatten : item }.flatten
36
42
  end
@@ -38,16 +44,25 @@ module Jsus
38
44
  # Contains the source files. Please, don't use sources directly, if you
39
45
  # depend on them to be topologically sorted. Use collection methods like
40
46
  # inject/reject/map directly on the container instead.
47
+ #
48
+ # @return [Array]
49
+ # @api semipublic
41
50
  def sources
42
51
  @sources ||= []
43
52
  end
44
53
  alias_method :to_a, :sources
45
54
 
55
+ # Sets sources to new value.
56
+ #
57
+ # @api semipublic
46
58
  def sources=(new_value) # :nodoc:
47
59
  @sources = new_value
48
60
  end
49
61
 
50
- # Performs a sort and returns self.
62
+ # Topologically sorts items in container if required.
63
+ #
64
+ # @return [self]
65
+ # @api semipublic
51
66
  def sort!
52
67
  unless sorted?
53
68
  remove_replaced_files!
@@ -57,13 +72,24 @@ module Jsus
57
72
  self
58
73
  end
59
74
 
60
- # Returns whether collection is sorted already
75
+ # Returns whether container requires sorting.
76
+ #
77
+ # @return [Boolean]
78
+ # @api semipublic
61
79
  def sorted?
62
80
  !!@sorted
63
81
  end
64
82
 
65
83
  # Lists all the required files (dependencies and extensions) for
66
- # the sources in the container.
84
+ # the sources in the container. Consider it a projection from source files
85
+ # space onto filesystem space.
86
+ #
87
+ # Optionally accepts a filesystem point to calculate relative paths from.
88
+ #
89
+ # @param [String] root point from which the relative paths are calculated.
90
+ # When omitted, full paths are returned.
91
+ # @return [Array] ordered list of required files
92
+ # @api public
67
93
  def required_files(root = nil)
68
94
  sort!
69
95
  files = sources.map {|s| s.required_files }.flatten
@@ -74,13 +100,18 @@ module Jsus
74
100
  files
75
101
  end
76
102
 
77
- def inspect # :nodoc:
103
+ # Shows inspection of the container.
104
+ # @api public
105
+ def inspect
78
106
  "#<#{self.class.name}:#{self.object_id} #{self.sources.inspect}>"
79
107
  end
80
108
 
81
109
  # Private API
82
110
 
83
- def topsort # :nodoc:
111
+ # Performs topological sort inside current container.
112
+ #
113
+ # @api private
114
+ def topsort
84
115
  graph = RGL::DirectedAdjacencyGraph.new
85
116
  # init vertices
86
117
  items = sources
@@ -98,20 +129,46 @@ module Jsus
98
129
  end
99
130
  end
100
131
  result = []
132
+ if Jsus.look_for_cycles?
133
+ cycles = graph.cycles
134
+ 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:"
141
+ cycles.each do |cycle|
142
+ puts "-" * 30
143
+ puts (cycle + [cycle.first]).map {|sf| sf.filename}.join(" => ")
144
+ end
145
+ puts "*" * 30
146
+ end
147
+ end
101
148
  graph.topsort_iterator.each { |item| result << item }
102
149
  result
103
150
  end
104
151
 
105
- def dependency_cache # :nodoc:
152
+ # Cached map of dependencies pointing to source files.
153
+ # @return [Hash]
154
+ # @api private
155
+ def dependency_cache
106
156
  @dependency_cache ||= {}
107
157
  end
108
158
 
109
- def provides_tree # :nodoc:
159
+ # Cached tree of what source files provide.
160
+ #
161
+ # @api private
162
+ # @return [Jsus::Util::Tree]
163
+ def provides_tree
110
164
  @provides_tree ||= provides_tree!
111
165
  end
112
166
 
113
- # Provides tree contains
114
- def provides_tree! # :nodoc:
167
+ # Returns tree of what source files provide.
168
+ #
169
+ # @api private
170
+ # @return [Jsus::Util::Tree]
171
+ def provides_tree!
115
172
  tree = Util::Tree.new
116
173
  # Provisions
117
174
  sources.each do |file|
@@ -128,17 +185,28 @@ module Jsus
128
185
  tree
129
186
  end
130
187
 
131
- def remove_replaced_files! # :nodoc:
188
+ # Removes files which are marked as replaced by other sources.
189
+ #
190
+ # @api private
191
+ def remove_replaced_files!
132
192
  sources.reject! do |sf|
133
193
  !sf.provides.empty? && sf.provides.any? { |tag| replacements_tree[tag] && replacements_tree[tag] != sf }
134
194
  end
135
195
  end
136
196
 
137
- def replacements_tree # :nodoc:
197
+ # Cached tree of what source files replace.
198
+ #
199
+ # @api private
200
+ # @return [Jsus::Util::Tree]
201
+ def replacements_tree
138
202
  @replacements_tree ||= replacements_tree!
139
203
  end
140
204
 
141
- def replacements_tree! # :nodoc:
205
+ # Returns tree of what source files replace.
206
+ #
207
+ # @api private
208
+ # @return [Jsus::Util::Tree]
209
+ def replacements_tree!
142
210
  tree = Util::Tree.new
143
211
  sources.each do |file|
144
212
  if file.replaces
@@ -148,25 +216,29 @@ module Jsus
148
216
  tree
149
217
  end
150
218
 
151
- def clear_cache! # :nodoc:
219
+ # Clears all caches for given container.
220
+ #
221
+ # @api private
222
+ def clear_cache!
152
223
  @provides_tree = nil
153
224
  @replacements_tree = nil
154
225
  @dependency_cache = nil
155
226
  @sorted = false
156
227
  end
157
228
 
158
-
229
+ # List of methods that clear cached state of container when called.
159
230
  CACHE_CLEAR_METHODS = [
160
231
  "map!", "reject!", "inject!", "collect!", "delete", "delete_at"
161
- ] # :nodoc:
232
+ ]
162
233
 
234
+ # List of methods that are delegated to underlying array of sources.
163
235
  DELEGATED_METHODS = [
164
236
  "==", "to_a", "map", "map!", "each", "inject", "inject!",
165
- "collect", "collect!", "reject", "reject!", "detect", "size",
166
- "length", "[]", "empty?", "index", "include?", "select",
237
+ "collect", "collect!", "reject", "reject!", "detect", "size",
238
+ "length", "[]", "empty?", "index", "include?", "select",
167
239
  "delete_if", "delete", "-", "+", "|", "&"
168
- ] # :nodoc:
169
- # delegates most Enumerable methods to #sources
240
+ ]
241
+
170
242
  (DELEGATED_METHODS).each do |m|
171
243
  class_eval <<-EVAL
172
244
  def #{m}(*args, &block)
@@ -177,4 +249,4 @@ module Jsus
177
249
  EVAL
178
250
  end
179
251
  end
180
- end
252
+ end