Skip to content

Commit

Permalink
Basic command definition (#1)
Browse files Browse the repository at this point in the history
* feat: basic "schema" for a command and skeleton creation

* add erlang to path

* basic command runner and CLI parsing

* complete package informations and improve readme

* add examples documentation

* improve documentation

* improve flake

* define help builder

* remove old tests
  • Loading branch information
Zoey de Souza Pessanha committed Jul 24, 2023
1 parent 9ab00e8 commit d0f20d4
Show file tree
Hide file tree
Showing 14 changed files with 425 additions and 79 deletions.
5 changes: 3 additions & 2 deletions .formatter.exs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"],
export: [locals_without_parens: [defcommand: 2]],
locals_without_parens: [defcommand: 2]
]
30 changes: 26 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,40 @@
# Nexus

```sh
_ __
|\ ||_\/| |(_
| \||_/\|_|__)
_ __
|\ ||_\/| |(_
| \||_/\|_|__)
```

> Create CLIs in a magic and declarative way!
An `Elixir` library to write command line apps in a simple and elelgant way!
An `Elixir` library to write command line apps in a cleaner and elegant way!

[![lint](https://github.com/zoedsoupe/nexus/actions/workflows/lint.yml/badge.svg)](https://github.com/zoedsoupe/nexus/actions/workflows/lint.yml)
[![test](https://github.com/zoedsoupe/nexus/actions/workflows/test.yml/badge.svg)](https://github.com/zoedsoupe/nexus/actions/workflows/test.yml)

## Example

```elixir dark
defmodule MyCLI do
use Nexus

@doc """
Answer "fizz" on "buzz" input and "buzz" on "fizz" input.
"""
defcommand :fizzbuzz, type: {:enum, ["fizz", "buzz"]}, required?: true

@impl Nexus.CLI
# input can be named to anything
@spec handle_input(atom, args) :: :ok
when args: list(binary)
def handle_input(:fizzbuzz, input) do
# logic to answer "fizz" or "buzz"
:ok
end
end
```

## Why "Nexus"

Nexus is a connection from two different worlds! This library connects the world of CLIs with the magic world of `Elixir`!
12 changes: 5 additions & 7 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

76 changes: 37 additions & 39 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -1,56 +1,54 @@
{
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-22.11";

outputs = { self, nixpkgs }:
let
systems = {
linux = "x86_64-linux";
darwin = "aarch64-darwin";
};
outputs = {nixpkgs, ...}: let
systems = {
linux = "x86_64-linux";
darwin = "aarch64-darwin";
};

pkgs = system: import nixpkgs {
pkgs = system:
import nixpkgs {
inherit system;
config.allowUnfree = true;
};

inputs = sys: with pkgs sys; [
elixir_1_14
] ++ lib.optional stdenv.isLinux [
inotify-tools
gtk-engine-murrine
] ++ lib.optional stdenv.isDarwin [
darwin.apple_sdk.frameworks.CoreServices
darwin.apple_sdk.frameworks.CoreFoundation
];
inputs = sys:
with pkgs sys;
[elixir_1_14 erlang]
++ lib.optional stdenv.isLinux [
inotify-tools
gtk-engine-murrine
]
++ lib.optional stdenv.isDarwin [
darwin.apple_sdk.frameworks.CoreServices
darwin.apple_sdk.frameworks.CoreFoundation
];

name = "nexus";
in {
applications."${systems.linux}".pescarte =
let
inherit (pkgs systems.linux) beam callPackage;
beamPackages = beam.packagesWith beam.interpreters.erlang;
in beamPackages.mixRelease rec {
pname = name;
version = "0.1.0";
src = ./.;
postBuild = "mix do deps.loadpaths --no-deps-check";
mixFodDeps = beamPackages.fetchMixDeps {
inherit src version;
pname = "mix-deps-${pname}";
sha256 = "";
};
};
name = "nexus";
in {
applications."${systems.linux}".pescarte = let
inherit (pkgs systems.linux) beam;
beamPackages = beam.packagesWith beam.interpreters.erlang;
in
beamPackages.buildMix {
inherit name;
version = "0.1.0";
src = ./.;
postBuild = "mix do deps.loadpaths --no-deps-check";
beamDeps = [];
};

devShells = {
"${systems.linux}".default = with pkgs systems.linux; mkShell {
devShells = {
"${systems.linux}".default = with pkgs systems.linux;
mkShell {
inherit name;
buildInputs = inputs systems.linux;
};

"${systems.darwin}".default = with pkgs systems.darwin; mkShell {
"${systems.darwin}".default = with pkgs systems.darwin;
mkShell {
inherit name;
buildInputs = inputs systems.darwin;
};
};
};
};
}
31 changes: 31 additions & 0 deletions lib/escript/example.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
defmodule Escript.Example do
@moduledoc """
This is an example on how to use `Nexus` with an
escript application.
After defined `:escript` entry into your `project/0` function
on `mix.exs` and set the `main_module` option, you can safely
define your commands as usual with `defcommand/2`, CLI config
and handlers.
Then you need to call `parse/0` macro, which will inject both
`parse/1` and `run/1` function, which the latter you can delegate
from the `main/1` escript funciton, as can seen below.
"""

use Nexus

defcommand :foo, required?: true, type: :string

@impl true
def version, do: "0.1.0"

@impl true
def handle_input(:foo, _args) do
IO.puts("Running :foo command...")
end

Nexus.parse()

defdelegate main(args), to: __MODULE__, as: :run
end
36 changes: 36 additions & 0 deletions lib/mix/tasks/example.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
defmodule Mix.Tasks.Example do
@moduledoc """
This is a Mix Task example using Nexus.
Basically, you can `use` both `Mix.Task` and `Nexus`
modules, define your commands as usual with `defcommand/2`
and implement others callbacks.
Then you need to call `Nexus.parse/0`, that will inject
both `parse/1` and `run/1` functions into your module.
In a `Mix.Task` module, the `run/1` function will supply
the behaviour, so you don't need to define it yourself.
If you need to do other computations inside `Mix.Task.run/1`,
then simply define `run/1` by yourself and call `__MODULE__.run/1`
when you need it, passing the raw args to it.
"""

use Mix.Task
use Nexus

defcommand :foo, type: :string, required?: false

@impl Nexus.CLI
def version, do: "0.1.0"

@impl Nexus.CLI
def banner, do: "Hello I'm a test"

@impl Nexus.CLI
def handle_input(:foo, _args) do
IO.puts("Running :foo command...")
end

Nexus.help()
Nexus.parse()
end
Loading

0 comments on commit d0f20d4

Please sign in to comment.