jsduck 0.2 → 0.3
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/README.md +10 -5
- data/jsduck.gemspec +7 -3
- data/lib/jsduck/aggregator.rb +7 -10
- data/lib/jsduck/app.rb +34 -12
- data/lib/jsduck/cfg_table.rb +2 -2
- data/lib/jsduck/doc_parser.rb +23 -23
- data/lib/jsduck/event_table.rb +2 -2
- data/lib/jsduck/lexer.rb +54 -41
- data/lib/jsduck/method_table.rb +2 -2
- data/lib/jsduck/page.rb +12 -5
- data/lib/jsduck/parser.rb +27 -19
- data/lib/jsduck/property_table.rb +2 -2
- data/lib/jsduck/table.rb +39 -10
- data/lib/jsduck/timer.rb +40 -0
- metadata +19 -4
data/README.md
CHANGED
@@ -106,10 +106,11 @@ For hacking fork it from github.
|
|
106
106
|
$ cd jsduck
|
107
107
|
$ rake --tasks
|
108
108
|
|
109
|
-
JsDuck depends on [json][] and [
|
109
|
+
JsDuck depends on [json][], [RDiscount][], and [parallel][] plus [RSpec][] for tests.
|
110
110
|
|
111
111
|
[json]: http://flori.github.com/json/
|
112
112
|
[RDiscount]: https://github.com/rtomayko/rdiscount
|
113
|
+
[parallel]: https://github.com/grosser/parallel
|
113
114
|
[RSpec]: http://rspec.info/
|
114
115
|
|
115
116
|
|
@@ -182,10 +183,6 @@ Missing features and TODO
|
|
182
183
|
* Support for custom @tags. Ext-doc supports this, I personally have
|
183
184
|
never used this feature, so I'm thinking it's not really needed.
|
184
185
|
|
185
|
-
* Speed improvements. JsDuck is clearly slower than ext-doc, but I
|
186
|
-
haven't so far done almost no optimizations, so there should be some
|
187
|
-
pretty low-hanging fruits to pick.
|
188
|
-
|
189
186
|
|
190
187
|
Copying
|
191
188
|
-------
|
@@ -198,6 +195,14 @@ JsDuck was developed by [Rene Saarsoo](http://triin.net).
|
|
198
195
|
Changelog
|
199
196
|
---------
|
200
197
|
|
198
|
+
* 0.3 - Performance improvements
|
199
|
+
* Significant peed improvements - most importantly utilizing
|
200
|
+
multiple CPU-s (if available) to speed things up. On my 4-core
|
201
|
+
box JsDuck is now even faster than ext-doc.
|
202
|
+
* Printing of performance info in verbose mode
|
203
|
+
* Support for comma-first coding style
|
204
|
+
* Few other fixes to JavaScript parsing
|
205
|
+
|
201
206
|
* 0.2 - most features of ext-doc supported.
|
202
207
|
* Links from documentation to source code
|
203
208
|
* Syntax highlighting of code examples
|
data/jsduck.gemspec
CHANGED
@@ -2,8 +2,8 @@ Gem::Specification.new do |s|
|
|
2
2
|
s.required_rubygems_version = ">= 1.3.7"
|
3
3
|
|
4
4
|
s.name = 'jsduck'
|
5
|
-
s.version = '0.
|
6
|
-
s.date = '2011-
|
5
|
+
s.version = '0.3'
|
6
|
+
s.date = '2011-02-08'
|
7
7
|
s.summary = "Simple JavaScript Duckumentation generator"
|
8
8
|
s.description = "Better ext-doc like JavaScript documentation generator for ExtJS"
|
9
9
|
s.homepage = "https://github.com/nene/jsduck"
|
@@ -11,11 +11,15 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.email = "nene@triin.net"
|
12
12
|
s.rubyforge_project = s.name
|
13
13
|
|
14
|
-
s.files = `git ls-files`.split("\n").find_all
|
14
|
+
s.files = `git ls-files`.split("\n").find_all do |file|
|
15
|
+
file !~ /spec.rb$/ && file !~ /benchmark/
|
16
|
+
end
|
17
|
+
|
15
18
|
s.executables = ["jsduck"]
|
16
19
|
|
17
20
|
s.add_dependency 'rdiscount'
|
18
21
|
s.add_dependency 'json'
|
22
|
+
s.add_dependency 'parallel'
|
19
23
|
|
20
24
|
s.require_path = 'lib'
|
21
25
|
end
|
data/lib/jsduck/aggregator.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'jsduck/parser'
|
2
|
-
require 'jsduck/doc_parser'
|
3
1
|
require 'jsduck/merger'
|
4
2
|
|
5
3
|
module JsDuck
|
@@ -12,22 +10,21 @@ module JsDuck
|
|
12
10
|
@classes = {}
|
13
11
|
@orphans = []
|
14
12
|
@current_class = nil
|
15
|
-
@doc_parser = DocParser.new
|
16
13
|
@merger = Merger.new
|
17
14
|
end
|
18
15
|
|
19
|
-
#
|
20
|
-
#
|
21
|
-
# #result method.
|
16
|
+
# Combines chunk of parsed JavaScript together with previously
|
17
|
+
# added chunks. The resulting documentation is accumulated inside
|
18
|
+
# this class and can be later accessed through #result method.
|
22
19
|
#
|
23
|
-
# - input
|
20
|
+
# - input parse result from JsDuck::Parser
|
24
21
|
# - filename name of the JS file where it came from
|
25
22
|
# - html_filename name of the HTML file where the source was saved.
|
26
23
|
#
|
27
|
-
def
|
24
|
+
def aggregate(input, filename="", html_filename="")
|
28
25
|
@current_class = nil
|
29
|
-
|
30
|
-
doc =
|
26
|
+
input.each do |docset|
|
27
|
+
doc = docset[:comment]
|
31
28
|
code = docset[:code]
|
32
29
|
href = html_filename + "#line-" + docset[:linenr].to_s
|
33
30
|
register(add_href(@merger.merge(doc, code), href, filename))
|
data/lib/jsduck/app.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'rubygems'
|
2
|
+
require 'jsduck/parser'
|
2
3
|
require 'jsduck/aggregator'
|
3
4
|
require 'jsduck/source_formatter'
|
4
5
|
require 'jsduck/class'
|
@@ -6,8 +7,10 @@ require 'jsduck/tree'
|
|
6
7
|
require 'jsduck/tree_icons'
|
7
8
|
require 'jsduck/subclasses'
|
8
9
|
require 'jsduck/page'
|
10
|
+
require 'jsduck/timer'
|
9
11
|
require 'json'
|
10
12
|
require 'fileutils'
|
13
|
+
require 'parallel'
|
11
14
|
|
12
15
|
module JsDuck
|
13
16
|
|
@@ -24,26 +27,42 @@ module JsDuck
|
|
24
27
|
@template_dir = nil
|
25
28
|
@input_files = []
|
26
29
|
@verbose = false
|
30
|
+
@timer = Timer.new
|
27
31
|
end
|
28
32
|
|
29
33
|
# Call this after input parameters set
|
30
34
|
def run
|
31
35
|
copy_template(@template_dir, @output_dir)
|
32
|
-
|
33
|
-
|
34
|
-
|
36
|
+
|
37
|
+
parsed_files = @timer.time(:parsing) { parallel_parse(@input_files) }
|
38
|
+
result = @timer.time(:aggregating) { aggregate(parsed_files) }
|
39
|
+
classes = @timer.time(:aggregating) { filter_classes(result) }
|
40
|
+
@timer.time(:generating) { write_tree(@output_dir+"/output/tree.js", classes) }
|
41
|
+
@timer.time(:generating) { write_pages(@output_dir+"/output", classes) }
|
42
|
+
|
43
|
+
@timer.report if @verbose
|
35
44
|
end
|
36
45
|
|
37
|
-
#
|
38
|
-
|
39
|
-
def parse_files(filenames)
|
40
|
-
agr = Aggregator.new
|
46
|
+
# Parses the files in parallel using as many processes as available CPU-s
|
47
|
+
def parallel_parse(filenames)
|
41
48
|
src = SourceFormatter.new(@output_dir + "/source")
|
42
|
-
filenames
|
49
|
+
Parallel.map(filenames) do |fname|
|
43
50
|
puts "Parsing #{fname} ..." if @verbose
|
44
51
|
code = IO.read(fname)
|
45
|
-
|
46
|
-
|
52
|
+
{
|
53
|
+
:name => fname,
|
54
|
+
:src_name => src.write(code, fname),
|
55
|
+
:data => Parser.new(code).parse,
|
56
|
+
}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Aggregates parsing results sequencially
|
61
|
+
def aggregate(parsed_files)
|
62
|
+
agr = Aggregator.new
|
63
|
+
parsed_files.each do |file|
|
64
|
+
puts "Aggregating #{file[:name]} ..." if @verbose
|
65
|
+
agr.aggregate(file[:data], File.basename(file[:name]), File.basename(file[:src_name]))
|
47
66
|
end
|
48
67
|
agr.result
|
49
68
|
end
|
@@ -73,12 +92,15 @@ module JsDuck
|
|
73
92
|
end
|
74
93
|
|
75
94
|
# Writes documentation page for each class
|
95
|
+
# We do it in parallel using as many processes as available CPU-s
|
76
96
|
def write_pages(path, docs)
|
77
97
|
subclasses = Subclasses.new(docs)
|
78
|
-
|
98
|
+
cache = {}
|
99
|
+
Parallel.each(docs) do |cls|
|
79
100
|
filename = path + "/" + cls[:name] + ".html"
|
80
101
|
puts "Writing to #{filename} ..." if @verbose
|
81
|
-
|
102
|
+
html = Page.new(cls, subclasses, cache).to_html
|
103
|
+
File.open(filename, 'w') {|f| f.write(html) }
|
82
104
|
end
|
83
105
|
end
|
84
106
|
|
data/lib/jsduck/cfg_table.rb
CHANGED
data/lib/jsduck/doc_parser.rb
CHANGED
@@ -48,7 +48,7 @@ module JsDuck
|
|
48
48
|
# - and those without it
|
49
49
|
input.each_line do |line|
|
50
50
|
line.chomp!
|
51
|
-
if line =~ /\A\s*\*\s?(.*)\Z/
|
51
|
+
if line =~ /\A\s*\*\s?(.*)\Z/
|
52
52
|
result << $1
|
53
53
|
else
|
54
54
|
result << line
|
@@ -64,39 +64,39 @@ module JsDuck
|
|
64
64
|
def parse_loop
|
65
65
|
add_tag(:default)
|
66
66
|
while !@input.eos? do
|
67
|
-
if look(/@class\b/)
|
67
|
+
if look(/@class\b/)
|
68
68
|
at_class
|
69
|
-
elsif look(/@extends\b/)
|
69
|
+
elsif look(/@extends\b/)
|
70
70
|
at_extends
|
71
|
-
elsif look(/@singleton\b/)
|
71
|
+
elsif look(/@singleton\b/)
|
72
72
|
boolean_at_tag(/@singleton/, :singleton)
|
73
|
-
elsif look(/@event\b/)
|
73
|
+
elsif look(/@event\b/)
|
74
74
|
at_event
|
75
|
-
elsif look(/@method\b/)
|
75
|
+
elsif look(/@method\b/)
|
76
76
|
at_method
|
77
|
-
elsif look(/@constructor\b/)
|
77
|
+
elsif look(/@constructor\b/)
|
78
78
|
boolean_at_tag(/@constructor/, :constructor)
|
79
|
-
elsif look(/@param\b/)
|
79
|
+
elsif look(/@param\b/)
|
80
80
|
at_param
|
81
|
-
elsif look(/@returns?\b/)
|
81
|
+
elsif look(/@returns?\b/)
|
82
82
|
at_return
|
83
|
-
elsif look(/@cfg\b/)
|
83
|
+
elsif look(/@cfg\b/)
|
84
84
|
at_cfg
|
85
|
-
elsif look(/@property\b/)
|
85
|
+
elsif look(/@property\b/)
|
86
86
|
at_property
|
87
|
-
elsif look(/@type\b/)
|
87
|
+
elsif look(/@type\b/)
|
88
88
|
at_type
|
89
|
-
elsif look(/@xtype\b/)
|
89
|
+
elsif look(/@xtype\b/)
|
90
90
|
at_xtype
|
91
|
-
elsif look(/@member\b/)
|
91
|
+
elsif look(/@member\b/)
|
92
92
|
at_member
|
93
|
-
elsif look(/@static\b/)
|
93
|
+
elsif look(/@static\b/)
|
94
94
|
boolean_at_tag(/@static/, :static)
|
95
|
-
elsif look(/@(private|ignore|hide|protected)\b/)
|
95
|
+
elsif look(/@(private|ignore|hide|protected)\b/)
|
96
96
|
boolean_at_tag(/@(private|ignore|hide|protected)/, :private)
|
97
|
-
elsif look(/@/)
|
97
|
+
elsif look(/@/)
|
98
98
|
@current_tag[:doc] += @input.scan(/@/)
|
99
|
-
elsif look(/[^@]/)
|
99
|
+
elsif look(/[^@]/)
|
100
100
|
@current_tag[:doc] += @input.scan(/[^@]+/)
|
101
101
|
end
|
102
102
|
end
|
@@ -183,9 +183,9 @@ module JsDuck
|
|
183
183
|
match(/@type/)
|
184
184
|
add_tag(:type)
|
185
185
|
skip_horiz_white
|
186
|
-
if look(/\{/)
|
186
|
+
if look(/\{/)
|
187
187
|
@current_tag[:type] = typedef
|
188
|
-
elsif look(/\S/)
|
188
|
+
elsif look(/\S/)
|
189
189
|
@current_tag[:type] = @input.scan(/\S+/)
|
190
190
|
end
|
191
191
|
skip_white
|
@@ -217,7 +217,7 @@ module JsDuck
|
|
217
217
|
# matches {type} if possible and sets it on @current_tag
|
218
218
|
def maybe_type
|
219
219
|
skip_horiz_white
|
220
|
-
if look(/\{/)
|
220
|
+
if look(/\{/)
|
221
221
|
@current_tag[:type] = typedef
|
222
222
|
end
|
223
223
|
end
|
@@ -225,7 +225,7 @@ module JsDuck
|
|
225
225
|
# matches identifier name if possible and sets it on @current_tag
|
226
226
|
def maybe_name
|
227
227
|
skip_horiz_white
|
228
|
-
if look(/\w/)
|
228
|
+
if look(/\w/)
|
229
229
|
@current_tag[:name] = ident
|
230
230
|
end
|
231
231
|
end
|
@@ -233,7 +233,7 @@ module JsDuck
|
|
233
233
|
# matches ident.chain if possible and sets it on @current_tag
|
234
234
|
def maybe_ident_chain(propname)
|
235
235
|
skip_horiz_white
|
236
|
-
if look(/\w/)
|
236
|
+
if look(/\w/)
|
237
237
|
@current_tag[propname] = ident_chain
|
238
238
|
end
|
239
239
|
end
|
data/lib/jsduck/event_table.rb
CHANGED
data/lib/jsduck/lexer.rb
CHANGED
@@ -38,7 +38,7 @@ module JsDuck
|
|
38
38
|
tok = @tokens[i]
|
39
39
|
i += 1
|
40
40
|
return false if tok == nil
|
41
|
-
if t.instance_of?(Symbol)
|
41
|
+
if t.instance_of?(Symbol)
|
42
42
|
tok[:type] == t
|
43
43
|
else
|
44
44
|
tok[:value] == t
|
@@ -67,40 +67,60 @@ module JsDuck
|
|
67
67
|
end
|
68
68
|
|
69
69
|
# Goes through the whole input and tokenizes it
|
70
|
+
#
|
71
|
+
# For efficency we look for tokens in order of frequency in
|
72
|
+
# JavaScript source code:
|
73
|
+
#
|
74
|
+
# - first check for most common operators.
|
75
|
+
# - then for identifiers and keywords.
|
76
|
+
# - then strings
|
77
|
+
# - then comments
|
78
|
+
#
|
79
|
+
# The remaining token types are less frequent, so these are left
|
80
|
+
# to the end.
|
81
|
+
#
|
70
82
|
def tokenize
|
71
83
|
@tokens = []
|
72
84
|
while !@input.eos? do
|
73
|
-
|
74
|
-
if @input.check(/[
|
85
|
+
skip_white
|
86
|
+
if @input.check(/[.(),;={}:]/)
|
75
87
|
@tokens << {
|
76
|
-
:type => :
|
77
|
-
:value =>
|
88
|
+
:type => :operator,
|
89
|
+
:value => @input.scan(/./)
|
78
90
|
}
|
79
|
-
elsif @input.check(
|
91
|
+
elsif @input.check(/[a-zA-Z_]/)
|
80
92
|
value = @input.scan(/\w+/)
|
81
93
|
@tokens << {
|
82
94
|
:type => KEYWORDS[value] ? :keyword : :ident,
|
83
95
|
:value => value
|
84
96
|
}
|
85
|
-
elsif @input.check(
|
86
|
-
@tokens << {
|
87
|
-
:type => :doc_comment,
|
88
|
-
# Calculate current line number, starting with 1
|
89
|
-
:linenr => @input.string[0...@input.pos].count("\n") + 1,
|
90
|
-
:value => @input.scan_until(/\*\/|\Z/)
|
91
|
-
}
|
92
|
-
elsif @input.check(/"/) then
|
97
|
+
elsif @input.check(/'/)
|
93
98
|
@tokens << {
|
94
99
|
:type => :string,
|
95
|
-
:value => eval(@input.scan(/
|
100
|
+
:value => eval(@input.scan(/'([^'\\]|\\.)*'/))
|
96
101
|
}
|
97
|
-
elsif @input.check(/
|
102
|
+
elsif @input.check(/"/)
|
98
103
|
@tokens << {
|
99
104
|
:type => :string,
|
100
|
-
:value => eval(@input.scan(/
|
105
|
+
:value => eval(@input.scan(/"([^"\\]|\\.)*"/))
|
101
106
|
}
|
102
|
-
elsif @input.check(/\//)
|
103
|
-
|
107
|
+
elsif @input.check(/\//)
|
108
|
+
# Several things begin with dash:
|
109
|
+
# - comments, regexes, division-operators
|
110
|
+
if @input.check(/\/\*\*/)
|
111
|
+
@tokens << {
|
112
|
+
:type => :doc_comment,
|
113
|
+
# Calculate current line number, starting with 1
|
114
|
+
:linenr => @input.string[0...@input.pos].count("\n") + 1,
|
115
|
+
:value => @input.scan_until(/\*\/|\Z/)
|
116
|
+
}
|
117
|
+
elsif @input.check(/\/\*/)
|
118
|
+
# skip multiline comment
|
119
|
+
@input.scan_until(/\*\/|\Z/)
|
120
|
+
elsif @input.check(/\/\//)
|
121
|
+
# skip line comment
|
122
|
+
@input.scan_until(/\n|\Z/)
|
123
|
+
elsif regex?
|
104
124
|
@tokens << {
|
105
125
|
:type => :regex,
|
106
126
|
:value => @input.scan(/\/([^\/\\]|\\.)*\/[gim]*/)
|
@@ -111,7 +131,20 @@ module JsDuck
|
|
111
131
|
:value => @input.scan(/\//)
|
112
132
|
}
|
113
133
|
end
|
114
|
-
elsif @input.check(
|
134
|
+
elsif @input.check(/[0-9]+/)
|
135
|
+
nr = @input.scan(/[0-9]+(\.[0-9]*)?/)
|
136
|
+
@tokens << {
|
137
|
+
:type => :number,
|
138
|
+
# When number ends with ".", append "0" so Ruby eval will work
|
139
|
+
:value => eval(/\.$/ =~ nr ? nr+"0" : nr)
|
140
|
+
}
|
141
|
+
elsif @input.check(/\$/)
|
142
|
+
value = @input.scan(/\$\w*/)
|
143
|
+
@tokens << {
|
144
|
+
:type => :ident,
|
145
|
+
:value => value
|
146
|
+
}
|
147
|
+
elsif @input.check(/./)
|
115
148
|
@tokens << {
|
116
149
|
:type => :operator,
|
117
150
|
:value => @input.scan(/./)
|
@@ -128,7 +161,7 @@ module JsDuck
|
|
128
161
|
# - closing square-bracket ]
|
129
162
|
# Otherwise it's a beginning of regex
|
130
163
|
def regex?
|
131
|
-
if @tokens.last
|
164
|
+
if @tokens.last
|
132
165
|
type = @tokens.last[:type]
|
133
166
|
value = @tokens.last[:value]
|
134
167
|
if type == :ident || type == :number
|
@@ -142,26 +175,6 @@ module JsDuck
|
|
142
175
|
return true
|
143
176
|
end
|
144
177
|
|
145
|
-
def skip_white_and_comments
|
146
|
-
skip_white
|
147
|
-
while multiline_comment? || line_comment? do
|
148
|
-
if multiline_comment? then
|
149
|
-
@input.scan_until(/\*\/|\Z/)
|
150
|
-
elsif line_comment? then
|
151
|
-
@input.scan_until(/\n|\Z/)
|
152
|
-
end
|
153
|
-
skip_white
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
def multiline_comment?
|
158
|
-
@input.check(/\/\*[^*]/)
|
159
|
-
end
|
160
|
-
|
161
|
-
def line_comment?
|
162
|
-
@input.check(/\/\//)
|
163
|
-
end
|
164
|
-
|
165
178
|
def skip_white
|
166
179
|
@input.scan(/\s+/)
|
167
180
|
end
|
data/lib/jsduck/method_table.rb
CHANGED
data/lib/jsduck/page.rb
CHANGED
@@ -9,9 +9,16 @@ module JsDuck
|
|
9
9
|
|
10
10
|
# Creates HTML documentation page for one class.
|
11
11
|
class Page
|
12
|
-
|
12
|
+
# Initializes doc page generator
|
13
|
+
#
|
14
|
+
# - cls : the Class object for which to generate documentation
|
15
|
+
# - subclasses : lookup table for easy access to subclasses
|
16
|
+
# - cache : cache for already generated HTML rows for class members
|
17
|
+
#
|
18
|
+
def initialize(cls, subclasses = {}, cache = {})
|
13
19
|
@cls = cls
|
14
20
|
@subclasses = subclasses
|
21
|
+
@cache = cache
|
15
22
|
@formatter = DocFormatter.new(cls.full_name)
|
16
23
|
end
|
17
24
|
|
@@ -23,10 +30,10 @@ module JsDuck
|
|
23
30
|
abstract,
|
24
31
|
description,
|
25
32
|
"<div class='hr'></div>",
|
26
|
-
CfgTable.new(@cls).to_html,
|
27
|
-
PropertyTable.new(@cls).to_html,
|
28
|
-
MethodTable.new(@cls).to_html,
|
29
|
-
EventTable.new(@cls).to_html,
|
33
|
+
CfgTable.new(@cls, @cache).to_html,
|
34
|
+
PropertyTable.new(@cls, @cache).to_html,
|
35
|
+
MethodTable.new(@cls, @cache).to_html,
|
36
|
+
EventTable.new(@cls, @cache).to_html,
|
30
37
|
"</div>",
|
31
38
|
].join("\n")
|
32
39
|
end
|
data/lib/jsduck/parser.rb
CHANGED
@@ -1,18 +1,20 @@
|
|
1
1
|
require 'jsduck/lexer'
|
2
|
+
require 'jsduck/doc_parser'
|
2
3
|
|
3
4
|
module JsDuck
|
4
5
|
|
5
6
|
class Parser
|
6
7
|
def initialize(input)
|
7
8
|
@lex = Lexer.new(input)
|
9
|
+
@doc_parser = DocParser.new
|
8
10
|
@docs = []
|
9
11
|
end
|
10
12
|
|
11
13
|
# Parses the whole JavaScript block and returns array where for
|
12
14
|
# each doc-comment there is a hash of three values: the comment
|
13
|
-
#
|
14
|
-
# and parsed structure of the code that
|
15
|
-
# comment.
|
15
|
+
# structure created by DocParser, number of the line where the
|
16
|
+
# comment starts, and parsed structure of the code that
|
17
|
+
# immediately follows the comment.
|
16
18
|
#
|
17
19
|
# For example with the following JavaScript input:
|
18
20
|
#
|
@@ -26,7 +28,10 @@ module JsDuck
|
|
26
28
|
#
|
27
29
|
# [
|
28
30
|
# {
|
29
|
-
# :comment =>
|
31
|
+
# :comment => [
|
32
|
+
# {:tagname => :default, :doc => "Method description"},
|
33
|
+
# {:tagname => :return, :type => "Number", :doc => ""},
|
34
|
+
# ],
|
30
35
|
# :linenr => 1,
|
31
36
|
# :code => {
|
32
37
|
# :type => :assignment,
|
@@ -45,10 +50,10 @@ module JsDuck
|
|
45
50
|
#
|
46
51
|
def parse
|
47
52
|
while !@lex.empty? do
|
48
|
-
if look(:doc_comment)
|
53
|
+
if look(:doc_comment)
|
49
54
|
comment = @lex.next(true)
|
50
55
|
@docs << {
|
51
|
-
:comment => comment[:value],
|
56
|
+
:comment => @doc_parser.parse(comment[:value]),
|
52
57
|
:linenr => comment[:linenr],
|
53
58
|
:code => code_block
|
54
59
|
}
|
@@ -64,15 +69,18 @@ module JsDuck
|
|
64
69
|
|
65
70
|
# <code-block> := <function> | <var-declaration> | <assignment> | <property-literal>
|
66
71
|
def code_block
|
67
|
-
if look("function")
|
72
|
+
if look("function")
|
68
73
|
function
|
69
|
-
elsif look("var")
|
74
|
+
elsif look("var")
|
70
75
|
var_declaration
|
71
|
-
elsif look(:ident, ":") || look(:string, ":")
|
76
|
+
elsif look(:ident, ":") || look(:string, ":")
|
72
77
|
property_literal
|
73
|
-
elsif look(:ident) || look("
|
78
|
+
elsif look(",", :ident, ":") || look(",", :string, ":")
|
79
|
+
match(",")
|
80
|
+
property_literal
|
81
|
+
elsif look(:ident) || look("this")
|
74
82
|
maybe_assignment
|
75
|
-
elsif look(:string)
|
83
|
+
elsif look(:string)
|
76
84
|
{:type => :assignment, :left => [match(:string)]}
|
77
85
|
else
|
78
86
|
{:type => :nop}
|
@@ -115,7 +123,7 @@ module JsDuck
|
|
115
123
|
# <maybe-assignment> := <ident-chain> [ "=" <expression> ]
|
116
124
|
def maybe_assignment
|
117
125
|
left = ident_chain
|
118
|
-
if look("=")
|
126
|
+
if look("=")
|
119
127
|
match("=")
|
120
128
|
right = expression
|
121
129
|
end
|
@@ -143,17 +151,17 @@ module JsDuck
|
|
143
151
|
# <expression> := <function> | <ext-extend> | <literal>
|
144
152
|
# <literal> := <string> | <boolean> | <number> | <regex>
|
145
153
|
def expression
|
146
|
-
if look("function")
|
154
|
+
if look("function")
|
147
155
|
function
|
148
|
-
elsif look("Ext", ".", "extend")
|
156
|
+
elsif look("Ext", ".", "extend")
|
149
157
|
ext_extend
|
150
|
-
elsif look(:string)
|
158
|
+
elsif look(:string)
|
151
159
|
{:type => :literal, :class => "String"}
|
152
|
-
elsif look("true") || look("false")
|
160
|
+
elsif look("true") || look("false")
|
153
161
|
{:type => :literal, :class => "Boolean"}
|
154
|
-
elsif look(:number)
|
162
|
+
elsif look(:number)
|
155
163
|
{:type => :literal, :class => "Number"}
|
156
|
-
elsif look(:regex)
|
164
|
+
elsif look(:regex)
|
157
165
|
{:type => :literal, :class => "RegExp"}
|
158
166
|
end
|
159
167
|
end
|
@@ -182,7 +190,7 @@ module JsDuck
|
|
182
190
|
# Matches all arguments, returns the value of last match
|
183
191
|
# When the whole sequence doesn't match, throws exception
|
184
192
|
def match(*args)
|
185
|
-
if look(*args)
|
193
|
+
if look(*args)
|
186
194
|
last = nil
|
187
195
|
args.length.times { last = @lex.next }
|
188
196
|
last
|
data/lib/jsduck/table.rb
CHANGED
@@ -8,8 +8,18 @@ module JsDuck
|
|
8
8
|
# @row_class, and implement the signature_suffix() and extra_doc()
|
9
9
|
# methods.
|
10
10
|
class Table
|
11
|
-
|
11
|
+
# Initializes class member table generator
|
12
|
+
#
|
13
|
+
# - cls : the class for which to generate the table.
|
14
|
+
#
|
15
|
+
# - cache : shared cache of already generated HTML rows. If Foo
|
16
|
+
# inherits from Bar and we have already generated members table
|
17
|
+
# for Bar, then we don't have to re-render all the HTML the
|
18
|
+
# methods from Bar, but can just look them up from cache.
|
19
|
+
#
|
20
|
+
def initialize(cls, cache={})
|
12
21
|
@cls = cls
|
22
|
+
@cache = cache
|
13
23
|
@formatter = DocFormatter.new(cls.full_name)
|
14
24
|
end
|
15
25
|
|
@@ -29,20 +39,39 @@ module JsDuck
|
|
29
39
|
].join("\n")
|
30
40
|
end
|
31
41
|
|
42
|
+
# Returns HTML row for class member.
|
43
|
+
#
|
44
|
+
# When HTML for member has already been rendered we can pick it
|
45
|
+
# from cache and only fill in some details which differ from class
|
46
|
+
# to class.
|
47
|
+
#
|
48
|
+
# Otherwise perform the rendering of HTML and save it to cache.
|
32
49
|
def row(item)
|
50
|
+
cache_key = "#{item[:member]}-#{@row_class}-#{item[:name]}"
|
51
|
+
if @cache[cache_key]
|
52
|
+
html = @cache[cache_key]
|
53
|
+
else
|
54
|
+
html = @cache[cache_key] = create_row(item)
|
55
|
+
end
|
56
|
+
inherited = inherited?(item) ? 'inherited' : ''
|
57
|
+
owner = inherited?(item) ? member_link(item) : Class.short_name(item[:member])
|
58
|
+
html.sub(/!!--inherited--!!/, inherited).sub(/!!--owner-class--!!/, owner)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Generates HTML for the row, leaving in placeholders for owner
|
62
|
+
# class name and inherited class.
|
63
|
+
def create_row(item)
|
33
64
|
p_doc = primary_doc(item)
|
34
65
|
e_doc = extra_doc(item)
|
35
66
|
description = expandable_desc(p_doc, e_doc)
|
36
67
|
expandable = expandable?(p_doc, e_doc) ? 'expandable' : ''
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
"</tr>",
|
45
|
-
].join("")
|
68
|
+
return <<-EOHTML
|
69
|
+
<tr class='#{@row_class} #{expandable} !!--inherited--!!'>
|
70
|
+
<td class='micon'><a href='#expand' class='exi'> </a></td>
|
71
|
+
<td class='sig'>#{signature(item)}<div class='mdesc'>#{description}</div></td>
|
72
|
+
<td class='msource'>!!--owner-class--!!</td>
|
73
|
+
</tr>
|
74
|
+
EOHTML
|
46
75
|
end
|
47
76
|
|
48
77
|
def member_link(item)
|
data/lib/jsduck/timer.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module JsDuck
|
2
|
+
|
3
|
+
# Helper for timing execution of named code blocks.
|
4
|
+
#
|
5
|
+
# timer = Timer.new
|
6
|
+
# a = timer.time(:sum) { 5 + 5 }
|
7
|
+
# b = timer.time(:sum) { 5 + 5 }
|
8
|
+
# c = timer.time(:mult) { 5 * 5 }
|
9
|
+
# d = timer.time(:mult) { 5 * 5 }
|
10
|
+
# timer.report
|
11
|
+
#
|
12
|
+
# The #report method will print sum of the time spent in each
|
13
|
+
# category.
|
14
|
+
#
|
15
|
+
class Timer
|
16
|
+
def initialize
|
17
|
+
@timings = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
# Performs timing of one code block.
|
21
|
+
# Returns the same value that code block returns.
|
22
|
+
def time(name)
|
23
|
+
begin_time = Time.now
|
24
|
+
result = yield
|
25
|
+
interval = Time.now - begin_time
|
26
|
+
if @timings[name]
|
27
|
+
@timings[name] += interval
|
28
|
+
else
|
29
|
+
@timings[name] = interval
|
30
|
+
end
|
31
|
+
result
|
32
|
+
end
|
33
|
+
|
34
|
+
# prints timings report to console
|
35
|
+
def report
|
36
|
+
@timings.each {|name, time| puts "#{name}:\t#{time} seconds" }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
metadata
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsduck
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 13
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: "0.
|
8
|
+
- 3
|
9
|
+
version: "0.3"
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Rene Saarsoo
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-
|
17
|
+
date: 2011-02-08 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -45,6 +45,20 @@ dependencies:
|
|
45
45
|
version: "0"
|
46
46
|
type: :runtime
|
47
47
|
version_requirements: *id002
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: parallel
|
50
|
+
prerelease: false
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
hash: 3
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
type: :runtime
|
61
|
+
version_requirements: *id003
|
48
62
|
description: Better ext-doc like JavaScript documentation generator for ExtJS
|
49
63
|
email: nene@triin.net
|
50
64
|
executables:
|
@@ -79,6 +93,7 @@ files:
|
|
79
93
|
- lib/jsduck/source_formatter.rb
|
80
94
|
- lib/jsduck/subclasses.rb
|
81
95
|
- lib/jsduck/table.rb
|
96
|
+
- lib/jsduck/timer.rb
|
82
97
|
- lib/jsduck/tree.rb
|
83
98
|
- lib/jsduck/tree_icons.rb
|
84
99
|
- template/index.html
|