line
stmt
bran
cond
sub
pod
time
code
1
#!/usr/bin/perl
2
#-------------------------------------------------------------------------------
3
# Extract documentation from Java source code.
4
# Philip R Brenan at gmail dot com, Appa Apps Ltd, 2017
5
#-------------------------------------------------------------------------------
6
# Override when we click on the method it should go to the overridden method and the comment can then be shortened
7
# Method should use a hash of fields, it currently uses an array
8
# returns in title should link to definition of that item
9
# class in title should link to definition of that class
10
package Java::Doc;
11
require v5.16.0;
12
1
1
478
use warnings FATAL => qw(all);
1
7
1
32
13
1
1
5
use strict;
1
1
1
19
14
1
1
4
use Carp qw(confess);
1
1
1
89
15
1
1
301
use Data::Dump qw(dump);
1
6138
1
71
16
1
1
560
use Data::Table::Text qw(:all);
1
44754
1
2512
17
18
our $VERSION = '20171012';
19
20
genLValueHashMethods(qw(parse)); # Combined parse tree of all the input files read
21
genLValueHashMethods(qw(classes)); # Classes encountered in all the input files read
22
23
my %veryWellKnownClassesHash = map {$_=>1} split /\n/, &veryWellKnownClasses; # Urls describing some well known Java classes
24
25
sub urlIfKnown($$) # Replace a well known type with an informative url
26
12
12
0
22
{my ($javaDoc, $type) = @_; # Java doc builder, type to replace with an informative url
27
12
44
for my $url(keys %veryWellKnownClassesHash, @{$javaDoc->wellKnownClasses})
12
212
28
237
370
{my $i = index($url, "/$type.html");
29
237
100
346
if ($i >= 0)
30
{#say STDERR "AAAA $i $type $url", ;
31
6
44
return qq($type );
32
}
33
}
34
$type
35
6
31
}
36
37
sub getAttributes($) # Get the attributes from a method type: public, private, final, static etc
38
12
12
0
20
{my ($type) = @_; # Type as parsed out
39
12
26
my $t = qq( $type ); # Blank pad
40
12
30
$t =~ s(\A\s*[\(\{]) ( )gs; # Replace leading open bracket with space
41
12
13
my @attributes; # Method attributes
42
12
20
for(qw(public private protected abstract final static))
43
72
100
488
{push @attributes, $_ if $t =~ m($_)s;
44
72
438
$t =~ s($_) ( )gs;
45
}
46
12
48
$t =~ s(\s+) ( )gs; # Remove excess white space
47
12
34
(trim($t), @attributes)
48
}
49
#say STDERR dump([getAttributes(" (final public static float ")]); exit;
50
51
sub parseJavaFile($$) # Parse java file for package, class, method, parameters
52
1
1
0
2
{my ($javaDoc, $fileOrString) = @_; # Java doc builder, Parse tree, java file or string of java to process
53
1
16
my $parse = $javaDoc->parse; # Parse tree
54
55
1
50
8
my $s = $fileOrString =~ m(\n)s ? $fileOrString : readFile($fileOrString);
56
57
1
9
my $package; # Package we are in
58
my @class; # Containing classes as array
59
1
0
my $class; # Containing classes as a.b.c
60
1
0
my $method; # Method we are in
61
1
12
my $state = 0; # 0 - outer, 1 - parameters to last method
62
63
1
2
my $line = 0; # Line numbers
64
1
10
for(split /\n/, $s)
65
30
69
{++$line;
66
30
100
53
if ($state == 0)
50
67
18
100
137
{if (m(\A\s*package\s+((\w+|\.)+))) # 'package' package ;
100
50
100
68
{#say STDERR "Package = $1";
69
1
3
$package = $1;
70
}
71
elsif (m(\A.*?class\s+(\w+)\s*\{?\s*//C\s+(.*?)\s*\Z)) # Class with optional '{' //C
72
2
7
{push @class, $1; # Save containing class
73
2
9
$class = join '.', @class;
74
#say STDERR "Class $class = $1 = $2";
75
2
47
$javaDoc->classes->{$class} = $parse->{$package}{$class}{comment} = $2; # Record the last encountered class as the class to link to - could be improved!
76
}
77
elsif (m(\A\s*}\s*//C\s+(\w+))) # '}' '//C' className - close class className
78
{#say STDERR "Class = $1 End";
79
0
0
0
if (!@class)
80
0
0
{warn "Closing class $1 but no class to close";
81
}
82
0
0
0
if ($1 ne $class[-1])
83
0
0
{warn "Closing class $1 but in class $class ignored";
84
}
85
else
86
{$parse->{$package}{$class}{methods} =
87
[sort
88
0
0
0
{my $r = $b->{res} cmp $a->{res}; return $r if $r;
0
0
89
0
0
0
my $n = $a->{name} cmp $b->{name}; return $n if $n;
0
0
90
0
0
my $c = $a->{comment} cmp $b->{comment}; return $c;
0
0
91
}
92
0
0
@{$parse->{$package}{$class}{methods}}];
0
0
93
94
0
0
pop @class;
95
0
0
$class = join '.', @class;
96
}
97
}
98
elsif # Method with either '()' meaning no parameters or optional '(' followed by //M for method, //c for constructor, //O=package.method for override of the named method
99
(m(\A\s*(.*?)
100
\s+(\w+)
101
\s*(\x28\s*\x29)?
102
\s*\x28?\s*
103
//(M|c|O=\S+)\s+(.*?)\s*\Z)x) # Comment
104
3
16
{my ($empty, $res, $comment) = ($3, $4, $5);
105
3
9
$method = $2;
106
107
3
7
my ($type, @attributes) = getAttributes($1); # Method attributes
108
109
3
26
my $override; # Method is an override
110
3
50
10
if ($res =~ m(\Ac\Z)s) # In summa it is a constructor
50
111
0
0
{push @attributes, q(constructor); # Constructor
112
0
0
$type = qq($method ); # Type for a constructor is the constructor name
113
}
114
elsif ($res =~ m(\AO=(.+?)\Z)s) # Override
115
0
0
{$override = $1;
116
0
0
0
my $dot = $comment =~ m(\.\Z)s ? '' : '.';
117
0
0
$comment = qq($comment$dot Overrides: $override );
118
}
119
120
3
50
33
14
if ($package and $class) # Save method details is possible
121
{#say STDERR "Method = $method == $type == $comment ";
122
123
3
4
push @{$parse->{$package}{$class}{methods}},
3
14
124
{type=>$javaDoc->urlIfKnown($type), name=>$method, res=>$res,
125
comment=>$comment, attributes=>[@attributes], line=>$line};
126
3
50
33
12
$state = 1 if !$empty and !$override; # Get parameters next if method has parameters and is not an override
127
}
128
else
129
0
0
{my $m = qq(Ignoring method $method as no preceding);
130
0
0
my $f = qq(in file:\n$fileOrString\nLine:\n$_);
131
0
0
0
warn "$m package $f" unless $package;
132
0
0
0
warn "$m class $f" unless $class;
133
}
134
}
135
}
136
elsif ($state == 1)
137
12
100
85
{if (m(\A.\s*(.+?)\s+(\w+)\s*[,\)\{]*\s*//P\s+(.*?)\s*\Z)) # type name, optional ',){', //P
138
{#say STDERR "Parameter =$1=$2=$3";
139
9
28
my ($type, $parameter, $comment) = ($1, $2, $3);
140
9
17
my ($t, @attributes) = getAttributes($type);
141
9
71
push @{$parse->{$package}{$class}{methods}[-1]{parameters}},
9
32
142
[$javaDoc->urlIfKnown($t), $parameter, $comment, [@attributes],
143
$line];
144
}
145
else # End of parameters if the line does not match
146
3
4
{$state = 0;
147
3
50
33
17
if ($package and $class and $method)
33
148
3
8
{my $m = $parse->{$package}{$class}{methods}[-1];
149
3
50
7
if (my $p = $m->{parameters})
150
3
50
8
{if (my @p = @$p)
151
3
5
{$m->{nameSig} = join ', ', map {$_->[1]} @p;
9
26
152
3
5
$m->{typeSig} = join ', ', map {$_->[0]} @p;
9
25
153
}
154
}
155
}
156
else
157
0
0
{warn "Ignoring method $method as no preceding package or class or ".
158
"method in file:\n$fileOrString\nLine:\n$_";
159
}
160
}
161
}
162
}
163
#say STDERR "AAAA ", dump($parse); exit;
164
$parse
165
1
6
}
166
167
sub parseJavaFiles($) # Parse all the input files into one parse tree
168
1
1
0
2
{my ($javaDoc) = @_; # Java doc processor
169
1
1
for(@{$javaDoc->source}) # Extend the parse tree with the parse of each source file
1
15
170
1
7
{$javaDoc->parseJavaFile($_);
171
}
172
}
173
174
sub htmlJavaFiles($) # Create documentation using html for all java files from combined parse tree
175
1
1
0
2
{my ($javaDoc) = @_; # Java doc processor, combined parse tree
176
1
19
my $parse = $javaDoc->parse; # Parse tree
177
1
50
18
my $indent = $javaDoc->indent // 0; # Indentation per level
178
1
10
my @c = @{$javaDoc->colors}; # Back ground colours
1
16
179
1
50
8
@c = 'white' unless @c;
180
1
2
my $d; # Current background colour - start
181
1
2
my $D = q(); # Current background colour - end
182
my $swapColours = sub # Swap background colour
183
7
7
9
{my ($margin) = @_;
184
7
9
my $m = $margin * $indent;
185
7
11
push @c, my $c = shift @c;
186
7
16
$d = qq();
187
1
10
};
188
1
4
&$swapColours(0); # Swap background colour
189
190
1
3
my @h = <
191
$d
192
193
194
195
196
Packages
197
204
$D
205
END
206
207
1
3
for my $package(sort keys %$parse)
208
1
1
{my %package = %{$parse->{$package}};
1
4
209
1
3
&$swapColours(1);
210
1
3
push @h, <
211
212
$d
213
Package: $package
214
215
Class Description
216
END
217
1
5
for my $class(sort keys %package)
218
2
5
{my %class = %{$package{$class}};
2
7
219
2
7
my $classComment = $class{comment};
220
2
18
push @h, <<"END";
221
$class
222
$classComment
223
224
END
225
}
226
1
5
push @h, <
227
228
$D
229
END
230
1
6
for my $class(sort keys %package)
231
2
2
{my %class = %{$package{$class}};
2
7
232
2
3
my $classComment = $class{comment};
233
2
4
&$swapColours(2);
234
2
7
push @h, <
235
$d
236
237
Class: $class , package: $package
238
$classComment
239
240
Returns Method Signature Attributes Line Description
241
END
242
2
3
for my $method(@{$class{methods}})
2
4
243
3
3
{my %method = %{$method};
3
14
244
3
50
5
my $attr = join ' ', @{$method{attributes}//[]};
3
9
245
3
4
my $type = $method{type};
246
3
5
my $name = $method{name};
247
3
3
my $comment = $method{comment};
248
3
4
my $line = $method{line};
249
3
50
7
my $sig = $method{typeSig} // 'void';
250
3
20
push @h, <
251
$type
252
$name
253
$sig
254
$attr
255
$line
256
$comment
257
258
END
259
}
260
2
5
push @h, <
261
262
$D
263
END
264
2
3
for my $method(@{$class{methods}})
2
3
265
3
4
{my %method = %{$method};
3
10
266
3
6
my $type = $method{type};
267
3
3
my $name = $method{name};
268
3
4
my $comment = $method{comment};
269
3
20
&$swapColours(3);
270
3
12
push @h, <
271
$d
272
273
$name returns $type --- in class $class
274
$comment
275
END
276
277
3
50
14
if (my $parameters = $method{parameters})
278
3
6
{my @parameters = @$parameters;
279
3
4
push @h, <
280
281
Name Type Line Description
282
END
283
3
6
for my $parameter(@parameters)
284
9
15
{my ($type, $name, $comment, $attributes, $line) = @$parameter;
285
9
50
9
my $attr = join ' ', @{$attributes//[]};
9
20
286
9
26
push @h, qq( $name $type $line $comment );
287
}
288
3
6
push @h, <
289
290
END
291
}
292
3
10
push @h, <
293
$D
294
295
END
296
}
297
}
298
}
299
300
1
11
s(L<(.+?)>) ($1 )gs for @h;
301
302
@h
303
1
9
}
304
305
1
1
0
10
sub veryWellKnownClasses {<<'END'}
306
https://developer.android.com/reference/android/app/Activity.html
307
https://developer.android.com/reference/android/content/Context.html
308
https://developer.android.com/reference/android/graphics/BitmapFactory.html
309
https://developer.android.com/reference/android/graphics/Bitmap.html
310
https://developer.android.com/reference/android/graphics/Canvas.html
311
https://developer.android.com/reference/android/graphics/drawable/BitmapDrawable.html
312
https://developer.android.com/reference/android/graphics/drawable/Drawable.html
313
https://developer.android.com/reference/android/graphics/Matrix.html
314
https://developer.android.com/reference/android/graphics/Paint.html
315
https://developer.android.com/reference/android/graphics/Path.html
316
https://developer.android.com/reference/android/graphics/PorterDuff.Mode.html
317
https://developer.android.com/reference/android/graphics/RectF.html
318
https://developer.android.com/reference/android/media/MediaPlayer.html
319
https://developer.android.com/reference/android/util/DisplayMetrics.html
320
https://developer.android.com/reference/java/io/ByteArrayOutputStream.html
321
https://developer.android.com/reference/java/io/DataInputStream.html
322
https://developer.android.com/reference/java/io/DataOutputStream.html
323
https://developer.android.com/reference/java/io/File.html
324
https://developer.android.com/reference/java/io/FileOutputStream.html
325
https://developer.android.com/reference/java/lang/String.html
326
https://developer.android.com/reference/java/lang/Thread.html
327
https://developer.android.com/reference/java/util/Stack.html
328
https://developer.android.com/reference/java/util/TreeMap.html
329
https://developer.android.com/reference/java/util/TreeSet.html
330
https://developer.android.com/studio/command-line/adb.html
331
END
332
333
#1 Attributes # Attributes that can be set or retrieved by assignment
334
335
if (1) { # Parameters that can be set by the caller
336
genLValueArrayMethods(qw(source)); # A reference to an array of Java source files that contain documentation as well as java
337
genLValueScalarMethods(qw(target)); # Name of the file to contain the generated documentation
338
genLValueArrayMethods(qw(wellKnownClasses)); # A reference to an array of urls that contain the class name of well known Java classes such as: L which will be used in place of the class name to make it possible to locate definitions of these other classes.
339
genLValueScalarMethods(qw(indent)); # Indentation for methods vs classes and classes vs packages - defaults to 0
340
genLValueArrayMethods(qw(colors)); # A reference to an array of colours expressed in html format - defaults to B - the background applied to each output section is cycled through these colours to individuate each section.
341
}
342
343
#1 Methods # Methods available
344
345
sub new # Create a new java doc processor
346
1
1
1
16
{bless {}; # Java doc processor
347
}
348
349
sub html($) # Create documentation using html as the output format. Write the generated html to the file specified by L if any and return the generated html as an array of lines.
350
1
1
1
3
{my ($javaDoc) = @_; # Java doc processor
351
352
1
4
$javaDoc->parseJavaFiles; # Parse the input files
353
#say STDERR "AAAA ", dump($javaDoc->parse); exit;
354
1
3
my @h = $javaDoc->htmlJavaFiles; # Write as html
355
356
1
50
26
if (my $file = $javaDoc->target)
357
0
0
{my $h = @h;
358
0
0
writeFile($file, join "\n", @h);
359
0
0
say STDERR "$h lines of documentation written to:\n$file";
360
}
361
@h # Return the generated html
362
1
25
}
363
364
# podDocumentation
365
366
=encoding utf-8
367
368
=head1 Name
369
370
Java::Doc - Extract L
371
from L
372
373
=head1 Synopsis
374
375
use Java::Doc;
376
377
my $j = Java::Doc::new; # New document builder
378
379
$j->source = [qw(~/java/layoutText/LayoutText.java)]; # Source files
380
$j->target = qq(~/java/documentation.html); # Output html
381
$j->indent = 20; # Indentation
382
$j->colors = [map {"#$_"} qw(ccFFFF FFccFF FFFFcc), # Background colours
383
qw(CCccFF FFCCcc ccFFCC)];
384
$j->html; # Create html
385
386
Each source file is parsed for documentation information which is then
387
collated into a colorful cross referenced html file.
388
389
Documentation is extracted for L, L,
390
L.
391
392
=head2 Packages
393
394
Lines matching
395
396
package packageName ;
397
398
are assumed to define packages.
399
400
=head2 Classes
401
402
Lines with comments B/C> are assumed to define classes:
403
404
class className //C
405
406
with the text of the comment being the definition of the class.
407
408
Classes are terminated with:
409
410
} //C className
411
412
which allows class document definitions to be nested.
413
414
=head2 Methods
415
416
Methods are specified by lines with comments matching B/M>:
417
418
methodName () //M
419
420
methodName //M
421
422
with the description of the method contained in the text of the comment
423
extending to the end of the line.
424
425
Constructors should be marked with comments matching B/c> as in:
426
427
methodName //c
428
429
Methods that are overridden should be noted with a comment as in:
430
431
methodName //O=package.class.method
432
433
=head2 Parameters
434
435
Methods that are not overrides and that do have parameters should place the
436
parameters declarations one per line on succeeding lines marked with comments
437
B/P> as in:
438
439
parameterName //P
440
441
=head2 Example
442
443
The following fragment of java code provides an example of documentation held as
444
comments that can be processed by this module:
445
446
package com.appaapps;
447
448
public class Outer //C Layout text on a canvas
449
{public static void draw //M Draw text to fill a fractional area of the canvas
450
(final Canvas canvas) //P Canvas to draw on
451
{}
452
453
class Inner //C Inner class
454
{InnerText() //c Constructor
455
{}
456
} //C Inner
457
} //C Outer
458
459
=head1 Description
460
461
The following sections describe the methods in each functional area of this
462
module. For an alphabetic listing of all methods by name see L.
463
464
465
466
=head1 Attributes
467
468
Attributes that can be set or retrieved by assignment
469
470
=head2 source :lvalue
471
472
A reference to an array of Java source files that contain documentation as well as java
473
474
475
=head2 target :lvalue
476
477
Name of the file to contain the generated documentation
478
479
480
=head2 wellKnownClasses :lvalue
481
482
A reference to an array of urls that contain the class name of well known Java classes such as: L which will be used in place of the class name to make it possible to locate definitions of these other classes.
483
484
485
=head2 indent :lvalue
486
487
Indentation for methods vs classes and classes vs packages - defaults to 0
488
489
490
=head2 colors :lvalue
491
492
A reference to an array of colours expressed in html format - defaults to B - the background applied to each output section is cycled through these colours to individuate each section.
493
494
495
=head1 Methods
496
497
Methods available
498
499
=head2 new()
500
501
Create a new java doc processor
502
503
504
=head2 html($)
505
506
Create documentation using html as the output format. Write the generated html to the file specified by L if any and return the generated html as an array of lines.
507
508
1 $javaDoc Java doc processor
509
510
511
=head1 Index
512
513
514
1 L
515
516
2 L
517
518
3 L
519
520
4 L
521
522
5 L
523
524
6 L
525
526
7 L
527
528
=head1 Installation
529
530
This module is written in 100% Pure Perl and, thus, it is easy to read, use,
531
modify and install.
532
533
Standard L process for building and installing modules:
534
535
perl Build.PL
536
./Build
537
./Build test
538
./Build install
539
540
=head1 Author
541
542
L
543
544
L
545
546
=head1 Copyright
547
548
Copyright (c) 2016-2017 Philip R Brenan.
549
550
This module is free software. It may be used, redistributed and/or modified
551
under the same terms as Perl itself.
552
553
=cut
554
555
556
557
# Tests and documentation
558
559
sub test
560
1
1
0
10
{my $p = __PACKAGE__;
561
1
8
binmode($_, ":utf8") for *STDOUT, *STDERR;
562
1
50
64
return if eval "eof(${p}::DATA)";
563
1
41
my $s = eval "join('', <${p}::DATA>)";
564
1
50
8
$@ and die $@;
565
1
1
449
eval $s;
1
49120
1
8
1
66
566
1
50
466
$@ and die $@;
567
}
568
569
test unless caller;
570
571
1;
572
# podDocumentation
573
__DATA__