Skip to content

Commit

Permalink
docs: add documentation on command creation and command manager confi…
Browse files Browse the repository at this point in the history
…guration
  • Loading branch information
yusshu committed Oct 20, 2023
1 parent 388f67e commit 6ef8aa3
Show file tree
Hide file tree
Showing 21 changed files with 410 additions and 4 deletions.
14 changes: 13 additions & 1 deletion docs/annotated/annotated.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,20 @@ using annotated classes and methods.
The annotated command API is just an alternative way to create `Command` instances,
we use this instead of the classic `Command.builder(String)` method.

### Comparison

You can make a side-by-side comparison of the two approaches in the following table
and links:

| Imperative | Annotated |
|----------------------------------------------------------------------------|-------------------------------------------------------------------------|
| [Basic Command Creation](../imperatively/basic.md) | [Basic Command Creation](../annotated/basic.md) |
| [Command with single Argument](../imperatively/argument.md) | [Command with single Argument](../annotated/argument.md) |
| [Command with multiple Arguments](../imperatively/multiple-arguments.md) | [Command with multiple Arguments](../annotated/multiple-arguments.md) |
| [Command with optional Arguments](../imperatively/optional-arguments.md) | [Command with optional Arguments](../annotated/optional-arguments.md) |

### Elements of the Annotated Command API

The annotated command API is composed of 3 elements:
The annotated command API is composed of:
- The `@Command` annotation and others.
- The `AnnotatedCommandTreeBuilder` interface
20 changes: 20 additions & 0 deletions docs/annotated/argument.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
## #2 With Arguments

Check this command example with a single argument:

```java
@Command(names = "hello")
public class TestCommand implements CommandClass {

@Command(names = "")
public void run(String name) {
System.out.println("Hi " + name);
}

}
```

In this example:
- Executing `hello yusshu` will print `Hi yusshu`
- Executing `hello Fixed` will print `Hi Fixed`
- Executing `hello` will result in an error
18 changes: 18 additions & 0 deletions docs/annotated/basic.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
## #1 Basic Command

Check this basic command example, with no arguments, no subcommands and no permissions,
using the annotated command creation approach:

```java
@Command(names = "test")
public class TestCommand implements CommandClass {

@Command(names = "")
public void run() {
System.out.println("Hello World!");
}

}
```

Executing `test` will print `Hello World!`
6 changes: 5 additions & 1 deletion docs/annotated/index.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@ annotated.md
command-class.md
command-tree-builder.md
part-injector.md
subcommand-instance-creator.md
subcommand-instance-creator.md
basic.md
argument.md
multiple-arguments.md
optional-arguments.md
25 changes: 25 additions & 0 deletions docs/annotated/multiple-arguments.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
## #3 Command with Multiple Args

This example shows how to create a command with multiple arguments
using the annotated approach:

```java
@Command(names = "greet")
public class GreetingCommand implements CommandClass {

@Command(names = "")
public void run(String name, boolean formal) {
if (formal) {
System.out.println("Hello, " + name + "!");
} else {
System.out.println("Hi, " + name + "!");
}
}

}
```

- Executing `greet John false` will print `Hi, John!`
- Executing `greet John true` will print `Hello, John!`
- Executing `greet John` will result in a usage error
- Executing `greet` will result in a usage error
24 changes: 24 additions & 0 deletions docs/annotated/optional-arguments.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
## #4 With Optional Args

This example shows how to create a command with optional arguments
with the annotated approach:

```java
@Command(names = "greet")
public class GreetingCommand implements CommandClass {

@Command(names = "")
public void run(String name, @OptArg("Mr.") String title) {
System.out.println("Hello, " + title + " " + name + "!");
}

}
```

The `@OptArg` annotation is used to mark an argument as optional, and
it accepts a default value as a parameter, which will be used if the
argument is not present in the input.

- Executing `greet John` will print `Hello, Mr. John!`
- Executing `greet John Dr.` will print `Hello, Dr. John!`
- Executing `greet John Mr.` will print `Hello, Mr. John!`
3 changes: 2 additions & 1 deletion docs/concepts/index.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
command.md
command-manager.md
command-part.md
command-context.md
command-context.md
namespaces.md
34 changes: 34 additions & 0 deletions docs/concepts/namespaces.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
## Namespaces

*(If you use an already implemented platform and annotated commands, you don't need
to use Namespaces, yay!)*

A namespace is a mapping/set of the arguments that are injected into the execution.
For example, we can inject the user executor of a command and use it later.

Creating a namespace:
<!--@formatter:off-->
```java
// Create a namespace
Namespace namespace = Namespace.create();
```
<!--@formatter:on-->

Now we can set any object in the namespace, by type and name, for example, suppose we
have a `User` class:
<!--@formatter:off-->
```java
namespace.setObject(User.class, "USER", new User("Fixed", 16));
```
<!--@formatter:on-->

And now, we can retrieve the object from the namespace, using the exact same
type and name, for example:
<!--@formatter:off-->
```java
User user = namespace.getObject(User.class, "USER");

System.out.println(user.getName()); // Fixed
```
<!--@formatter:on-->

74 changes: 74 additions & 0 deletions docs/configuration/authorizer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
## Authorizer

`command-flow` has a functional interface `Authorizer` with a single method responsible for
determining if a command should be executed.

### Platform Specific

There are some platform specific implementations of `Authorizer`, which are automatically
set if you use the specific `CommandManager` class, for example, if you instantiate the
`BukkitCommandManager`, it will already use the `BukkitAuthorizer` by default, awesome!

### Implementation

The `Authorizer` single method accepts a `Namespace` and the actual permission string,
and returns a boolean value indicating if the command should be executed or not.

Check the following implementation example, suppose we have a `User` class, and we have
previously set the sender user instance in the execution namespace *(Check page about
Command Dispatch)*

<!--@formatter:off-->
```java
public class MyAuthorizer implements Authorizer {
@Override
public boolean isAuthorized(Namespace namespace, String permission) {
User user = namespace.getObject(User.class, "USER");

// User not set!
if (user == null) {
return false;
}

return user.hasPermission(permission);
}
}
```
<!--@formatter:on-->

Now we can set our `Authorizer` in the `CommandManager`

<!--@formatter:off-->
```java
CommandManager commandManager = ...;

commandManager.setAuthorizer(new MyAuthorizer());
```
<!--@formatter:on-->

### Permission String

The permission string is an optional attribute for `Command` instances, set during
its instantiation, for example:

Using builders:
<!--@formatter:off-->
```java
Command command = Command.builder("test")
.permission("this.is.the.permission.string")
.action(context -> {
System.out.println("Hello World!");
})
.build();
```
<!--@formatter:on-->

Or annotations:
<!--@formatter:off-->
```java
@Command(names = "test", permission = "this.is.the.permission.string")
public class TestCommand implements CommandClass {
...
}
```
<!--@formatter:on-->
8 changes: 8 additions & 0 deletions docs/configuration/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
## Configuring the Command Manager

The `CommandManager` allows developers to fully configurate its behavior and
how to determine certain aspects of the command parsing & dispatching process.

The `CommandManager` can also be extended for platform-specific features and
native integration, like, automatically registering commands in a platform
command registry.
3 changes: 3 additions & 0 deletions docs/configuration/index.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
configuration.md
authorizer.md
tokenizer.md
35 changes: 35 additions & 0 deletions docs/configuration/tokenizer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
## Input Tokenizer

The input tokenizer is responsible for converting a simple input string into a
list of tokens. The tokens are then used by the parser to enter the desired
command path and either dispatch a command or get suggestions for the next
token.

The `InputTokenizer` is a functional interface that can be set to the
`CommandManager` via the `CommandManager#setInputTokenizer` method.

For example:

```java
// create a tokenizer
InputTokenizer tokenizer = ...;

// set the tokenizer
CommandManager manager = ...;
manager.setInputTokenizer(tokenizer);
```

### Default Implementations

`command-flow` provides two default implementations of the `InputTokenizer`
interface, `StringSpaceTokenizer` and `QuotedSpaceTokenizer`:

- `StringSpaceTokenizer` - This tokenizer splits the input string by spaces
and returns the resulting tokens. This is the default tokenizer used by
`CommandManager` if no other tokenizer is set.
- `QuotedSpaceTokenizer` - This tokenizer splits the input string by spaces
but also supports quoted strings. For example, the input string
`hello "world of commands"` would be split into the tokens `hello` and
`world of commands`.


Empty file added docs/dispatch/index.txt
Empty file.
30 changes: 30 additions & 0 deletions docs/imperatively/argument.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
## #2 With Arguments

Check this command example with a single argument:

<!--@formatter:off-->
```java
import static me.fixeddev.commandflow.part.Parts.*;

//...

// create an (argument) part of type string, with the name 'name'
CommandPart nameArg = string("name");

// create the command
Command helloCommand = Command.builder("hello")
.addPart(nameArg)
.action(context -> {
// get the value of the name argument and print 'Hi <name>'
context.<String>getValue(nameArg).ifPresent(name -> {
System.out.println("Hi " + name);
});
})
.build();
```
<!--@formatter:on-->

In this example:
- Executing `hello yusshu` will print `Hi yusshu`
- Executing `hello Fixed` will print `Hi Fixed`
- Executing `hello` will print nothing
16 changes: 16 additions & 0 deletions docs/imperatively/basic.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
## #1 Basic Command

Check this basic command example, with no arguments, no subcommands and no permissions,
using the imperative command creation approach:

<!--@formatter:off-->
```java
Command testCommand = Command.builder("test")
.action(context -> {
System.out.println("Hello World!");
})
.build();
```
<!--@formatter:on-->

Executing `test` will print `Hello World!`
5 changes: 5 additions & 0 deletions docs/imperatively/index.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
intro.md
basic.md
argument.md
multiple-arguments.md
optional-arguments.md
18 changes: 18 additions & 0 deletions docs/imperatively/intro.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
## Imperative Command Creation

We can imperatively create commands using the command builder interface. This
way to create commands is the most flexible one, but also the most verbose.

An alternative to this approach is to use the [annotation-based command creation](../annotated/annotated.md).

### Comparison

You can make a side-by-side comparison of the two approaches in the following table
and links:

| Imperative | Annotated |
|----------------------------------------------------------------------------|-------------------------------------------------------------------------|
| [Basic Command Creation](../imperatively/basic.md) | [Basic Command Creation](../annotated/basic.md) |
| [Command with single Argument](../imperatively/argument.md) | [Command with single Argument](../annotated/argument.md) |
| [Command with multiple Arguments](../imperatively/multiple-arguments.md) | [Command with multiple Arguments](../annotated/multiple-arguments.md) |
| [Command with optional Arguments](../imperatively/optional-arguments.md) | [Command with optional Arguments](../annotated/optional-arguments.md) |
Loading

0 comments on commit 6ef8aa3

Please sign in to comment.