Low commit activity in last 3 years
There's a lot of open issues
A long-lived project that still receives updates
Simplifies options parsing and configuration loading.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Development

~> 12.0
~> 3.7

Runtime

~> 0.6.1
 Project Readme

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.