• Stars
    star
    176
  • Rank 208,932 (Top 5 %)
  • Language
    Elixir
  • License
    MIT License
  • Created over 7 years ago
  • Updated 10 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Command line arguments parser for Elixir

Optimus

Optimus avatar: Transformer's head shaped as a letter “O”

Build Status Coverage Status Module Version Hex Docs Total Download License Last Updated

A command line arguments parsing library for Elixir.

It's aim is to take off the maximum possible amount of manual argument handling. The intended use case is to configure Optimus parser, run it against the command line and then do nothing but take completely validated ready to use values.

The library was strongly inspired by the awesome clap.rs library. Optimus does not generally follow its design, but it tries to follow the idea of zero manual manipulation with the values after the parser has returned them.

Installation

Add optimus to your list of dependencies in mix.exs:

def deps do
  [
    {:optimus, "~> 0.2"}
  ]
end

Example

Let's configure a CLI interface to an imaginary utility which reads data from a file of the following format:

# timestamp, value
1481729245, 12.0
1481729245, 13.0
1481729246, 11.1
...

and outputs some statistic metrics of the values. It also has a subcommand which validates the source file integrity.

defmodule Statcalc do
  def main(argv) do
    Optimus.new!(
      name: "statcalc",
      description: "Statistic metrics calculator",
      version: "1.2.3",
      author: "John Smith [email protected]",
      about: "Utility for calculating statistic metrics of values read from a file for a certain period of time",
      allow_unknown_args: false,
      parse_double_dash: true,
      args: [
        infile: [
          value_name: "INPUT_FILE",
          help: "File with raw data",
          required: true,
          parser: :string
        ],
        outfile: [
          value_name: "OUTPUT_FILE",
          help: "File to write statistics to",
          required: false,
          parser: :string
        ]
      ],
      flags: [
        print_header: [
          short: "-h",
          long: "--print-header",
          help: "Specifies whether to print header before the outputs",
          multiple: false,
        ],
        verbosity: [
          short: "-v",
          help: "Verbosity level",
          multiple: true,
        ],
      ],
      options: [
        date_from: [
          value_name: "DATE_FROM",
          short: "-f",
          long: "--from",
          help: "Start date for the period",
          parser: fn(s) ->
            case Date.from_iso8601(s) do
              {:error, _} -> {:error, "invalid date"}
              {:ok, _} = ok -> ok
            end
          end,
          required: true
        ],
        date_to: [
          value_name: "DATE_TO",
          short: "-t",
          long: "--to",
          help: "End date for the period",
          parser: fn(s) ->
            case Date.from_iso8601(s) do
              {:error, _} -> {:error, "invalid date"}
              {:ok, _} = ok -> ok
            end
          end,
          required: false,
          default: &Date.utc_today/0
        ],
      ],
      subcommands: [
        validate: [
          name: "validate",
          about: "Validates the raw contents of a file",
          args: [
            file: [
              value_name: "FILE",
              help: "File with raw data to validate",
              required: true,
              parser: :string
            ]
          ]
        ]
      ]
    ) |> Optimus.parse!(argv) |> IO.inspect
  end
end

(The whole sample code can be found in optimus_example repo.)

Nearly all of the configuration options above are not mandatory.

Also most configuration parameters are self-explanatory, except parser. For options and positional arguments parser is a lambda which accepts a string argument and returns either {:ok, parsed_value} or {:error, string_reason}. There are also some predefined parsers which are denoted by atoms: :string, :integer and :float. No parser means that :string parser will be used.

Not required options can have a default value. Both a term (string, number, etc.) or a lambda with zero arity can be used. If the option accepts multiple values, the default value should be a list, for example [1.0] or fn -> ["x", "y"] end.

Now if we try to launch our compiled escript without any args we'll see the following:

>./statcalc
The following errors occurred:
- missing required arguments: INPUT_FILE
- missing required options: --from(-f), --to(-t)

Try
    statcalc --help

to see available options

There are several things to note:

  • the script exited (in Optimus.parse!) since we haven't received a valid set of arguments;
  • a list of errors is displayed (and it's as full as possible);
  • a user is offered to launch statcalc with --help flag which is automatically handled by Optimus.

If we launch statcalc --help, we'll see the following:

>./statcalc --help
Statistic metrics calculator 1.2.3
John Smith [email protected]
Utility for calculating statistic metrics of values read from a file for a certain period of time

USAGE:
    statcalc [--print-header] --from DATE_FROM --to DATE_TO INPUT_FILE [OUTPUT_FILE]
    statcalc --version
    statcalc --help
    statcalc help subcommand

ARGS:

    INPUT_FILE         File with raw data
    OUTPUT_FILE        File to write statistics to

FLAGS:

    -h, --print-header        Specifies whether to print header before the
                              outputs

OPTIONS:

    -f, --from        Start date for the period
    -t, --to          End date for the period  (default: 2017-12-20)

SUBCOMMANDS:

    validate        Validates the raw contents of a file

The things to note are:

  • Optimus formed a formatted help information and also exited;
  • it also offers some other autogenerated commands (--version and help subcommand).

Now if we finally produce a valid list of args, we'll have our arguments parsed:

>./statcalc --print-header -f 2016-01-01 -t 2016-02-01 infile.raw outfile.dat
%Optimus.ParseResult{
  args: %{
    infile: "infile.raw",
    outfile: "outfile.dat"
  },
  flags: %{
    print_header: true
  },
  options: %{
    date_from: ~D[2016-01-01],
    date_to: ~D[2016-02-01]
  },
  unknown: []
}

Optimus.ParseResult is a struct with four fields: args, flags, options, which are maps, and unknown, which is a list. Things to note are:

  • unknown list is always empty if we set allow_unknown_args: false for our (sub)command;
  • values in args, flags and options maps are kept under keys specified in configuration;
  • for options with multiple: true the value is a list;
  • for flags without multiple: true the value is a boolean;
  • for flags with multiple: true the value is an integer (representing the number of occurrences of a flag).

Credits

Brutal picture for the project was made by Igor Garybaldi.

Copyright and License

Copyright (c) 2016 Ilya Averyanov

This work is free. You can redistribute it and/or modify it under the terms of the MIT License. See the LICENSE.md file for more details.

Sponsored by FunBox

More Repositories

1

optimizt

CLI image optimization tool
JavaScript
915
star
2

harold

Compares frontend project bundles
JavaScript
241
star
3

smppex

✉️ SMPP 3.4 protocol and framework implementation in Elixir
Elixir
103
star
4

fitting

Library add improve test log for RSpec and WebMock, validate its according to API Blueprint and Open API, show the documentation coverage with log.
Ruby
46
star
5

beatrix

A tool to chop off useless fonts glyphs and convert TTF/OTF into WOFF & WOFF2
JavaScript
40
star
6

blueprinter

API Blueprint renderer to output documentation as an HTML page
JavaScript
34
star
7

talks

Архив с публичными выступлениями наших сотрудников
29
star
8

init-exporter

Utility for exporting services described by Procfile to init system
Go
27
star
9

phantom-lord

Handy API for Headless Chromium
JavaScript
26
star
10

chokecherry

Wrapper around lager logger which limits the volume of info messages irrespectively of the lager's backend
Erlang
26
star
11

diamonds

A pile of shiny typed JS helpers for everyday usage
TypeScript
21
star
12

smppsend

Command line tool for sending messages to SMSC through SMPP
Elixir
19
star
13

sidekiq-influxdb

Writes Sidekiq job execution metrics to InfluxDB
Ruby
18
star
14

webpack-dev-server-firewall

Prevents access to dev server from unknown IPs
JavaScript
17
star
15

chronos

One library to rule the time
TypeScript
17
star
16

shrine-webdav

Provides a simple WebDAV storage for Shrine
Ruby
17
star
17

plumbapius

Plugs and tools for validating HTTP requests and responses according to API Blueprint specs
Elixir
14
star
18

languagetool-node

CLI spell and grammar checker
JavaScript
13
star
19

crafter

API Blueprint parser written in pure JavaScript
JavaScript
12
star
20

esplanade

Validate requests and responses against API Blueprint specifications
Ruby
12
star
21

babel-plugin-typograf

Babel plugin for enhancing text punctuation and readability
JavaScript
11
star
22

tomograph

Convert API Blueprint, Swagger and OpenAPI to JSON Schema and search through it
Ruby
11
star
23

eslint-plugin-no-only-tests

Disallow the use of describe.only() and it.only()
JavaScript
10
star
24

markdown-lint

Markdown code style linter
JavaScript
10
star
25

scss-vars-loader

SCSS variables for BEM-blocks
JavaScript
9
star
26

scss-imports-loader

Global imports for SCSS files
JavaScript
8
star
27

eslint-config

ESLint rules that follow our style guide
JavaScript
8
star
28

vscode-apib-ls

API Blueprint language server
JavaScript
8
star
29

api-validator

A tool to validate server responses using API Blueprint documentation
JavaScript
7
star
30

face_control

Comment on problems in added lines of pull requests in Atlassian Bitbucket Server (formerly Stash)
Ruby
7
star
31

frontend-tests-runner

A library for running Mocha tests in parallel
JavaScript
6
star
32

loggun

Приводит логи приложения к единому формату
Ruby
6
star
33

free-port-finder

Tiny utility for checking ports availability
JavaScript
6
star
34

stylelint-rules

A collection of SCSS rules missing in stylelint-scss
JavaScript
6
star
35

scss-lint-config

Config for Stylelint SCSS linting
JavaScript
6
star
36

bacula_exporter

Bacula exporter for Prometheus
Go
5
star
37

pipeline-heavy-job-plugin

This plugin allows defining job weight for pipeline projects as HeavyJob Plugin does for freestyle projects.
Java
5
star
38

rebuild-in-progress-webpack-plugin

Creates the file indicator at the beginning of the build and deletes it at the end
JavaScript
5
star
39

statesman-diagram

Generates DOT representations of Statesman machines and runs dot to render them to PNGs
Ruby
5
star
40

fazio

A tool to find an npm dep somewhere on your filesystem
JavaScript
5
star
41

piper

Utility for log rotation for 12-factor apps
Go
5
star
42

api-blueprint-tutorial

General information about API Blueprint tools in FunBox
JavaScript
5
star
43

eleb128

LEB128 Erlang implementation
Erlang
4
star
44

simplecov-bitbucket-server

Uploads test coverage data to Bitbucket Server via Code Coverage plugin
Ruby
4
star
45

activerecord-overflow_signalizer

Signalize when some primary key overflow soon
Ruby
4
star
46

dkrpm

Dockerized RPM building process powered by RPMBuilder
Shell
2
star
47

airborne_report

Generate reports on tests with the airborne gem
Ruby
2
star
48

qa-test

Тестовое задание для QA
Ruby
2
star
49

dioxy

Aggregating proxy for MQTT broker metrics in JSON format
Go
1
star
50

api-blueprint

API Blueprint specification
1
star
51

capistrano-init-exporter

Capistrano bindings for the init-exporter utility
Ruby
1
star
52

scss-utils

A small set of SCSS mixins
SCSS
1
star