jsduck 3.0.1 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +1 -1
- data/Rakefile +73 -41
- data/js-classes/String.js +10 -8
- data/jsduck.gemspec +2 -2
- data/lib/jsduck/accessors.rb +3 -0
- data/lib/jsduck/aggregator.rb +34 -1
- data/lib/jsduck/api_exporter.rb +48 -0
- data/lib/jsduck/app.rb +47 -182
- data/lib/jsduck/app_data.rb +34 -0
- data/lib/jsduck/{exporter.rb → app_exporter.rb} +21 -19
- data/lib/jsduck/categories.rb +13 -62
- data/lib/jsduck/class.rb +23 -9
- data/lib/jsduck/class_formatter.rb +2 -2
- data/lib/jsduck/class_writer.rb +49 -0
- data/lib/jsduck/doc_formatter.rb +16 -8
- data/lib/jsduck/doc_parser.rb +42 -36
- data/lib/jsduck/examples.rb +9 -5
- data/lib/jsduck/file_categories.rb +65 -0
- data/lib/jsduck/full_exporter.rb +29 -0
- data/lib/jsduck/guides.rb +12 -10
- data/lib/jsduck/images.rb +2 -2
- data/lib/jsduck/index_html.rb +67 -0
- data/lib/jsduck/inherit_doc.rb +75 -0
- data/lib/jsduck/js_parser.rb +8 -1
- data/lib/jsduck/lint.rb +9 -9
- data/lib/jsduck/logger.rb +64 -6
- data/lib/jsduck/merger.rb +29 -25
- data/lib/jsduck/null_object.rb +19 -0
- data/lib/jsduck/options.rb +46 -20
- data/lib/jsduck/renderer.rb +24 -18
- data/lib/jsduck/search_data.rb +2 -2
- data/lib/jsduck/source_writer.rb +19 -6
- data/lib/jsduck/stats.rb +103 -0
- data/lib/jsduck/template_dir.rb +51 -0
- data/lib/jsduck/videos.rb +9 -6
- data/lib/jsduck/welcome.rb +14 -8
- data/opt/extjs-welcome.html +74 -0
- data/opt/touch-iframe.html +85 -0
- data/opt/touch-welcome.html +122 -0
- metadata +401 -389
- data/bin/stats +0 -92
- data/lib/jsduck/aliases.rb +0 -54
data/lib/jsduck/merger.rb
CHANGED
@@ -103,7 +103,7 @@ module JsDuck
|
|
103
103
|
end
|
104
104
|
end
|
105
105
|
|
106
|
-
if tag[:tagname] == :
|
106
|
+
if tag[:tagname] == :alias
|
107
107
|
groups[:class] << tag
|
108
108
|
elsif group_name == :cfg
|
109
109
|
groups[:cfg].last << tag
|
@@ -123,8 +123,7 @@ module JsDuck
|
|
123
123
|
:extends => detect_extends(doc_map, code),
|
124
124
|
:mixins => detect_list(:mixins, doc_map, code),
|
125
125
|
:alternateClassNames => detect_list(:alternateClassNames, doc_map, code),
|
126
|
-
:
|
127
|
-
:meta => detect_meta(doc_map),
|
126
|
+
:aliases => detect_aliases(doc_map, code),
|
128
127
|
:singleton => detect_singleton(doc_map, code),
|
129
128
|
:requires => detect_list(:requires, doc_map, code),
|
130
129
|
:uses => detect_list(:uses, doc_map, code),
|
@@ -227,7 +226,8 @@ module JsDuck
|
|
227
226
|
:static => !!doc_map[:static],
|
228
227
|
:inheritable => !!doc_map[:inheritable],
|
229
228
|
:deprecated => detect_deprecated(doc_map),
|
230
|
-
:
|
229
|
+
:inheritdoc => doc_map[:inheritdoc] ? doc_map[:inheritdoc].first : nil,
|
230
|
+
:meta => detect_meta(doc_map),
|
231
231
|
})
|
232
232
|
hash[:id] = create_member_id(hash)
|
233
233
|
return hash
|
@@ -330,31 +330,35 @@ module JsDuck
|
|
330
330
|
end
|
331
331
|
end
|
332
332
|
|
333
|
-
def
|
334
|
-
if doc_map[:
|
335
|
-
|
333
|
+
def detect_aliases(doc_map, code)
|
334
|
+
if doc_map[:alias]
|
335
|
+
build_aliases_hash(doc_map[:alias].map {|tag| tag[:name] })
|
336
336
|
elsif code[:xtype] || code[:alias]
|
337
|
-
|
338
|
-
(code[:xtype]
|
339
|
-
|
340
|
-
|
337
|
+
hash = {}
|
338
|
+
build_aliases_hash(code[:xtype].map {|xtype| "widget."+xtype }, hash) if code[:xtype]
|
339
|
+
build_aliases_hash(code[:alias], hash) if code[:alias]
|
340
|
+
hash
|
341
|
+
else
|
342
|
+
{}
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
# Given array of full alias names like "foo.bar", "foo.baz"
|
347
|
+
# build hash like {"foo" => ["bar", "baz"]}
|
348
|
+
#
|
349
|
+
# When hash given as second argument, then merges the aliases into
|
350
|
+
# it instead of creating a new hash.
|
351
|
+
def build_aliases_hash(aliases, hash={})
|
352
|
+
aliases.each do |a|
|
353
|
+
if a =~ /^([\w.]+)\.(\w+)$/
|
354
|
+
if hash[$1]
|
355
|
+
hash[$1] << $2
|
341
356
|
else
|
342
|
-
|
343
|
-
end
|
344
|
-
end
|
345
|
-
(code[:alias] || []).each do |a|
|
346
|
-
if a =~ /^([\w.]+)\.(\w+)$/
|
347
|
-
if xtypes[$1]
|
348
|
-
xtypes[$1] << $2
|
349
|
-
else
|
350
|
-
xtypes[$1] = [$2]
|
351
|
-
end
|
357
|
+
hash[$1] = [$2]
|
352
358
|
end
|
353
359
|
end
|
354
|
-
xtypes
|
355
|
-
else
|
356
|
-
{}
|
357
360
|
end
|
361
|
+
hash
|
358
362
|
end
|
359
363
|
|
360
364
|
def detect_meta(doc_map)
|
@@ -437,7 +441,7 @@ module JsDuck
|
|
437
441
|
parent[:properties] = [] unless parent[:properties]
|
438
442
|
parent[:properties] << it
|
439
443
|
else
|
440
|
-
Logger.instance.warn("Ignoring subproperty #{$1}.#{$2}, no parent found with name '#{$1}'.", @filename, @linenr)
|
444
|
+
Logger.instance.warn(:subproperty, "Ignoring subproperty #{$1}.#{$2}, no parent found with name '#{$1}'.", @filename, @linenr)
|
441
445
|
end
|
442
446
|
else
|
443
447
|
items << it
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module JsDuck
|
2
|
+
# A class that does nothing.
|
3
|
+
# Responds to all methods by returning self, unless a hash passed to
|
4
|
+
# constructor.
|
5
|
+
# See: http://en.wikipedia.org/wiki/Null_Object_pattern
|
6
|
+
class NullObject
|
7
|
+
# Optionally takes a hash of method_name => return_value pairs,
|
8
|
+
# making it return those values for those methods, sort of like
|
9
|
+
# OpenStruct, but for all other methods self is still returned and
|
10
|
+
# any number of arguments is accepted.
|
11
|
+
def initialize(methods={})
|
12
|
+
@methods = methods
|
13
|
+
end
|
14
|
+
|
15
|
+
def method_missing(meth, *args, &block)
|
16
|
+
@methods.has_key?(meth) ? @methods[meth] : self
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/jsduck/options.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'optparse'
|
2
2
|
require 'jsduck/meta_tag_loader'
|
3
|
+
require 'jsduck/logger'
|
3
4
|
|
4
5
|
module JsDuck
|
5
6
|
|
@@ -11,8 +12,6 @@ module JsDuck
|
|
11
12
|
attr_accessor :ignore_global
|
12
13
|
attr_accessor :external_classes
|
13
14
|
attr_accessor :meta_tags
|
14
|
-
attr_accessor :warnings
|
15
|
-
attr_accessor :verbose
|
16
15
|
|
17
16
|
# Customizing output
|
18
17
|
attr_accessor :title
|
@@ -24,6 +23,7 @@ module JsDuck
|
|
24
23
|
attr_accessor :guides
|
25
24
|
attr_accessor :videos
|
26
25
|
attr_accessor :examples
|
26
|
+
attr_accessor :stats
|
27
27
|
attr_accessor :categories_path
|
28
28
|
attr_accessor :pretty_json
|
29
29
|
attr_accessor :images
|
@@ -73,9 +73,7 @@ module JsDuck
|
|
73
73
|
@meta_tags = []
|
74
74
|
@meta_tag_paths = []
|
75
75
|
|
76
|
-
@
|
77
|
-
@verbose = false
|
78
|
-
@version = "3.0.1"
|
76
|
+
@version = "3.1.0"
|
79
77
|
|
80
78
|
# Customizing output
|
81
79
|
@title = "Sencha Docs - Ext JS"
|
@@ -87,6 +85,7 @@ module JsDuck
|
|
87
85
|
@guides = nil
|
88
86
|
@videos = nil
|
89
87
|
@examples = nil
|
88
|
+
@stats = false
|
90
89
|
@categories_path = nil
|
91
90
|
@pretty_json = false
|
92
91
|
@images = []
|
@@ -130,8 +129,9 @@ module JsDuck
|
|
130
129
|
|
131
130
|
opts.on('-o', '--output=PATH',
|
132
131
|
"Directory to output all this amazing documentation.",
|
133
|
-
"This option MUST be specified (unless --stdout).",
|
134
|
-
|
132
|
+
"This option MUST be specified (unless --stdout).",
|
133
|
+
"Use dash '-' to write docs to STDOUT (only export).", " ") do |path|
|
134
|
+
@output_dir = path == "-" ? :stdout : canonical(path)
|
135
135
|
end
|
136
136
|
|
137
137
|
opts.on('--ignore-global', "Turns off the creation of global class.", " ") do
|
@@ -152,16 +152,17 @@ module JsDuck
|
|
152
152
|
|
153
153
|
opts.on('--meta-tags=PATH',
|
154
154
|
"Path to Ruby file or directory with custom",
|
155
|
-
"meta-tag implementations.
|
156
|
-
@meta_tag_paths << path
|
155
|
+
"meta-tag implementations.", " ") do |path|
|
156
|
+
@meta_tag_paths << canonical(path)
|
157
157
|
end
|
158
158
|
|
159
|
-
opts.on('--no-warnings',
|
160
|
-
|
159
|
+
opts.on('--no-warnings',
|
160
|
+
"Turns off all warnings. Same as --warnings=-all", " ") do
|
161
|
+
Logger.instance.set_warning(:all, false)
|
161
162
|
end
|
162
163
|
|
163
164
|
opts.on('-v', '--verbose', "This will fill up your console.", " ") do
|
164
|
-
|
165
|
+
Logger.instance.verbose = true
|
165
166
|
end
|
166
167
|
|
167
168
|
opts.separator "Customizing output:"
|
@@ -211,6 +212,11 @@ module JsDuck
|
|
211
212
|
@examples = canonical(path)
|
212
213
|
end
|
213
214
|
|
215
|
+
opts.on('--stats',
|
216
|
+
"Creates page with all kinds of statistics. Experimental!", " ") do
|
217
|
+
@stats = true
|
218
|
+
end
|
219
|
+
|
214
220
|
opts.on('--categories=PATH',
|
215
221
|
"Path to JSON file which defines categories for classes.", " ") do |path|
|
216
222
|
@categories_path = canonical(path)
|
@@ -249,12 +255,11 @@ module JsDuck
|
|
249
255
|
@img_tpl = tpl
|
250
256
|
end
|
251
257
|
|
252
|
-
opts.on('--
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
@export = :stdout
|
258
|
+
opts.on('--export=TYPE',
|
259
|
+
"Exports docs in JSON. TYPE is one of:",
|
260
|
+
"* full - full class docs.",
|
261
|
+
"* api - only class- and member names.", " ") do |format|
|
262
|
+
@export = format.to_sym
|
258
263
|
end
|
259
264
|
|
260
265
|
opts.on('--seo', "Creates index.php that handles search engine traffic.", " ") do
|
@@ -270,6 +275,21 @@ module JsDuck
|
|
270
275
|
opts.separator "Debugging:"
|
271
276
|
opts.separator ""
|
272
277
|
|
278
|
+
opts.on('--warnings=+A,-B,+C', Array,
|
279
|
+
"Turns warnings selectively on/off.",
|
280
|
+
"+foo turns on a warning, -foo turns it off.",
|
281
|
+
"Possible warning types are:",
|
282
|
+
" ",
|
283
|
+
*Logger.instance.doc_warnings) do |warnings|
|
284
|
+
warnings.each do |op|
|
285
|
+
if op =~ /^([-+]?)(.*)$/
|
286
|
+
enable = !($1 == "-")
|
287
|
+
name = $2.to_sym
|
288
|
+
Logger.instance.set_warning(name, enable)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
273
293
|
# For debugging it's often useful to set --processes=0 to get deterministic results.
|
274
294
|
opts.on('-p', '--processes=COUNT',
|
275
295
|
"The number of parallel processes to use.",
|
@@ -369,7 +389,7 @@ module JsDuck
|
|
369
389
|
@input_files << fname
|
370
390
|
end
|
371
391
|
else
|
372
|
-
|
392
|
+
Logger.instance.warn(nil, "File #{fname} not found")
|
373
393
|
end
|
374
394
|
end
|
375
395
|
|
@@ -387,7 +407,13 @@ module JsDuck
|
|
387
407
|
if @input_files.length == 0 && !@welcome && !@guides && !@videos && !@examples
|
388
408
|
puts "You should specify some input files, otherwise there's nothing I can do :("
|
389
409
|
exit(1)
|
390
|
-
elsif @
|
410
|
+
elsif @output_dir == :stdout && !@export
|
411
|
+
puts "Output to STDOUT only works when using --export option."
|
412
|
+
exit(1)
|
413
|
+
elsif ![nil, :full, :api].include?(@export)
|
414
|
+
puts "Unknown export format: #{@export}"
|
415
|
+
exit(1)
|
416
|
+
elsif @output_dir != :stdout
|
391
417
|
if !@output_dir
|
392
418
|
puts "You should also specify an output directory, where I could write all this amazing documentation."
|
393
419
|
exit(1)
|
data/lib/jsduck/renderer.rb
CHANGED
@@ -17,7 +17,7 @@ module JsDuck
|
|
17
17
|
"<div class='doc-contents'>",
|
18
18
|
render_private_class_notice,
|
19
19
|
@cls[:doc],
|
20
|
-
render_meta_data,
|
20
|
+
render_meta_data(@cls[:meta]),
|
21
21
|
"</div>",
|
22
22
|
"<div class='members'>",
|
23
23
|
render_member_sections,
|
@@ -35,9 +35,11 @@ module JsDuck
|
|
35
35
|
]
|
36
36
|
end
|
37
37
|
|
38
|
-
def render_meta_data
|
38
|
+
def render_meta_data(meta_data)
|
39
|
+
return if meta_data.size == 0
|
40
|
+
|
39
41
|
@meta_tags.map do |tag|
|
40
|
-
contents =
|
42
|
+
contents = meta_data[tag.name]
|
41
43
|
if contents
|
42
44
|
tag.to_html(contents)
|
43
45
|
else
|
@@ -136,9 +138,9 @@ module JsDuck
|
|
136
138
|
statics = @cls[:statics][sec[:type]]
|
137
139
|
if members.length > 0 || statics.length > 0
|
138
140
|
[
|
139
|
-
"<div
|
141
|
+
"<div class='members-section'>",
|
140
142
|
statics.length == 0 ? "<div class='definedBy'>Defined By</div>" : "",
|
141
|
-
"<h3 class='members-title'>#{sec[:title]}</h3>",
|
143
|
+
"<h3 class='members-title icon-#{sec[:type]}'>#{sec[:title]}</h3>",
|
142
144
|
render_subsection(members, statics.length > 0 ? "Instance #{sec[:title]}" : nil),
|
143
145
|
render_subsection(statics, "Static #{sec[:title]}"),
|
144
146
|
"</div>",
|
@@ -165,11 +167,11 @@ module JsDuck
|
|
165
167
|
first_child = is_first ? "first-child" : ""
|
166
168
|
# shorthand to owner class
|
167
169
|
owner = m[:owner]
|
168
|
-
#
|
169
|
-
inherited = owner
|
170
|
+
# is this method inherited from parent?
|
171
|
+
inherited = (owner != @cls[:name])
|
170
172
|
|
171
173
|
return [
|
172
|
-
"<div id='#{m[:id]}' class='member #{first_child} #{inherited}'>",
|
174
|
+
"<div id='#{m[:id]}' class='member #{first_child} #{inherited ? 'inherited' : 'not-inherited'}'>",
|
173
175
|
# leftmost column: expand button
|
174
176
|
"<a href='#' class='side expandable'>",
|
175
177
|
"<span> </span>",
|
@@ -177,8 +179,10 @@ module JsDuck
|
|
177
179
|
# member name and type + link to owner class and source
|
178
180
|
"<div class='title'>",
|
179
181
|
"<div class='meta'>",
|
180
|
-
"<a href='#!/api/#{owner}' rel='#{owner}' class='
|
181
|
-
|
182
|
+
inherited ? "<a href='#!/api/#{owner}' rel='#{owner}' class='defined-in docClass'>#{owner}</a>" :
|
183
|
+
"<span class='defined-in' rel='#{owner}'>#{owner}</span>",
|
184
|
+
"<br/>",
|
185
|
+
"<a href='source/#{m[:files][0][:href]}' target='_blank' class='view-source'>view source</a>",
|
182
186
|
"</div>",
|
183
187
|
# method params signature or property type signature
|
184
188
|
render_signature(m),
|
@@ -202,7 +206,7 @@ module JsDuck
|
|
202
206
|
name = m[:name]
|
203
207
|
before = ""
|
204
208
|
if m[:tagname] == :method && m[:name] == "constructor"
|
205
|
-
before = "<strong class='
|
209
|
+
before = "<strong class='new-keyword'>new</strong>"
|
206
210
|
name = @cls[:name]
|
207
211
|
end
|
208
212
|
|
@@ -218,19 +222,19 @@ module JsDuck
|
|
218
222
|
|
219
223
|
after = ""
|
220
224
|
if m[:protected]
|
221
|
-
after += "<strong class='protected
|
225
|
+
after += "<strong class='protected signature'>protected</strong>"
|
222
226
|
end
|
223
227
|
if m[:static]
|
224
|
-
after += "<strong class='static
|
228
|
+
after += "<strong class='static signature'>static</strong>"
|
225
229
|
end
|
226
230
|
if m[:deprecated]
|
227
|
-
after += "<strong class='deprecated
|
231
|
+
after += "<strong class='deprecated signature'>deprecated</strong>"
|
228
232
|
end
|
229
233
|
if m[:required]
|
230
|
-
after += "<strong class='required
|
234
|
+
after += "<strong class='required signature'>required</strong>"
|
231
235
|
end
|
232
236
|
if m[:template]
|
233
|
-
after += "<strong class='template
|
237
|
+
after += "<strong class='template signature'>template</strong>"
|
234
238
|
end
|
235
239
|
|
236
240
|
uri = "#!/api/#{m[:owner]}-#{m[:id]}"
|
@@ -258,7 +262,7 @@ module JsDuck
|
|
258
262
|
if m[:deprecated]
|
259
263
|
v = m[:deprecated][:version] ? "since " + m[:deprecated][:version] : ""
|
260
264
|
doc << [
|
261
|
-
"<div class='deprecated'>",
|
265
|
+
"<div class='signature-box deprecated'>",
|
262
266
|
"<p>This #{m[:tagname]} has been <strong>deprecated</strong> #{v}</p>",
|
263
267
|
m[:deprecated][:text],
|
264
268
|
"</div>",
|
@@ -267,13 +271,15 @@ module JsDuck
|
|
267
271
|
|
268
272
|
if m[:template]
|
269
273
|
doc << [
|
270
|
-
"<div class='template'>",
|
274
|
+
"<div class='signature-box template'>",
|
271
275
|
"<p>This is a template method. A hook into the functionality of this class.",
|
272
276
|
"Feel free to override it in child classes.</p>",
|
273
277
|
"</div>",
|
274
278
|
]
|
275
279
|
end
|
276
280
|
|
281
|
+
doc << render_meta_data(m[:meta])
|
282
|
+
|
277
283
|
doc << render_params_and_return(m)
|
278
284
|
|
279
285
|
doc
|
data/lib/jsduck/search_data.rb
CHANGED
data/lib/jsduck/source_writer.rb
CHANGED
@@ -1,16 +1,29 @@
|
|
1
|
+
require 'jsduck/logger'
|
2
|
+
require 'fileutils'
|
3
|
+
|
1
4
|
module JsDuck
|
2
5
|
|
3
6
|
# Writes HTML JavaScript/CSS source into HTML file.
|
4
7
|
class SourceWriter
|
5
8
|
|
9
|
+
# Writes all source files as HTML files into destination dir.
|
10
|
+
#
|
11
|
+
# Can't be done in parallel, because file.html_filename= method
|
12
|
+
# updates all the doc-objects related to the file
|
13
|
+
def self.write_all(files, destination)
|
14
|
+
FileUtils.mkdir(destination)
|
15
|
+
src = SourceWriter.new(destination)
|
16
|
+
files.each do |file|
|
17
|
+
html_filename = src.write(file.to_html, file.filename)
|
18
|
+
Logger.instance.log("Writing source", html_filename)
|
19
|
+
file.html_filename = File.basename(html_filename)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
6
23
|
# Initializes SourceFormatter to the directory where
|
7
24
|
# HTML-formatted source files will be placed.
|
8
|
-
|
9
|
-
# Wrapper can be either :page or nil; with the first one the whole
|
10
|
-
# HTML page is created, otherwise source is left as is.
|
11
|
-
def initialize(output_dir, wrapper = :page)
|
25
|
+
def initialize(output_dir)
|
12
26
|
@output_dir = output_dir
|
13
|
-
@wrapper = wrapper
|
14
27
|
end
|
15
28
|
|
16
29
|
# Writes HTML into file in output directory. It returns the name
|
@@ -18,7 +31,7 @@ module JsDuck
|
|
18
31
|
def write(source, filename)
|
19
32
|
fname = uniq_html_filename(filename)
|
20
33
|
File.open(fname, 'w') do |f|
|
21
|
-
f.write(
|
34
|
+
f.write(wrap_page(source))
|
22
35
|
end
|
23
36
|
fname
|
24
37
|
end
|
data/lib/jsduck/stats.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
|
2
|
+
module JsDuck
|
3
|
+
|
4
|
+
# Calculates all kinds of statistics for classes
|
5
|
+
class Stats
|
6
|
+
# Maps array of classes into array of stats per class
|
7
|
+
def create(classes)
|
8
|
+
@classes = classes
|
9
|
+
|
10
|
+
classes.map do |cls|
|
11
|
+
local_members = cls.all_local_members
|
12
|
+
total_members = cls.all_members
|
13
|
+
class_wc = wc(cls[:doc])
|
14
|
+
members_wc = members_wc(cls)
|
15
|
+
|
16
|
+
{
|
17
|
+
:name => cls[:name],
|
18
|
+
|
19
|
+
:local_cfgs => member_count(local_members, :cfg),
|
20
|
+
:local_properties => member_count(local_members, :property),
|
21
|
+
:local_methods => member_count(local_members, :method),
|
22
|
+
:local_events => member_count(local_members, :event),
|
23
|
+
:local_members => local_members.length,
|
24
|
+
|
25
|
+
:total_cfgs => member_count(total_members, :cfg),
|
26
|
+
:total_properties => member_count(total_members, :property),
|
27
|
+
:total_methods => member_count(total_members, :method),
|
28
|
+
:total_events => member_count(total_members, :event),
|
29
|
+
:total_members => total_members.length,
|
30
|
+
|
31
|
+
:fanIn => fan_in(cls),
|
32
|
+
:fanOut => fan_out(cls),
|
33
|
+
|
34
|
+
:class_wc => class_wc,
|
35
|
+
:members_wc => members_wc,
|
36
|
+
:wc_per_member => local_members.length > 0 ? (members_wc / local_members.length) : 0,
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def member_count(members, type)
|
42
|
+
members.find_all {|m| m[:tagname] == type }.length
|
43
|
+
end
|
44
|
+
|
45
|
+
# How many classes depend on this class
|
46
|
+
def fan_in(cls)
|
47
|
+
fan_in_table[cls[:name]] || 0
|
48
|
+
end
|
49
|
+
|
50
|
+
# On how many classes this class depends on
|
51
|
+
def fan_out(cls)
|
52
|
+
dependencies(cls).length
|
53
|
+
end
|
54
|
+
|
55
|
+
# list of class names the class depends on
|
56
|
+
def dependencies(cls)
|
57
|
+
[
|
58
|
+
cls[:extends],
|
59
|
+
cls[:mixins],
|
60
|
+
cls[:requires],
|
61
|
+
cls[:uses],
|
62
|
+
].compact.flatten.sort.uniq
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns map of class names to its fan-in number.
|
66
|
+
def fan_in_table
|
67
|
+
return @fi_table if @fi_table
|
68
|
+
|
69
|
+
@fi_table = {}
|
70
|
+
@classes.each do |cls|
|
71
|
+
dependencies(cls).each do |d|
|
72
|
+
@fi_table[d] = (@fi_table[d] || 0) + 1
|
73
|
+
end
|
74
|
+
end
|
75
|
+
@fi_table
|
76
|
+
end
|
77
|
+
|
78
|
+
# Counts nr of words in documentation of all members of class
|
79
|
+
def members_wc(cls)
|
80
|
+
cnt = 0
|
81
|
+
cls.all_local_members.each do |m|
|
82
|
+
cnt += wc(m[:doc])
|
83
|
+
(m[:params] || []).each {|p| cnt += property_wc(p) }
|
84
|
+
(m[:properties] || []).each {|p| cnt += property_wc(p) }
|
85
|
+
cnt += wc(m[:return][:doc]) if m[:return]
|
86
|
+
end
|
87
|
+
cnt
|
88
|
+
end
|
89
|
+
|
90
|
+
def property_wc(property)
|
91
|
+
cnt = wc(property[:doc] || "")
|
92
|
+
(property[:properties] || []).each {|p| cnt += property_wc(p) }
|
93
|
+
cnt
|
94
|
+
end
|
95
|
+
|
96
|
+
# Strips HTML and counts words in text
|
97
|
+
def wc(str)
|
98
|
+
str.gsub(/<\/?[^>]*>/, "").scan(/\w+/).length
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|