simple_scripting

Simplifies options parsing and configuration loading.


Keywords
linux, shell-scripts, sysadmin
License
GPL-3.0
Install
gem install simple_scripting -v 0.12.1

Documentation

Gem Version Build Status Code Climate Coverage Status

SimpleScripting

SimpleScripting is a library composed of three modules (TabCompletion, Argv and Configuration) that simplify three common scripting tasks:

  • writing autocompletion scripts
  • implementing the commandline options parsing (and the related help)
  • loading and decoding the configuration for the script/application

SimpleScripting is an interesting (and useful) exercise in design, aimed at finding the simplest and most expressive data/structures that accomplish the given task(s). For this reason, the library can be useful for people who frequently write small scripts (eg. devops or nerds).

SimpleScripting::TabCompletion

TabCompletion makes trivial to define tab-completion for terminal commands on Linux/Mac systems; it's so easy that an example is much simpler than an explanation.

TabCompletion supports Bash, and Zsh (with bashcompinit).

Example

Suppose we have the command:

open_project [-e|--with-editor EDITOR] <project_name>

We want to add tab completion both for the option and the project name. Easy!!

Install the gem (simple_scripting), then create this class (/my/completion_scripts/open_project_completion.rb):

#!/usr/bin/env ruby

require 'simple_scripting/tab_completion'

class OpenProjectTabCompletion
  SYSTEM_EDITORS = `update-alternatives --list editor`.split("\n").map { |filename| File.basename(filename) }

  def with_editor(prefix, suffix, context)
    SYSTEM_EDITORS.grep /^#{prefix}/
  end

  def project_name(prefix, suffix, context)
    Dir["/my/home/my_projects/#{prefix}*"]
  end
end

if __FILE__ == $PROGRAM_NAME
  completion_definition = [
    ["-e", "--with-editor EDITOR"],
    'project_name'
  ]

  SimpleScripting::TabCompletion.new(completion_definition).complete(OpenProjectTabCompletion.new)
end

then chmod and register it:

$ chmod +x /my/completion_scripts/open_project_completion.rb
$ complete -C /my/completion_scripts/open_project_completion.rb -o default open_project

Done!

Now type the following, and get:

$ open_project g<tab>           # lists: "geet", "gitlab-ce", "gnome-terminal"
$ open_project --with-editor v  # lists: "vim.basic", "vim.tiny"
$ open_project --wi<tab>        # autocompletes "--with-editor"; this is built-in!

Happy completion!

Zsh

TabCompletion on Zsh requires bashcompinit; add the following to your ~/.zshrc:

autoload bashcompinit
bashcompinit

Note that a recent version of Zsh is required; the stock Ubuntu 16.04 version (5.1.1-1ubuntu2.2) has bug that breaks bash tab completion.

More complex use cases

For a description of the more complex use cases, including edge cases and error handling, see the wiki.

SimpleScripting::Argv

Argv is a module which acts as frontend to the standard Option Parser library (optparse), giving a very convenient format for specifying the arguments. Argv also generates the help.

This is a definition example:

require 'simple_scripting/argv'

result = SimpleScripting::Argv.decode(
  ['-s', '--only-scheduled-days',     'Only print scheduled days'                           ],
  ['-d', '--print-defaults TEMPLATE', 'Print the default activities from the named template'],
  'schedule',
  '[weeks]',
  long_help: 'This is the long help! It can span multiple lines.'
) || exit

which:

  • optionally accepts the -s/--only-scheduled-days switch, interpreting it as boolean,
  • optionally accepts the -d/--print-defaults switch, interpreting it as string,
  • requires the schedule argument,
  • optionally accepts the weeks argument,
  • automatically adds the -h and --help switches,
  • prints all the options and the long help if the help is invoked,
  • exits with a descriptive error if invalid parameters are passed.

This is a sample result:

{
  only_scheduled_days: true,
  print_defaults:      'my_defaults',
  schedule:            'schedule.txt',
  weeks:               '3',
}

This is the corresponding help:

Usage: tmpfile [options] <schedule> [<weeks>]
    -s, --only-scheduled-days        Only print scheduled days
    -d, --print-defaults TEMPLATE    Print the default activities from the named template
    -h, --help                       Help

This is the long help! It can span multiple lines.

Commands are also supported (with unlimited depth), by using a hash:

commands, result = SimpleScripting::Argv.decode(
  'pr' => {
    'create' => [
      'title',
      'description',
      long_help: 'This is the create PR command help.'
    ]
  },
  'issues' => {
    'list' => []
  }
) || exit

For the guide, see the wiki page.

SimpleScripting::Configuration

Configuration is a module which acts as frontend to the ParseConfig gem (parseconfig), giving compact access to the configuration and its values, and adding a few helpers for common tasks.

Say one writes a script (foo_my_bar.rb), with a corresponding ($HOME/.foo_my_bar) configuration, which contains:

some_relative_file_path=foo
some_absolute_file_path=/path/to/bar
multiple_paths=foo:/path/to/bar
my_password=uTxllKRD2S+IH92oi30luwu0JIqp7kKA

[a_group]
group_key=baz

This is the workflow and functionality offered by Configuration:

require 'simple_scripting/configuration'

# Picks up automatically the configuration file name, based on the calling program
#
configuration = SimpleScripting::Configuration.load(passwords_key: 'encryption_key')

configuration.some_relative_file_path.full_path # '$HOME/foo'
configuration.some_absolute_file_path           # '/path/to/bar'
configuration.some_absolute_file_path.full_path # '/path/to/bar' (recognized as absolute)
configuration.multiple_paths.full_paths         # ['$HOME/foo', '/path/to/bar']

configuration.my_password.decrypted             # 'encrypted_value'

configuration.a_group.group_key                 # 'baz'; also supports #full_path and #decrypted

Encryption note

The purpose of encryption in this library is just to avoid displaying passwords in plaintext; it's not considered safe against attacks.

Help

See the wiki for additional help.