jsduck 3.7.0 → 3.8.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -120,7 +120,9 @@ Thanks to [Ondřej Jirman](https://github.com/megous),
120
120
  [ligaard](https://github.com/ligaard),
121
121
  [Bill Hubbard](http://www.sencha.com/forum/member.php?272458-BillHubbard),
122
122
  [Ed Spencer](https://github.com/edspencer),
123
- [atian25](https://github.com/atian25) and many-many others who
123
+ [atian25](https://github.com/atian25),
124
+ Katherine Chu,
125
+ [Rob Dougan](https://github.com/rdougan) and many-many others who
124
126
  reported bugs, submitted patches, and provided a lot of useful input.
125
127
 
126
128
 
data/Rakefile CHANGED
@@ -13,7 +13,7 @@ end
13
13
 
14
14
  def load_sdk_vars
15
15
  if File.exists?("sdk-vars.rb")
16
- require "sdk-vars.rb"
16
+ require "./sdk-vars.rb"
17
17
  else
18
18
  puts "Error: sdk-vars.rb not found."
19
19
  puts
data/jsduck.gemspec CHANGED
@@ -2,8 +2,8 @@ Gem::Specification.new do |s|
2
2
  s.required_rubygems_version = ">= 1.3.5"
3
3
 
4
4
  s.name = 'jsduck'
5
- s.version = '3.7.0'
6
- s.date = '2012-02-29'
5
+ s.version = '3.8.0'
6
+ s.date = '2012-03-15'
7
7
  s.summary = "Simple JavaScript Duckumentation generator"
8
8
  s.description = "Documentation generator for Sencha JS frameworks"
9
9
  s.homepage = "https://github.com/senchalabs/jsduck"
data/lib/jsduck/app.rb CHANGED
@@ -10,6 +10,7 @@ require 'jsduck/parallel_wrap'
10
10
  require 'jsduck/logger'
11
11
  require 'jsduck/assets'
12
12
  require 'jsduck/json_duck'
13
+ require 'jsduck/io'
13
14
  require 'jsduck/lint'
14
15
  require 'jsduck/template_dir'
15
16
  require 'jsduck/class_writer'
@@ -81,7 +82,7 @@ module JsDuck
81
82
  def parallel_parse(filenames)
82
83
  @parallel.map(filenames) do |fname|
83
84
  Logger.instance.log("Parsing", fname)
84
- SourceFile.new(IO.read(fname), fname, @opts)
85
+ SourceFile.new(JsDuck::IO.read(fname), fname, @opts)
85
86
  end
86
87
  end
87
88
 
@@ -22,7 +22,7 @@ module JsDuck
22
22
  :guides => @assets.guides.to_array,
23
23
  :videos => @assets.videos.to_array,
24
24
  :examples => @assets.examples.to_array,
25
- :search => SearchData.new.create(@relations.classes),
25
+ :search => SearchData.new.create(@relations.classes, @assets),
26
26
  :stats => @opts.stats ? Stats.new.create(@relations.classes) : [],
27
27
  :signatures => MetaTagRegistry.instance.signatures,
28
28
  :localStorageDb => @opts.local_storage_db,
data/lib/jsduck/class.rb CHANGED
@@ -178,7 +178,7 @@ module JsDuck
178
178
  end
179
179
 
180
180
  # merges second members hash into first one
181
- def merge!(hash1, hash2)
181
+ def merge!(hash1, hash2, skip_overrides=false)
182
182
  hash2.each_pair do |name, m|
183
183
  if m[:meta] && m[:meta][:hide]
184
184
  if hash1[name]
@@ -210,7 +210,18 @@ module JsDuck
210
210
  # this, ignore overriding itself.
211
211
  if new[:owner] != old[:owner]
212
212
  new[:overrides] = [] unless new[:overrides]
213
- new[:overrides] << old unless new[:overrides].any? {|m| m[:owner] == old[:owner] }
213
+ unless new[:overrides].any? {|m| m[:owner] == old[:owner] }
214
+ # Make a copy of the important properties for us. We can't
215
+ # just push the actual `old` member itself, because there
216
+ # can be circular overrides (notably with Ext.Base), which
217
+ # will result in infinite loop when we try to convert our
218
+ # class into JSON.
219
+ new[:overrides] << {
220
+ :name => old[:name],
221
+ :owner => old[:owner],
222
+ :id => old[:id],
223
+ }
224
+ end
214
225
  end
215
226
  end
216
227
 
@@ -1,8 +1,11 @@
1
+ # -*- coding: utf-8 -*-
1
2
  require 'rubygems'
2
3
  require 'rdiscount'
3
4
  require 'strscan'
4
5
  require 'cgi'
5
6
  require 'jsduck/logger'
7
+ require 'jsduck/inline_img'
8
+ require 'jsduck/inline_video'
6
9
 
7
10
  module JsDuck
8
11
 
@@ -20,22 +23,6 @@ module JsDuck
20
23
  # Default value: '<a href="%c%M">%a</a>'
21
24
  attr_accessor :link_tpl
22
25
 
23
- # Template HTML that replaces {@img URL alt text}
24
- # Can contain placeholders:
25
- #
26
- # %u - URL from @img tag (e.g. "some/path.png")
27
- # %a - alt text for image
28
- #
29
- # Default value: '<img src="%u" alt="%a"/>'
30
- attr_accessor :img_tpl
31
-
32
- # This will hold list of all image paths gathered from {@img} tags.
33
- attr_accessor :images
34
-
35
- # Base path to prefix images from {@img} tags.
36
- # Defaults to no prefix.
37
- attr_accessor :img_path
38
-
39
26
  # Sets up instance to work in context of particular class, so
40
27
  # that when {@link #blah} is encountered it knows that
41
28
  # Context#blah is meant.
@@ -61,13 +48,26 @@ module JsDuck
61
48
  @max_length = 120
62
49
  @relations = relations
63
50
  @images = []
51
+
52
+ @inline_img = InlineImg.new(opts)
53
+ @inline_video = InlineVideo.new(opts)
54
+
64
55
  @link_tpl = opts[:link_tpl] || '<a href="%c%#%m">%a</a>'
65
- @img_tpl = opts[:img_tpl] || '<img src="%u" alt="%a"/>'
66
56
  @link_re = /\{@link\s+(\S*?)(?:\s+(.+?))?\}/m
67
- @img_re = /\{@img\s+(\S*?)(?:\s+(.+?))?\}/m
57
+
68
58
  @example_annotation_re = /<pre><code>\s*@example( +[^\n]*)?\s+/m
69
59
  end
70
60
 
61
+ # Sets base path to prefix images from {@img} tags.
62
+ def img_path=(path)
63
+ @inline_img.base_path = path
64
+ end
65
+
66
+ # Returns list of all image paths gathered from {@img} tags.
67
+ def images
68
+ @inline_img.images
69
+ end
70
+
71
71
  # Replaces {@link} and {@img} tags, auto-generates links for
72
72
  # recognized classnames.
73
73
  #
@@ -93,8 +93,10 @@ module JsDuck
93
93
  while !s.eos? do
94
94
  if s.check(@link_re)
95
95
  out += replace_link_tag(s.scan(@link_re))
96
- elsif s.check(@img_re)
97
- out += replace_img_tag(s.scan(@img_re))
96
+ elsif substitute = @inline_img.replace(s)
97
+ out += substitute
98
+ elsif substitute = @inline_video.replace(s)
99
+ out += substitute
98
100
  elsif s.check(/[{]/)
99
101
  # There might still be "{" that doesn't begin {@link} or {@img} - ignore it
100
102
  out += s.scan(/[{]/)
@@ -185,10 +187,6 @@ module JsDuck
185
187
  end
186
188
  end
187
189
 
188
- def replace_img_tag(input)
189
- input.sub(@img_re) { img($1, $2) }
190
- end
191
-
192
190
  # Looks input text for patterns like:
193
191
  #
194
192
  # My.ClassName
@@ -258,21 +256,6 @@ module JsDuck
258
256
  Logger.instance.warn(:link_auto, msg, @doc_context[:filename], @doc_context[:linenr])
259
257
  end
260
258
 
261
- # applies the image template
262
- def img(url, alt_text)
263
- @images << url
264
- @img_tpl.gsub(/(%\w)/) do
265
- case $1
266
- when '%u'
267
- @img_path ? (@img_path + "/" + url) : url
268
- when '%a'
269
- CGI.escapeHTML(alt_text||"")
270
- else
271
- $1
272
- end
273
- end
274
- end
275
-
276
259
  # applies the link template
277
260
  def link(cls, member, anchor_text, type=nil, static=false)
278
261
  # Use the canonical class name for link (not some alternateClassName)
@@ -345,21 +328,25 @@ module JsDuck
345
328
  #
346
329
  def shorten(input)
347
330
  sent = first_sentence(strip_tags(input))
348
- if sent.length > @max_length
349
- sent[0..(@max_length-4)] + "..."
331
+ # Use u-modifier to correctly count multi-byte characters
332
+ chars = sent.scan(/./mu)
333
+ if chars.length > @max_length
334
+ chars[0..(@max_length-4)].join + "..."
350
335
  else
351
336
  sent + " ..."
352
337
  end
353
338
  end
354
339
 
355
340
  def first_sentence(str)
356
- str.sub(/\A(.+?\.)\s.*\Z/m, "\\1")
341
+ str.sub(/\A(.+?(\.|。))\s.*\Z/mu, "\\1")
357
342
  end
358
343
 
359
344
  # Returns true when input should get shortened.
360
345
  def too_long?(input)
361
346
  stripped = strip_tags(input)
362
- first_sentence(stripped).length < stripped.length || stripped.length > @max_length
347
+ # for sentence v/s full - compare byte length
348
+ # for full v/s max - compare char length
349
+ first_sentence(stripped).length < stripped.length || stripped.scan(/./mu).length > @max_length
363
350
  end
364
351
 
365
352
  def strip_tags(str)
@@ -286,7 +286,9 @@ module JsDuck
286
286
  add_tag(:type)
287
287
  skip_horiz_white
288
288
  if look(/\{/)
289
- @current_tag[:type] = typedef
289
+ tdf = typedef
290
+ @current_tag[:type] = tdf[:type]
291
+ @current_tag[:optional] = true if tdf[:optional]
290
292
  elsif look(/\S/)
291
293
  @current_tag[:type] = @input.scan(/\S+/)
292
294
  end
@@ -354,10 +356,13 @@ module JsDuck
354
356
  end
355
357
 
356
358
  # matches {type} if possible and sets it on @current_tag
359
+ # Also checks for {optionality=} in type definition.
357
360
  def maybe_type
358
361
  skip_horiz_white
359
362
  if look(/\{/)
360
- @current_tag[:type] = typedef
363
+ tdf = typedef
364
+ @current_tag[:type] = tdf[:type]
365
+ @current_tag[:optional] = true if tdf[:optional]
361
366
  end
362
367
  end
363
368
 
@@ -431,12 +436,28 @@ module JsDuck
431
436
  end
432
437
  end
433
438
 
434
- # matches {...} and returns text inside brackets
439
+ # matches {...=} and returns text inside brackets
435
440
  def typedef
436
441
  match(/\{/)
437
- name = @input.scan(/[^}]+/)
442
+ name = @input.scan(/[^{}]*/)
443
+
444
+ # Type definition can contain nested braces: {{foo:Number}}
445
+ # In such case we parse the definition so that the braces are balanced.
446
+ while @input.check(/[{]/)
447
+ name += "{" + typedef[:type] +"}"
448
+ name += @input.scan(/[^{}]*/)
449
+ end
450
+
451
+ if name =~ /=$/
452
+ name = name.chop
453
+ optional = true
454
+ else
455
+ optional = nil
456
+ end
457
+
438
458
  match(/\}/)
439
- return name
459
+
460
+ return {:type => name, :optional => optional}
440
461
  end
441
462
 
442
463
  # matches <ident_chain> <ident_chain> ... until line end
data/lib/jsduck/guides.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'jsduck/logger'
2
2
  require 'jsduck/json_duck'
3
+ require 'jsduck/io'
3
4
  require 'jsduck/null_object'
4
5
  require 'jsduck/logger'
5
6
  require 'jsduck/grouped_asset'
@@ -51,7 +52,7 @@ module JsDuck
51
52
  @formatter.doc_context = {:filename => guide_file, :linenr => 0}
52
53
  name = File.basename(in_dir)
53
54
  @formatter.img_path = "guides/#{name}"
54
- html = add_toc(guide, @formatter.format(IO.read(guide_file)))
55
+ html = add_toc(guide, @formatter.format(JsDuck::IO.read(guide_file)))
55
56
 
56
57
  JsonDuck.write_jsonp(out_dir+"/README.js", name, {:guide => html, :title => guide["title"]})
57
58
  end
@@ -1,4 +1,5 @@
1
1
  require 'jsduck/logger'
2
+ require 'jsduck/io'
2
3
  require 'fileutils'
3
4
 
4
5
  module JsDuck
@@ -49,7 +50,7 @@ module JsDuck
49
50
  # Opens in_file, replaces {keys} inside it, writes to out_file
50
51
  def write_template(in_file, out_file, replacements)
51
52
  Logger.instance.log("Writing", out_file)
52
- html = IO.read(in_file)
53
+ html = JsDuck::IO.read(in_file)
53
54
  html.gsub!(/\{\w+\}/) do |key|
54
55
  replacements[key] ? replacements[key] : key
55
56
  end
@@ -0,0 +1,53 @@
1
+ require 'cgi'
2
+ require 'jsduck/logger'
3
+
4
+ module JsDuck
5
+
6
+ # Implementation of inline tag {@img}
7
+ class InlineImg
8
+ # Base path to prefix images from {@img} tags.
9
+ # Defaults to no prefix.
10
+ attr_accessor :base_path
11
+
12
+ # This will hold list of all image paths gathered from {@img} tags.
13
+ attr_accessor :images
14
+
15
+ def initialize(opts={})
16
+ @tpl = opts[:img_tpl] || '<img src="%u" alt="%a"/>'
17
+
18
+ @re = /\{@img\s+(\S*?)(?:\s+(.+?))?\}/m
19
+
20
+ @base_path = nil
21
+ @images = []
22
+ end
23
+
24
+ # Takes StringScanner instance.
25
+ #
26
+ # Looks for inline tag at the current scan pointer position, when
27
+ # found, moves scan pointer forward and performs the apporpriate
28
+ # replacement.
29
+ def replace(input)
30
+ if input.check(@re)
31
+ input.scan(@re).sub(@re) { apply_tpl($1, $2) }
32
+ else
33
+ false
34
+ end
35
+ end
36
+
37
+ # applies the image template
38
+ def apply_tpl(url, alt_text)
39
+ @images << url
40
+ @tpl.gsub(/(%\w)/) do
41
+ case $1
42
+ when '%u'
43
+ @base_path ? (@base_path + "/" + url) : url
44
+ when '%a'
45
+ CGI.escapeHTML(alt_text||"")
46
+ else
47
+ $1
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ end
@@ -0,0 +1,58 @@
1
+ require 'cgi'
2
+ require 'jsduck/logger'
3
+
4
+ module JsDuck
5
+
6
+ # Implementation of inline tag {@video}
7
+ class InlineVideo
8
+ def initialize(opts={})
9
+ @templates = {
10
+ "html5" => '<video src="%u">%a</video>',
11
+ "vimeo" => [
12
+ '<p><object width="640" height="360">',
13
+ '<param name="allowfullscreen" value="true" />',
14
+ '<param name="allowscriptaccess" value="always" />',
15
+ '<param name="flashvars" value="api=1" />',
16
+ '<param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=%u&amp;server=vimeo.com&amp;color=4CC208&amp;fullscreen=1" />',
17
+ '<embed src="http://vimeo.com/moogaloop.swf?clip_id=%u&amp;server=vimeo.com&amp;color=4CC208&amp;fullscreen=1" ',
18
+ 'type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="640" height="360"></embed>',
19
+ '</object></p>',
20
+ ].join
21
+ }
22
+
23
+ @re = /\{@video\s+(\w+)\s+(\S*?)(?:\s+(.+?))?\}/m
24
+ end
25
+
26
+ # Takes StringScanner instance.
27
+ #
28
+ # Looks for inline tag at the current scan pointer position, when
29
+ # found, moves scan pointer forward and performs the apporpriate
30
+ # replacement.
31
+ def replace(input)
32
+ if input.check(@re)
33
+ input.scan(@re).sub(@re) { apply_tpl($1, $2, $3) }
34
+ else
35
+ false
36
+ end
37
+ end
38
+
39
+ # applies the video template of the specified type
40
+ def apply_tpl(type, url, alt_text)
41
+ unless @templates.has_key?(type)
42
+ Logger.instance.warn(nil, "Unknown video type #{type}")
43
+ end
44
+
45
+ @templates[type].gsub(/(%\w)/) do
46
+ case $1
47
+ when '%u'
48
+ url
49
+ when '%a'
50
+ CGI.escapeHTML(alt_text||"")
51
+ else
52
+ $1
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ end
data/lib/jsduck/io.rb ADDED
@@ -0,0 +1,30 @@
1
+ module JsDuck
2
+
3
+ # A helper to use instead the builtin IO class to read files in
4
+ # correct encoding.
5
+ #
6
+ # By default in Ruby 1.9 the encoding is auto-detected, which can
7
+ # have surprising results. So in here we read in all files in UTF-8
8
+ # (the default) or in some other encoding specified through --encoding
9
+ # option and convert it to UTF-8 internally.
10
+ class IO
11
+ @@encoding = "UTF-8"
12
+
13
+ # Sets the external encoding to be used for reading files.
14
+ # When it's different from UTF-8, the input will be converted to UTF-8.
15
+ def self.encoding=(e)
16
+ if e =~ /^UTF-8$/i
17
+ @@encoding = e
18
+ else
19
+ @@encoding = e+":UTF-8"
20
+ end
21
+ end
22
+
23
+ # Reads given filename into string
24
+ def self.read(filename)
25
+ File.open(filename, "r:"+@@encoding) {|f| f.read }
26
+ end
27
+
28
+ end
29
+
30
+ end