Skip to content

Commit

Permalink
Add Javadoc comments (#91)
Browse files Browse the repository at this point in the history
  • Loading branch information
sanderploegsma authored Jan 23, 2024
1 parent 8137eec commit 0fcbce1
Show file tree
Hide file tree
Showing 61 changed files with 498 additions and 424 deletions.
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Start by reading up on Exercism analyzers:

To learn how the Java Analyzer works:

- Read the [project documentation][project-documentation].
- Browse [existing exercise analyzer implementations][browse-analyzers].

### Writing comments
Expand All @@ -46,3 +47,4 @@ See [the Analyzer comment guidelines][analyzer-comments-guidelines] for guidance
[analyzer-docs-interface]: https://exercism.org/docs/building/tooling/analyzers/interface
[community-docs]: https://exercism.org/docs/community/being-a-good-community-member
[contributing-docs-github]: https://exercism.org/docs/building/github
[project-documentation]: https://exercism.github.io/java-analyzer/
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

The Java analyzer uses [Abstract Syntax Trees][ast-wiki] (ASTs) to analyze submitted solutions using the [`javaparser`][javaparser] library.

The documentation for this project can be found at [exercism.github.io/java-analyzer/][documentation].

## Contributing

If you want to contribute to the Java analyzer, please refer to the [Contributing Guide][contributing-guide].
Expand Down Expand Up @@ -62,4 +64,5 @@ bin/run-tests-in-docker.sh

[ast-wiki]: https://en.wikipedia.org/wiki/Abstract_syntax_tree
[contributing-guide]: https://github.com/exercism/java-analyzer/blob/main/CONTRIBUTING.md
[javaparser]: https://github.com/javaparser/javaparser
[documentation]: https://exercism.github.io/java-analyzer/
[javaparser]: https://github.com/javaparser/javaparser
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ plugins {

group = "org.exercism"
version = "1.0-SNAPSHOT"
mainClassName = "analyzer.Main"
mainClassName = "analyzer.AnalyzerCli"

repositories {
mavenCentral()
Expand Down
6 changes: 6 additions & 0 deletions src/doc/docs/index.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# Welcome to exercism/java-analyzer

Welcome to the Exercism Java analyzer documentation! 👋

!!! note
This documentation is still under construction.
In the meantime, we suggest having a look at the [Javadoc][javadoc].

[javadoc]: /java-analyzer/api/
39 changes: 39 additions & 0 deletions src/main/java/analyzer/Analysis.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,72 @@
import java.util.Set;

/**
* This class is used to collect analysis results in the form of comments, tags and an optional summary.
*
* @see <a href="https://exercism.org/docs/building/tooling/analyzers/interface">The analyzer interface in the Exercism documentation</a>
*/
public class Analysis {
private String summary;
private final Set<Comment> comments = new LinkedHashSet<>();
private final Set<String> tags = new LinkedHashSet<>();

/**
* The summary is a short description of the complete analysis result.
* It is {@code null} by default.
*
* @return The summary if set, {@code null} otherwise.
*/
public String getSummary() {
return summary;
}

/**
* Set the summary of the analysis.
* If the summary was set previously, setting it again will overwrite it.
* The summary can be cleared by setting it to {@code null}.
*
* @param summary The summary to set.
*/
public void setSummary(String summary) {
this.summary = summary;
}

/**
* Retrieve a copy of the comments added to this analysis.
* The resulting list is guaranteed to contain no duplicates.
*
* @return List of comments.
*/
public List<Comment> getComments() {
return List.copyOf(comments);
}

/**
* Retrieve a copy of the tags added to this analysis.
* The resulting list is guaranteed to contain no duplicates.
*
* @return List of tags.
*/
public List<String> getTags() {
return List.copyOf(tags);
}

/**
* Add a new comment to the analysis.
* This does nothing if a comment with the same values was added previously.
*
* @param comment The comment to add.
*/
public void addComment(Comment comment) {
comments.add(comment);
}

/**
* Add a new tag to the analysis.
* This does nothing if the same tag was added previously.
*
* @param tag The tag to add.
*/
public void addTag(String tag) {
tags.add(tag);
}
Expand Down
18 changes: 13 additions & 5 deletions src/main/java/analyzer/Analyzer.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
package analyzer;

import com.github.javaparser.ast.CompilationUnit;

import java.util.List;

/**
* The {@code Analyzer} interface is used to implement both global and exercise-specific analyzers.
*/
public interface Analyzer {
void analyze(List<CompilationUnit> compilationUnits, Analysis analysis);
/**
* Analyze the given solution and append analysis results to the given analysis.
* The {@code analyze} method of each analyzer is invoked once for the whole submitted solution.
*
* @param solution The solution that should be analyzed.
* @param analysis The analysis instance used to collect results.
* This instance is shared across all analyzers, and should be used to add comments and tags,
* or set a summary.
*/
void analyze(Solution solution, Analysis analysis);
}
50 changes: 50 additions & 0 deletions src/main/java/analyzer/AnalyzerCli.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package analyzer;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Path;

/**
* The main entrypoint to the Java analyzer from the command-line.
* The CLI expects three arguments and is used like this:
*
* <pre>
* java -jar java-analyzer.jar exercise-slug /path/to/input/ /path/to/output/
* </pre>
*/
public class AnalyzerCli {

private static boolean isNotValidDirectory(String p) {
return !p.endsWith("/") || !new File(p).isDirectory();
}

public static void main(String... args) throws IOException {
if (args.length < 3) {
System.err.println("Invalid arguments. Usage: java-analyzer <exercise slug> <exercise directory> <output directory>");
System.exit(-1);
}

String slug = args[0];
String inputDirectory = args[1];
String outputDirectory = args[2];

if (isNotValidDirectory(inputDirectory)) {
System.err.println("Invalid input directory. Must be a valid directory and end with a slash.");
System.exit(-1);
}
if (isNotValidDirectory(outputDirectory)) {
System.err.println("Invalid output directory. Must be a valid directory and end with a slash.");
System.exit(-1);
}

var solution = new SubmittedSolution(slug, Path.of(inputDirectory));
var analysis = AnalyzerRoot.analyze(solution);

try (var analysisWriter = new FileWriter(Path.of(outputDirectory, "analysis.json").toFile());
var tagsWriter = new FileWriter(Path.of(outputDirectory, "tags.json").toFile())) {
var output = new OutputWriter(analysisWriter, tagsWriter);
output.write(analysis);
}
}
}
22 changes: 17 additions & 5 deletions src/main/java/analyzer/AnalyzerRoot.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,33 @@
import analyzer.exercises.lasagna.LasagnaAnalyzer;
import analyzer.exercises.leap.LeapAnalyzer;
import analyzer.exercises.twofer.TwoferAnalyzer;
import com.github.javaparser.ast.CompilationUnit;

import java.util.ArrayList;
import java.util.List;

/**
* The {@code AnalyzerRoot} is the initial entrypoint when analyzing a solution.
* Its job is to delegate the analysis of the parsed Java files to the global and exercise-specific analyzers.
*/
public class AnalyzerRoot {

public static Analysis analyze(String slug, List<CompilationUnit> compilationUnits) {
private AnalyzerRoot() {
}

/**
* Perform the analysis of a solution.
*
* @param solution The solution being analyzed.
* @return The aggregated analysis of all applicable analyzers.
*/
public static Analysis analyze(Solution solution) {
var analysis = new Analysis();

for (Analyzer analyzer : createAnalyzers(slug)) {
analyzer.analyze(compilationUnits, analysis);
for (Analyzer analyzer : createAnalyzers(solution.getSlug())) {
analyzer.analyze(solution, analysis);
}

if (analysis.getComments().stream().anyMatch(x -> x.getType() != CommentType.CELEBRATORY)) {
if (analysis.getComments().stream().anyMatch(x -> x.getType() != Comment.Type.CELEBRATORY)) {
analysis.addComment(new FeedbackRequest());
}

Expand Down
68 changes: 66 additions & 2 deletions src/main/java/analyzer/Comment.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,82 @@
import java.util.Objects;

/**
* The {@link Comment} class models a single comment in the analysis output.
* Each comment has a unique key that translates to a Markdown template in the
* <a href="https://github.com/exercism/website-copy">exercism/website-copy</a> repository.
* <p>
* If the Markdown template contains any parameters, classes inheriting from {@link Comment} should override the
* {@link Comment#getParameters()} method to return the parameter keys and values specific to that template.
* <p>
* Override the {@link Comment#getType()} method to change the {@link Type} associated to the comment.
*
* @see <a href="https://exercism.org/docs/building/tooling/analyzers/interface">The analyzer interface in the Exercism documentation</a>
* @see <a href="https://github.com/exercism/website-copy/tree/main/analyzer-comments/java">Analyzer comments for the Java track in the website-copy</a>
*/
public abstract class Comment {

/**
* The type of comment.
* Note that the order defined here corresponds to the order in which comments are sorted in the analyzer output.
*
* @see <a href="https://exercism.org/docs/building/tooling/analyzers/interface#h-type-optional">Documentation on comment types</a>
*/
public enum Type {
ESSENTIAL,
ACTIONABLE,
INFORMATIVE,
CELEBRATORY
}

/**
* The comment key is a {@link String} that uniquely identifies the comment.
* <p>
* Comment keys use the format {@code "java.<scope>.<name>"}.
* The {@code <scope>} can be either {@code general} for general comments,
* or the slug of the exercise for exercise-specific comments.
* The {@code <name>} specifies the name of the comment.
* <p>
* The combination of {@code <scope>} and {@code <name>} must be unique, and defines the location of the
* Markdown template in the <a href="https://github.com/exercism/website-copy">exercism/website-copy</a> repository.
* <p>
* For example, the comment key {@code "java.hello-world.foo_bar"} would translate to the Markdown file at
* {@code analyzer-comments/java/hello-world/foo_bar.md}.
*
* @return The unique comment key.
*/
public abstract String getKey();

/**
* Each parameter in the Markdown template should have a corresponding parameter in the comment.
* Parameters in Markdown templates are of the form {@code %<parameterName>s}.
* <p>
* For example, if the Markdown template contains a parameter {@code %<methodName>s},
* the implementation of this method could look like this:
* <pre>{@code
* public Map<String, String> getParameters() {
* return Map.of("methodName", "theNameOfTheMethod");
* }
* }</pre>
*
* @return The parameters for the comment.
*/
public Map<String, String> getParameters() {
return Map.of();
}

public CommentType getType() {
return CommentType.INFORMATIVE;
/**
* <ul>
* <li>Use {@link Type#ESSENTIAL} to instruct students that they <b>must</b> address it.</li>
* <li>Use {@link Type#ACTIONABLE} to instruct students that they could improve their solution by addressing it.</li>
* <li>Use {@link Type#INFORMATIVE} to give students extra information without expecting them to use it.</li>
* <li>Use {@link Type#CELEBRATORY} to tell students that they did something right.</li>
* </ul>
*
* @return The type of the comment.
* @see <a href="https://exercism.org/docs/building/tooling/analyzers/interface#h-type-optional">Documentation on comment types</a>
*/
public Type getType() {
return Type.INFORMATIVE;
}

@Override
Expand Down
11 changes: 0 additions & 11 deletions src/main/java/analyzer/CommentType.java

This file was deleted.

68 changes: 0 additions & 68 deletions src/main/java/analyzer/Main.java

This file was deleted.

Loading

0 comments on commit 0fcbce1

Please sign in to comment.