Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor func names #44

Merged
merged 5 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased] - yyyy-mm-dd

## [0.2.0] - 2024-10-09

- Refactor flag get/parsing to use ref to simplify code and enable removal of transform module.
- Renamed some fields to make them more accurate in the Command struct.

## [0.1.7] - 2024-10-09

- Fix command parsing bug.
Expand Down
46 changes: 22 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Commands can have typed flags added to them to enable different behaviors.
var root = Command(
name="logger", description="Base command.", run=handler
)
root.flags.add_string_flag(name="type", shorthand="t", usage="Formatting type: [json, custom]")
root.flags.string_flag(name="type", shorthand="t", usage="Formatting type: [json, custom]")
```

![Logging](https://github.com/thatstoasty/prism/blob/main/doc/tapes/logging.gif)
Expand Down Expand Up @@ -120,7 +120,7 @@ fn main() -> None:
persistent_pre_run=pre_hook,
persistent_post_run=post_hook,
))
get_command[].flags.persistent_flags.add_bool_flag(name="lover", shorthand="l", usage="Are you an animal lover?")
get_command[].flags.persistent_flags.bool_flag(name="lover", shorthand="l", usage="Are you an animal lover?")
```

![Persistent](https://github.com/thatstoasty/prism/blob/main/doc/tapes/persistent.gif)
Expand All @@ -135,7 +135,7 @@ By default flags are considered optional. If you want your command to report an
var print_tool = Arc(Command(
name="tool", description="This is a dummy command!", run=tool_func, aliases=List[String]("object", "thing")
))
print_tool[].flags.add_bool_flag(name="required", shorthand="r", usage="Always required.")
print_tool[].flags.bool_flag(name="required", shorthand="r", usage="Always required.")
print_tool[].mark_flag_required("required")
```

Expand All @@ -147,7 +147,7 @@ Same for persistent flags:
description="This is a dummy command!",
run=test,
)
root.persistent_flags.add_bool_flag(name="free", shorthand="f", usage="Always required.")
root.persistent_flags.bool_flag(name="free", shorthand="f", usage="Always required.")
root.mark_persistent_flag_required("free")
```

Expand All @@ -159,8 +159,8 @@ If you have different flags that must be provided together (e.g. if they provide
var print_tool = Arc(Command(
name="tool", description="This is a dummy command!", run=tool_func, aliases=List[String]("object", "thing")
))
print_tool[].flags.add_string_flag(name="color", shorthand="c", usage="Text color", default="#3464eb")
print_tool[].flags.add_string_flag(name="formatting", shorthand="f", usage="Text formatting")
print_tool[].flags.uint32_flag(name="color", shorthand="c", usage="Text color", default=0x3464eb)
print_tool[].flags.string_flag(name="formatting", shorthand="f", usage="Text formatting")
print_tool[].mark_flags_required_together("color", "formatting")
```

Expand All @@ -170,8 +170,8 @@ You can also prevent different flags from being provided together if they repres
var print_tool = Arc(Command(
name="tool", description="This is a dummy command!", run=tool_func, aliases=List[String]("object", "thing")
))
print_tool[].add_string_flag(name="color", shorthand="c", usage="Text color", default="#3464eb")
print_tool[].add_string_flag(name="hue", shorthand="x", usage="Text color", default="#3464eb")
print_tool[].string_flag(name="color", shorthand="c", usage="Text color", default="#3464eb")
print_tool[].string_flag(name="hue", shorthand="x", usage="Text color", default="#3464eb")
print_tool[].mark_flags_mutually_exclusive("color", "hue")
```

Expand All @@ -181,8 +181,8 @@ If you want to require at least one flag from a group to be present, you can use
var print_tool = Arc(Command(
name="tool", description="This is a dummy command!", run=tool_func, aliases=List[String]("object", "thing")
))
print_tool[].flags.add_string_flag(name="color", shorthand="c", usage="Text color", default="#3464eb")
print_tool[].flags.add_string_flag(name="formatting", shorthand="f", usage="Text formatting")
print_tool[].flags.string_flag(name="color", shorthand="c", usage="Text color", default="#3464eb")
print_tool[].flags.string_flag(name="formatting", shorthand="f", usage="Text formatting")
print_tool[].mark_flags_one_required("color", "formatting")
print_tool[].mark_flags_mutually_exclusive("color", "formatting")
```
Expand All @@ -208,16 +208,16 @@ fn main() -> None:
run=test,
)
# Persistent flags are defined on the parent command.
root.persistent_flags.add_bool_flag(name="required", shorthand="r", usage="Always required.")
root.persistent_flags.add_string_flag(name="host", shorthand="h", usage="Host")
root.persistent_flags.add_string_flag(name="port", shorthand="p", usage="Port")
root.persistent_flags.bool_flag(name="required", shorthand="r", usage="Always required.")
root.persistent_flags.string_flag(name="host", shorthand="h", usage="Host")
root.persistent_flags.string_flag(name="port", shorthand="p", usage="Port")
root.mark_persistent_flag_required("required")

var print_tool = Arc(Command(
name="tool", description="This is a dummy command!", run=tool_func
))
print_tool[].flags.add_bool_flag(name="also", shorthand="a", usage="Also always required.")
print_tool[].flags.add_string_flag(name="uri", shorthand="u", usage="URI")
print_tool[].flags.bool_flag(name="also", shorthand="a", usage="Also always required.")
print_tool[].flags.string_flag(name="uri", shorthand="u", usage="URI")

# Child commands are added to the parent command.
root.add_subcommand(print_tool)
Expand Down Expand Up @@ -246,13 +246,13 @@ Validation of positional arguments can be specified using the `arg_validator` fi
- `exact_args[Int]` - report an error if there are not exactly N positional args.
- `range_args[min, max]` - report an error if the number of args is not between min and max.
- Content of the arguments:
- `only_valid_args` - report an error if there are any positional args not specified in the `valid_args` field of `Command`, which can optionally be set to a list of valid values for positional args.
- `valid_args` - report an error if there are any positional args not specified in the `valid_args` field of `Command`, which can optionally be set to a list of valid values for positional args.

If `arg_validator` is undefined, it defaults to `arbitrary_args`.

> NOTE: `match_all` is unstable at the moment. I will work on ironing it out in the near future. This most likely does not work.

Moreover, `match_all[arg_validators: List[ArgValidator]]` enables combining existing checks with arbitrary other checks. For instance, if you want to report an error if there are not exactly N positional args OR if there are any positional args that are not in the ValidArgs field of Command, you can call `match_all` on `exact_args` and `only_valid_args`, as shown below:
Moreover, `match_all[arg_validators: List[ArgValidator]]` enables combining existing checks with arbitrary other checks. For instance, if you want to report an error if there are not exactly N positional args OR if there are any positional args that are not in the ValidArgs field of Command, you can call `match_all` on `exact_args` and `valid_args`, as shown below:

```mojo
fn test_match_all():
Expand All @@ -273,16 +273,15 @@ Commands are configured to accept a `--help` flag by default. This will print th

```mojo
fn help_func(inout command: Arc[Command]) -> String:
return ""
return "My help function."

fn main() -> None:
var root = Command(
name="hello",
description="This is a dummy command!",
run=test,
help=help_func
)

var hello_command = Arc(Command(name="chromeria", description="This is a dummy command!", run=hello, help=help_func))
```

![Help](https://github.com/thatstoasty/prism/blob/main/doc/tapes/help.gif)
Expand All @@ -293,19 +292,18 @@ fn main() -> None:

## TODO

### Documentation

### Features

- Add find suggestion logic to `Command` struct.
- Add suggestion logic to `Command` struct.
- Autocomplete generation.
- Enable usage function to return the results of a usage function upon calling wrong functions or commands.
- Replace print usage with writers to enable stdout/stderr/file writing.
- Update default help command to improve available commands and flags section.

### Improvements

- Tree traversal improvements.
- Arc[Command] being passed to validators and command functions is marked as inout because the compiler complains about forming a reference to a borrowed register value. This is a temporary fix, I will try to get it back to a borrowed reference.
- `Arc[Command]` being passed to validators and command functions is marked as inout because the compiler complains about forming a reference to a borrowed register value. This is a temporary fix, I will try to get it back to a borrowed reference.
- For now, help functions and arg validators will need to be set after the command is constructed. This is to help reduce cyclical dependencies, but I will work on a way to set these values in the constructor as the type system matures.

### Bugs
4 changes: 2 additions & 2 deletions examples/aliases.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ fn tool_func(ctx: Context) -> None:
fn main() -> None:
var root = Command(
name="my",
description="This is a dummy command!",
usage="This is a dummy command!",
run=test,
)

var print_tool = Arc(
Command(
name="tool", description="This is a dummy command!", run=tool_func, aliases=List[String]("object", "thing")
name="tool", usage="This is a dummy command!", run=tool_func, aliases=List[String]("object", "thing")
)
)

Expand Down
15 changes: 8 additions & 7 deletions examples/arg_validators.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -23,32 +23,33 @@ fn hello(ctx: Context) -> None:
fn main() -> None:
var root = Command(
name="hello",
description="This is a dummy command!",
usage="This is a dummy command!",
run=test,
)

var no_args_command = Arc(Command(name="no_args", description="This is a dummy command!", run=hello))
var no_args_command = Arc(Command(name="no_args", usage="This is a dummy command!", run=hello))
no_args_command[].arg_validator = no_args

var valid_args_command = Arc(
Command(
name="valid_args",
description="This is a dummy command!",
usage="This is a dummy command!",
run=hello,
valid_args=List[String]("Pineapple")
)
)
valid_args_command[].arg_validator = valid_args

var minimum_n_args_command = Arc(Command(name="minimum_n_args", description="This is a dummy command!", run=hello))
var minimum_n_args_command = Arc(Command(name="minimum_n_args", usage="This is a dummy command!", run=hello))
minimum_n_args_command[].arg_validator = minimum_n_args[4]()

var maximum_n_args_command = Arc(Command(name="maximum_n_args", description="This is a dummy command!", run=hello))
var maximum_n_args_command = Arc(Command(name="maximum_n_args", usage="This is a dummy command!", run=hello))
maximum_n_args_command[].arg_validator = maximum_n_args[1]()

var exact_args_command = Arc(Command(name="exact_args", description="This is a dummy command!", run=hello))
var exact_args_command = Arc(Command(name="exact_args", usage="This is a dummy command!", run=hello))
exact_args_command[].arg_validator = exact_args[1]()

var range_args_command = Arc(Command(name="range_args", description="This is a dummy command!", run=hello))
var range_args_command = Arc(Command(name="range_args", usage="This is a dummy command!", run=hello))
range_args_command[].arg_validator = range_args[0, 1]()

root.add_subcommand(no_args_command)
Expand Down
4 changes: 2 additions & 2 deletions examples/chromeria.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ fn hello(ctx: Context) -> None:
fn main() -> None:
var root = Command(
name="hello",
description="This is a dummy command!",
usage="This is a dummy command!",
run=test,
)

var hello_command = Arc(Command(name="chromeria", description="This is a dummy command!", run=hello))
var hello_command = Arc(Command(name="chromeria", usage="This is a dummy command!", run=hello))

root.add_subcommand(hello_command)
root.execute()
14 changes: 7 additions & 7 deletions examples/fg_child.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@ fn tool_func(ctx: Context) -> None:
fn main() -> None:
var root = Command(
name="my",
description="This is a dummy command!",
usage="This is a dummy command!",
run=test,
)
root.persistent_flags.add_bool_flag(name="required", shorthand="r", usage="Always required.")
root.persistent_flags.add_string_flag(name="host", shorthand="h", usage="Host")
root.persistent_flags.add_string_flag(name="port", shorthand="p", usage="Port")
root.persistent_flags.bool_flag(name="required", shorthand="r", usage="Always required.")
root.persistent_flags.string_flag(name="host", shorthand="h", usage="Host")
root.persistent_flags.string_flag(name="port", shorthand="p", usage="Port")
root.mark_persistent_flag_required("required")

var print_tool = Arc(Command(name="tool", description="This is a dummy command!", run=tool_func))
print_tool[].flags.add_bool_flag(name="also", shorthand="a", usage="Also always required.")
print_tool[].flags.add_string_flag(name="uri", shorthand="u", usage="URI")
var print_tool = Arc(Command(name="tool", usage="This is a dummy command!", run=tool_func))
print_tool[].flags.bool_flag(name="also", shorthand="a", usage="Also always required.")
print_tool[].flags.string_flag(name="uri", shorthand="u", usage="URI")
root.add_subcommand(print_tool)

# Make sure to add the child command to the parent before marking flags.
Expand Down
23 changes: 15 additions & 8 deletions examples/fg_parent.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@ from memory import Arc
from prism import Command, Context


fn test(ctx: Context) -> None:
print("Pass tool, object, or thing as a subcommand!")
fn test(ctx: Context) raises -> None:
var host = ctx.command[].flags.get_string("host")
var port = ctx.command[].flags.get_string("port")
var uri = ctx.command[].flags.get_string("uri")

if uri != "":
print("URI:", uri)
else:
print(host + ":" + port)


fn tool_func(ctx: Context) -> None:
Expand All @@ -13,13 +20,13 @@ fn tool_func(ctx: Context) -> None:
fn main() -> None:
var root = Command(
name="my",
description="This is a dummy command!",
run=test,
usage="This is a dummy command!",
raising_run=test,
)
root.persistent_flags.add_bool_flag(name="required", shorthand="r", usage="Always required.")
root.persistent_flags.add_string_flag(name="host", shorthand="h", usage="Host")
root.persistent_flags.add_string_flag(name="port", shorthand="p", usage="Port")
root.persistent_flags.add_string_flag(name="uri", shorthand="u", usage="URI")
root.persistent_flags.bool_flag(name="required", shorthand="r", usage="Always required.")
root.persistent_flags.string_flag(name="host", shorthand="h", usage="Host")
root.persistent_flags.string_flag(name="port", shorthand="p", usage="Port")
root.persistent_flags.string_flag(name="uri", shorthand="u", usage="URI")
root.mark_flags_required_together("host", "port")
root.mark_flags_mutually_exclusive("host", "uri")
root.mark_flag_required("required")
Expand Down
17 changes: 10 additions & 7 deletions examples/hello_world.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fn build_printer_command() -> Arc[Command]:
var cmd = Arc(
Command(
name="printer",
description="Print the first arg.",
usage="Print the first arg.",
run=printer,
)
)
Expand All @@ -42,7 +42,7 @@ fn build_say_command() -> Arc[Command]:
return Arc(
Command(
name="say",
description="Say something to someone",
usage="Say something to someone",
run=say,
)
)
Expand All @@ -52,7 +52,7 @@ fn build_hello_command() -> Arc[Command]:
var cmd = Arc(
Command(
name="hello",
description="Say hello to someone",
usage="Say hello to someone",
run=say_hello,
)
)
Expand All @@ -63,15 +63,18 @@ fn build_goodbye_command() -> Arc[Command]:
var cmd = Arc(
Command(
name="goodbye",
description="Say goodbye to someone",
usage="Say goodbye to someone",
run=say_goodbye,
)
)
return cmd


fn test(ctx: Context) -> None:
print(ctx.command[].flags.get_as_string("env").value())
try:
print(ctx.command[].flags.get_string("env"))
except:
print("No env flag provided.")
for item in ctx.command[].flags.flags:
if item[].value:
print(item[].name, item[].value.value())
Expand All @@ -84,10 +87,10 @@ fn test(ctx: Context) -> None:
fn main() -> None:
var root = Command(
name="tones",
description="This is a dummy command!",
usage="This is a dummy command!",
run=test,
)
root.flags.add_string_flag(name="env", shorthand="e", usage="Environment.")
root.flags.string_flag(name="env", shorthand="e", usage="Environment.", default="")

var say_command = build_say_command()
var hello_command = build_hello_command()
Expand Down
2 changes: 1 addition & 1 deletion examples/printer/mojoproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ version = "0.1.0"
[dependencies]
max = ">=24.5.0,<25"
mist = ">=0.1.8,<0.2"
prism = ">=0.1.6,<0.2"
prism = ">=0.2.0,<0.2"
Loading