@@ -7,6 +7,12 @@ class RDoc::Stats
77
88 include RDoc ::Text
99
10+ TYPE_ORDER = %w[ Class Module Constant Attribute Method ] . freeze
11+ GREAT_JOB_MESSAGE = <<~MSG
12+ 100% documentation!
13+ Great Job!
14+ MSG
15+
1016 ##
1117 # Output level for the coverage report
1218
@@ -193,17 +199,6 @@ def fully_documented?
193199 @fully_documented
194200 end
195201
196- ##
197- # A report that says you did a great job!
198-
199- def great_job
200- report = RDoc ::Markup ::Document . new
201-
202- report << RDoc ::Markup ::Paragraph . new ( '100% documentation!' )
203- report << RDoc ::Markup ::Paragraph . new ( 'Great Job!' )
204-
205- report
206- end
207202
208203 ##
209204 # Calculates the percentage of items documented.
@@ -230,164 +225,167 @@ def report
230225 if @coverage_level . zero? then
231226 calculate
232227
233- return great_job if @num_items == @doc_items
228+ return GREAT_JOB_MESSAGE if @num_items == @doc_items
234229 end
235230
236- ucm = @store . unique_classes_and_modules
231+ items , empty_classes = collect_undocumented_items
237232
238- report = RDoc ::Markup ::Document . new
239- report << RDoc ::Markup ::Paragraph . new ( 'The following items are not documented:' )
240- report << RDoc ::Markup ::BlankLine . new
241-
242- ucm . sort . each do |cm |
243- body = report_class_module ( cm ) {
244- [
245- report_constants ( cm ) ,
246- report_attributes ( cm ) ,
247- report_methods ( cm ) ,
248- ] . compact
249- }
233+ if @coverage_level > 0 then
234+ calculate
250235
251- report << body if body
236+ return GREAT_JOB_MESSAGE if @num_items == @doc_items
252237 end
253238
254- if @coverage_level > 0 then
255- calculate
239+ report = + ""
240+ report << "The following items are not documented: \n \n "
256241
257- return great_job if @num_items == @doc_items
242+ # Referenced-but-empty classes
243+ empty_classes . each do |cm |
244+ report << "#{ cm . full_name } is referenced but empty.\n "
245+ report << "It probably came from another project. I'm sorry I'm holding it against you.\n \n "
258246 end
259247
260- report
261- end
248+ # Group items by file, then by type
249+ by_file = items . group_by { | item | item [ :file ] }
262250
263- ##
264- # Returns a report on undocumented attributes in ClassModule +cm+
251+ by_file . sort_by { | file , _ | file } . each do | file , file_items |
252+ report << " #{ file } : \n "
265253
266- def report_attributes ( cm )
267- return if cm . attributes . empty?
254+ by_type = file_items . group_by { |item | item [ :type ] }
268255
269- report = [ ]
256+ TYPE_ORDER . each do |type |
257+ next unless by_type [ type ]
258+
259+ report << " #{ type } :\n "
260+
261+ sorted = by_type [ type ] . sort_by { |item | [ item [ :line ] || 0 , item [ :name ] ] }
262+ name_width = sorted . reduce ( 0 ) { |max , item | item [ :line ] && item [ :name ] . length > max ? item [ :name ] . length : max }
263+
264+ sorted . each do |item |
265+ if item [ :line ]
266+ report << " %-*s %s:%d\n " % [ name_width , item [ :name ] , item [ :file ] , item [ :line ] ]
267+ else
268+ report << " #{ item [ :name ] } \n "
269+ end
270+
271+ if item [ :undoc_params ]
272+ report << " Undocumented params: #{ item [ :undoc_params ] . join ( ', ' ) } \n "
273+ end
274+ end
275+ end
270276
271- cm . attributes . each do |attr |
272- next if attr . documented?
273- line = attr . line ? ":#{ attr . line } " : nil
274- report << " #{ attr . definition } :#{ attr . name } # in file #{ attr . file . full_name } #{ line } \n "
275277 report << "\n "
276278 end
277279
278280 report
279281 end
280282
281283 ##
282- # Returns a report on undocumented items in ClassModule +cm+
284+ # Collects all undocumented items across all classes and modules.
285+ # Returns [items, empty_classes] where items is an Array of Hashes
286+ # with keys :type, :name, :file, :line, and empty_classes is an
287+ # Array of ClassModule objects that are referenced but have no files.
283288
284- def report_class_module ( cm )
285- return if cm . fully_documented? and @coverage_level . zero?
286- return unless cm . display?
289+ def collect_undocumented_items
290+ empty_classes = [ ]
291+ items = [ ]
287292
288- report = RDoc ::Markup ::Document . new
293+ @store . unique_classes_and_modules . each do |cm |
294+ next unless cm . display?
289295
290- if cm . in_files . empty? then
291- report << RDoc ::Markup ::Paragraph . new ( "#{ cm . definition } is referenced but empty." )
292- report << RDoc ::Markup ::Paragraph . new ( "It probably came from another project. I'm sorry I'm holding it against you." )
293-
294- return report
295- elsif cm . documented? then
296- documented = true
297- klass = RDoc ::Markup ::Verbatim . new ( "#{ cm . definition } # is documented\n " )
298- else
299- report << RDoc ::Markup ::Paragraph . new ( 'In files:' )
300-
301- list = RDoc ::Markup ::List . new :BULLET
302-
303- cm . in_files . each do |file |
304- para = RDoc ::Markup ::Paragraph . new file . full_name
305- list << RDoc ::Markup ::ListItem . new ( nil , para )
296+ if cm . in_files . empty?
297+ empty_classes << cm
298+ next
306299 end
307300
308- report << list
309- report << RDoc ::Markup ::BlankLine . new
301+ unless cm . documented? || cm . full_name == 'Object'
302+ file = cm . in_files . first &.full_name
303+ items << { type : cm . type . capitalize , name : cm . full_name , file : file , line : nil } if file
304+ end
310305
311- klass = RDoc ::Markup ::Verbatim . new ( "#{ cm . definition } \n " )
306+ collect_undocumented_constants ( cm , items )
307+ collect_undocumented_attributes ( cm , items )
308+ collect_undocumented_methods ( cm , items )
312309 end
313310
314- klass << "\n "
315-
316- body = yield . flatten # HACK remove #flatten
317-
318- if body . empty? then
319- return if documented
311+ [ items , empty_classes ]
312+ end
320313
321- klass . parts . pop
322- else
323- klass . parts . concat body
324- end
314+ ##
315+ # Collects undocumented constants from +cm+ into +items+.
325316
326- klass << "end\n "
317+ def collect_undocumented_constants ( cm , items )
318+ cm . constants . each do |constant |
319+ next if constant . documented? || constant . is_alias_for
327320
328- report << klass
321+ file = constant . file &.full_name
322+ next unless file
329323
330- report
324+ items << {
325+ type : "Constant" ,
326+ name : constant . full_name ,
327+ file : file ,
328+ line : constant . line ,
329+ }
330+ end
331331 end
332332
333333 ##
334- # Returns a report on undocumented constants in ClassModule +cm+
334+ # Collects undocumented attributes from +cm+ into +items+.
335335
336- def report_constants ( cm )
337- return if cm . constants . empty?
338-
339- report = [ ]
336+ def collect_undocumented_attributes ( cm , items )
337+ cm . attributes . each do |attr |
338+ next if attr . documented?
340339
341- cm . constants . each do |constant |
342- # TODO constant aliases are listed in the summary but not reported
343- # figure out what to do here
344- next if constant . documented? || constant . is_alias_for
340+ file = attr . file &.full_name
341+ next unless file
345342
346- line = constant . line ? ":#{ constant . line } " : line
347- report << " # in file #{ constant . file . full_name } #{ line } \n "
348- report << " #{ constant . name } = nil\n "
349- report << "\n "
343+ scope = attr . singleton ? "." : "#"
344+ items << {
345+ type : "Attribute" ,
346+ name : "#{ cm . full_name } #{ scope } #{ attr . name } " ,
347+ file : file ,
348+ line : attr . line ,
349+ }
350350 end
351-
352- report
353351 end
354352
355353 ##
356- # Returns a report on undocumented methods in ClassModule +cm+
357-
358- def report_methods ( cm )
359- return if cm . method_list . empty?
360-
361- report = [ ]
354+ # Collects undocumented methods from +cm+ into +items+.
355+ # At coverage level > 0, also counts undocumented parameters.
362356
357+ def collect_undocumented_methods ( cm , items )
363358 cm . each_method do |method |
364- next if method . documented? and @coverage_level . zero?
359+ next if method . documented? && @coverage_level . zero?
365360
366- if @coverage_level > 0 then
367- params , undoc = undoc_params method
361+ undoc_param_names = nil
368362
363+ if @coverage_level > 0
364+ params , undoc = undoc_params method
369365 @num_params += params
370366
371- unless undoc . empty? then
367+ unless undoc . empty?
372368 @undoc_params += undoc . length
373-
374- undoc = undoc . map do |param | "+#{ param } +" end
375- param_report = " # #{ undoc . join ', ' } is not documented\n "
369+ undoc_param_names = undoc
376370 end
377371 end
378372
379- next if method . documented? and not param_report
373+ next if method . documented? && ! undoc_param_names
380374
381- line = method . line ? ": #{ method . line } " : nil
382- scope = method . singleton ? 'self.' : nil
375+ file = method . file &. full_name
376+ next unless file
383377
384- report << " # in file #{ method . file . full_name } #{ line } \n "
385- report << param_report if param_report
386- report << " def #{ scope } #{ method . name } #{ method . params } ; end\n "
387- report << "\n "
388- end
378+ scope = method . singleton ? "." : "#"
379+ item = {
380+ type : "Method" ,
381+ name : "#{ cm . full_name } #{ scope } #{ method . name } " ,
382+ file : file ,
383+ line : method . line ,
384+ }
385+ item [ :undoc_params ] = undoc_param_names if undoc_param_names
389386
390- report
387+ items << item
388+ end
391389 end
392390
393391 ##
@@ -407,12 +405,10 @@ def summary
407405 @undoc_params ,
408406 ] . max . to_s . length
409407
410- report = RDoc :: Markup :: Verbatim . new
408+ report = + ""
411409
412410 report << "Files: %*d\n " % [ num_width , @num_files ]
413-
414411 report << "\n "
415-
416412 report << "Classes: %*d (%*d undocumented)\n " % [
417413 num_width , @num_classes , undoc_width , @undoc_classes ]
418414 report << "Modules: %*d (%*d undocumented)\n " % [
@@ -426,17 +422,14 @@ def summary
426422 report << "Parameters: %*d (%*d undocumented)\n " % [
427423 num_width , @num_params , undoc_width , @undoc_params ] if
428424 @coverage_level > 0
429-
430425 report << "\n "
431-
432426 report << "Total: %*d (%*d undocumented)\n " % [
433427 num_width , @num_items , undoc_width , @undoc_items ]
434-
435428 report << "%6.2f%% documented\n " % percent_doc
436429 report << "\n "
437430 report << "Elapsed: %0.1fs\n " % ( Time . now - @start )
438431
439- RDoc :: Markup :: Document . new report
432+ report
440433 end
441434
442435 ##
0 commit comments