jsduck 3.0.1 → 3.1.0
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 +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
|