pax_global_header00006660000000000000000000000064126451440520014515gustar00rootroot0000000000000052 comment=139a3a70ecc814c16bf5894140250a3107c5c772 lua_cliargs-3.0-1/000077500000000000000000000000001264514405200140025ustar00rootroot00000000000000lua_cliargs-3.0-1/.busted000066400000000000000000000002661264514405200152750ustar00rootroot00000000000000return { _all = { coverage = false }, default = { coverage = false, verbose = true, ROOT = {"spec"}, lpath = "src/?.lua;src/cliargs/?.lua;spec/?.lua;" } }lua_cliargs-3.0-1/.env000066400000000000000000000001161264514405200145710ustar00rootroot00000000000000GITHUB_USER="amireh" GITHUB_REPO="lua_cliargs" GITHUB_TOKEN= LUAROCKS_API_KEY=lua_cliargs-3.0-1/.gitignore000066400000000000000000000001551264514405200157730ustar00rootroot00000000000000/luacov.report.out /luacov.stats.out /.env.local /*.rock .swp /.luacheckcache /doc/compiled /doc/node_moduleslua_cliargs-3.0-1/.luacheckrc000066400000000000000000000001011264514405200160770ustar00rootroot00000000000000std = "min" cache = false files["spec"] = { std = "+busted" } lua_cliargs-3.0-1/.travis.yml000066400000000000000000000005341264514405200161150ustar00rootroot00000000000000language: erlang otp_release: - R15B02 env: - LUA="" - LUA="luajit" branches: only: - master install: - sudo apt-get install luajit - sudo apt-get install luarocks - sudo luarocks install busted 2.0rc10-1 - sudo luarocks install dkjson - sudo luarocks install yaml - sudo luarocks install inifile script: "busted spec" lua_cliargs-3.0-1/LICENSE000066400000000000000000000020451264514405200150100ustar00rootroot00000000000000Copyright (c) 2012-2015 Ahmad Amireh Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. lua_cliargs-3.0-1/README.md000066400000000000000000000221361264514405200152650ustar00rootroot00000000000000# lua_cliargs [![travis-ci status](https://secure.travis-ci.org/amireh/lua_cliargs.png)](http://travis-ci.org/#!/amireh/lua_cliargs/builds) cliargs is a command-line argument parser for Lua. It supports several types of arguments: 1. required arguments 2. optional arguments with different notations: `-short-key VALUE` and/or `--expanded-key=VALUE` 3. optional arguments with multiple-values that get appended to a list 4. optional "flag" arguments (on/off options) with notations: `-short-key` and/or `--expanded-key` 5. a single optional "splat" argument which can be repeated (must be the last argument) Optional arguments can have default values (strings), flags always default to 'true'. ## Usage Examples See the examples under the `examples/` directory. ## API See http://lua-cliargs.netlify.com/ for the API docs. ## Help listings `--help` A help listing will be automatically generated and accessed using the `--help` argument. When such an option is encountered, `cli:parse()` will abort and return `nil, string` with the help message; you are free to print it to the screen using `print()` if you want. You can also force its display in the code using `cli:print_help()`. This is the result for our example (see `examples/00_general.lua`): ``` Usage: cli_example.lua [OPTIONS] INPUT [OUTPUT-1 [OUTPUT-2 [...]]] ARGUMENTS: INPUT path to the input file (required) OUTPUT multiple output paths (optional, default: /dev/stdout) OPTIONS: -c, --compress=FILTER the filter to use for compressing output: gzip, lzma, bzip2, or none (default: gzip) -o FILE path to output file (default: /dev/stdout) -d script will run in DEBUG mode -v, --version prints the program's version and exits --verbose the script output will be very verbose ``` ## Validations ### Runtime argument validation From a parsing point of view, there are 3 cases that need to be handled which are outlined below. If I missed something, please open a ticket! **Missing a required argument** ``` $ lua examples/00_general.lua cli_example.lua: error: bad number of arguments; 1-4 argument(s) must be specified, not 0; re-run with --help for usage. ``` **Missing value for an optional argument** ``` $ lua examples/00_general.lua --compress inputfile cli_example.lua: error: option --compress requires a value to be set; re-run with --help for usage. ``` **Unknown arguments** ``` $ lua examples/00_general.lua -f inputfile cli_example.lua: error: unknown/bad flag; -f; re-run with --help for usage. ``` ### Some sanity guards In the following cases, `cliargs` will report an error to you and terminate the running script: 1. flag options can not accept a value. For example: `cli:add_flag('-v VERSION')` will return an error 2. duplicate keys are not allowed: defining two options with the key `--input` will be rejected ## Tests Running test specs is done using [busted](http://olivinelabs.com/busted/). You can install it using [LuaRocks](http://www.luarocks.org/), and then just call it with the `spec` folder: ``` luarocks install busted cd /path/to/lua_cliargs/ busted spec ``` ## Contributions If you come across a bug and you'd like to patch it, please fork the repository, commit your patch, and request a pull. ## Thanks to Many thanks to everyone who reported bugs, provided fixes, and added entirely new features: 1. [Thijs Schreijer](https://github.com/Tieske) 1. [Jack Lawson](https://github.com/ajacksified) 1. [Robert Andrew Ditthardt](https://github.com/DorianGray) 1. [Oscar Lim](https://github.com/o-lim) *If I missed you, don't hesitate to update this file or just email me.* ## Changelog ### Changes from 2.5.x 3.0 This major version release contains BREAKING API CHANGES. See the UPGRADE guide for help in updating your code to make use of it. **More flexible parsing** - options can occur anywhere now even after arguments (unless the `--` indicator is specified, then no options are parsed afterwards.) Previously, options were accepted only before arguments. - options using the short-key notation can be specified using `=` as a value delimiter as well as a space (e.g. `-c=lzma` and `-c lzma`) - the library is now more flexible with option definitions (notations like `-key VALUE`, `--key=VALUE`, `-k=VALUE` are all treated equally) - `--help` or `-h` will now cause the help listing to be displayed no matter where they are. Previously, this only happened if they were supplied as the first option. **Basic command support** You may now define commands with custom handlers. A command may be invoked by supplying its name as the first argument (options can still come before or afterwards). lua_cliargs will forward the rest of the options to that command to handle, which can be in a separate file. See `examples/04_commands--git.lua` for an example. **Re-defining defaults** It is now possible to pass a table containing default values (and override any existing defaults). The function for doing this is called `cli:load_defaults().`. This makes it possible to load run-time defaults from a configuration file, for example. **Reading configuration files** `cliargs` now exposes some convenience helpers for loading configuration from files (and a separate hook, `cli:load_defaults()` to inject this config if you want) found in `cli:read_defaults()`. This method takes a file-path and an optional file format and it will parse it for you, provided you have the necessary libraries installed. See the API docs for using this hook. **Other changes** - internal code changes and more comprehensive test-coverage ### Changes from 2.5.1 to 2.5.2 - No longer tracking the (legacy) tarballs in git or the luarocks package. Instead, we use the GitHub release tarballs for each version. ### Changes in 2.4.0 from 2.3-4 1. All arguments now accept a callback that will be invoked when parsing of those arguments was successful 2. (**POSSIBLY BREAKING**) Default value for flags is now `nil` instead of `false`. This will only affect existing behavior if you were explicitly testing unset flags to equal `false` (i.e. `if flag == false then`) as opposed to `if flag then` (or `if not flag then`). 3. Minor bugfixes ### Changes in 2.3.0 1. the parser will now understand `--` to denote the end of optional arguments and will map whatever comes after it to required/splat args 2. `-short VALUE` is now properly supported, so is `-short=VALUE` 3. short-key options can now officially be composed of more than 1 character 4. the parser now accepts callbacks that will be invoked as soon as options are parsed so that you can bail out of parsing preemptively (like for `--version` or `--help` options) 5. options can now accept multiple values via multiple invocations if a table was provided as a default value (passed-in values will be appended to that list) ### Changes in 2.2-0 from 2.1-2 1. the `=` that separates keys from values in the `--expanded-key` notation is no longer mandatory; using either a space or a `=` will map the value to the key (e.g., `--compress lzma` is equal to `--compress=lzma`) ### Changes in 2.0.0 from 1.x.x 1. added the 'splat' argument, an optional repetitive argument for which a maximum number of occurrences can be set 1. removed the reference, arguments are now solely returned by their key/expanded-key (BREAKING!) 1. removed object overhead and the `new()` method as the library will only be used once on program start-up (BREAKING!) 1. after parsing completed successfully, the library will effectively delete itself to free resources (BREAKING!) 1. option/flag is now allowed with only an expanded-key defined 1. Debug aid implemented; adding a first option `--__DUMP__`, will dump the results of parsing the command line. Especially for testing how to use the commandline with arguments containing spaces either quoted or not. 1. the `print_usage()` and `print_help()` now have a 'noprint' parameter that will not print the message, but return it as an error string (`nil + errmsg`) ## License The code is released under the MIT terms. Feel free to use it in both open and closed software as you please. Copyright (c) 2011-2015 Ahmad Amireh Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. lua_cliargs-3.0-1/UPGRADE.md000066400000000000000000000026561264514405200154240ustar00rootroot00000000000000## Upgrading from 2.x to 3.0 - `cli._VERSION` has been renamed to `cli.VERSION` **Function renames** The functions for defining arguments of all types have been renamed to drop the `_add` prefix from their names. This affects the following functions: - `cli:add_argument` has been renamed to `cli:argument` - `cli:add_option` has been renamed to `cli:option` - `cli:add_flag` has been renamed to `cli:flag` - `cli:optarg` has been renamed to `cli:splat` **Function alias removals** - `cli:add_opt` has been removed. Use `cli:option` instead - `cli:add_arg` has been removed. Use `cli:argument` instead - `cli:parse_args` has been removed. Use `cli:parse` instead **`cli:parse()` invocation changes** `cli:parse()` no longer accepts the auxiliary arguments `noprint` and `dump` as the second and third arguments; only one argument is now accepted and that is a custom arguments table. If left unspecified, we use the global `_G['arg']` program argument table as usual. So, the new signature is: `cli:parse(args: table) -> table` - to make the parser silent, use `cli:set_silent(true)` before invoking the parser - to generate the internal state dump, a runtime argument `--__DUMP__` must be passed as the first argument **Private function are now hidden** Hopefully you weren't relying on any of these because they are no longer exposed, and they weren't documented. The affected previous exports are: - `cli:__lookup()` - `cli:__add_opt()` lua_cliargs-3.0-1/bin/000077500000000000000000000000001264514405200145525ustar00rootroot00000000000000lua_cliargs-3.0-1/bin/coverage000077500000000000000000000011301264514405200162660ustar00rootroot00000000000000#!/usr/bin/env bash # Run busted and collect spec coverage using LuaCov. # Output will be found at /luacov.report.out. # # Usage: # # $ ./bin/coverage # $ cat luacov.report.out which luacov &> /dev/null if [ $? -ne 0 ]; then echo "You must have luacov installed." echo "Run 'luarocks install luacov' then try again". exit 1 fi which busted &> /dev/null if [ $? -ne 0 ]; then echo "You must have luacov installed." echo "Run 'luarocks install busted' then try again". exit 1 fi busted -c luacov src/ rm luacov.stats.out grep -zPo "(?s)={10,}\nSummary\n={10,}.+" luacov.report.outlua_cliargs-3.0-1/bin/docs000077500000000000000000000005321264514405200154300ustar00rootroot00000000000000#!/usr/bin/env bash if [ ! -d "doc" ]; then echo "Must be run from lua_cliargs root" exit 1 fi which npm &> /dev/null if [ $? -ne 0 ]; then echo "You must have npm (node.js) installed." exit 1 fi cd doc npm install ./node_modules/tinydoc/cli/tinydoc run echo "Docs compiled successfully. Open doc/compiled/index.html in a browser."lua_cliargs-3.0-1/bin/lint000077500000000000000000000004261264514405200154500ustar00rootroot00000000000000#!/usr/bin/env bash which luacheck &> /dev/null if [ $? -ne 0 ]; then echo "You must have luacheck installed." echo "Run 'luarocks install luacheck' then try again". exit 1 fi if [ ! -d src ]; then echo "You must run $0 from lua_cliargs root." exit 1 fi luacheck .lua_cliargs-3.0-1/bin/release000077500000000000000000000044471264514405200161310ustar00rootroot00000000000000#!/usr/bin/env bash [ -f ".env" ] && source ".env" [ -f ".env.local" ] && source ".env.local" function abort { echo -e "\e[00;31m[ FAILED ]\e[00m ${1}" exit 1 } function confirm { echo "${1} [y/N]" read confirmation if [ "${confirmation}" != "y" ]; then exit 0 fi } [ -z "${GITHUB_TOKEN}" ] && abort "Missing GITHUB_TOKEN env variable." [ -z "${GITHUB_USER}" ] && abort "Missing GITHUB_USER env variable." [ -z "${GITHUB_REPO}" ] && abort "Missing GITHUB_REPO env variable." [ -z "${LUAROCKS_API_KEY}" ] && abort "Missing LUAROCKS_API_KEY env variable." VERSION=$1 SRC_FILE="src/cliargs.lua" SRC_VERSION=$(grep "VERSION" src/cliargs.lua | sed -e 's/.*=//' -e 's/.* //' -e 's/"//g') NEW_ROCKSPEC="lua_cliargs-${VERSION}.rockspec" OLD_ROCKSPEC="lua_cliargs-${SRC_VERSION}.rockspec" if [ "${VERSION}" == "${SRC_VERSION}" ]; then abort "Version specified is the same as the current one in rockspec" fi # Publish to GitHub JSON_PAYLOAD=$( printf '{ "tag_name": "v%s", "target_commitish": "master", "name": "v%s", "body": "Release of version %s", "draft": false, "prerelease": false }' $VERSION $VERSION $VERSION ) echo $JSON_PAYLOAD echo "Releasing version ${VERSION}..." if [ ! -f $OLD_ROCKSPEC ]; then abort "Version in ${SRC_FILE} does not match the rockspec file!" fi # rename rockspec file mv $OLD_ROCKSPEC $NEW_ROCKSPEC # bump version in rockspec perl -p -i -e "s/${SRC_VERSION}/${VERSION}/g" $NEW_ROCKSPEC # bump version in src perl -p -i -e "s/${SRC_VERSION}/${VERSION}/" $SRC_FILE confirm "rockspec and source file have been modified, please confirm the changes. Proceed?" echo "Creating git release v${VERSION}..." git add $NEW_ROCKSPEC git rm $OLD_ROCKSPEC git add $SRC_FILE git commit -m "Release v${VERSION}" git push origin master echo "Done." confirm "Create a new GitHub release?" # the API will automatically create the tag for us, no need to do it manually! curl \ --data "$JSON_PAYLOAD" \ -X POST \ -H "Content-Type: application/json; charset=utf-8" \ -H "Accept: application/json" \ "https://api.github.com/repos/${GITHUB_USER}/${GITHUB_REPO}/releases?access_token=${GITHUB_TOKEN}" echo "Done." confirm "Publish to luarocks?" luarocks --api-key=$LUAROCKS_API_KEY upload $NEW_ROCKSPEC echo -e "\e[00;32m[ SUCCESS ]\e[00m" lua_cliargs-3.0-1/bin/watch-tests.sh000077500000000000000000000014131264514405200173560ustar00rootroot00000000000000#!/usr/bin/env bash # # Watches spec files and re-runs the busted suite when a spec or source file # changes. # # Usage: # # $0 [--focus] # # If --focus is passed, only the last spec file that has changed will be run # when a _source_ file changes. Otherwise, all specs will run on source changes. # # Requires inotify-tools[1]. # # [1] http://linux.die.net/man/1/inotifywait if [ ! -d spec ]; then echo "Must be run from lua_cliargs root." exit 1 fi LAST_FILE="spec/" inotifywait -rm --format '%w %f' -e close_write -e create src/ spec/ | while read dir file; do FILEPATH="${dir}${file}" if [[ $FILEPATH =~ src\/ ]]; then busted $@ "${LAST_FILE}" else if [[ $1 =~ "focus" ]]; then LAST_FILE=$FILEPATH fi busted $@ "${FILEPATH}" fi donelua_cliargs-3.0-1/doc/000077500000000000000000000000001264514405200145475ustar00rootroot00000000000000lua_cliargs-3.0-1/doc/package.json000066400000000000000000000006401264514405200170350ustar00rootroot00000000000000{ "name": "lua_cliargs_docs", "version": "1.0.0", "description": "docs for lua_cliargs", "main": "tinydoc.conf.js", "private": true, "dependencies": { "tinydoc-plugin-lua": "1.0.x", "tinydoc-theme-gitbooks": "1.0.x", "tinydoc": "3.2.x" }, "devDependencies": {}, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "Ahmad Amireh", "license": "MIT" } lua_cliargs-3.0-1/doc/tinydoc.conf.js000066400000000000000000000006541264514405200175070ustar00rootroot00000000000000var path = require('path'); exports.assetRoot = path.resolve(__dirname, '..'); exports.outputDir = path.resolve(__dirname, 'compiled'); exports.layout = 'single-page'; exports.title = 'lua_cliargs'; exports.scrollSpying = true; exports.resizableSidebar = false; exports.collapsibleSidebar = true; exports.plugins = [ require('tinydoc-plugin-lua')({ source: 'src/**/*.lua' }), require('tinydoc-theme-gitbooks')() ]; lua_cliargs-3.0-1/examples/000077500000000000000000000000001264514405200156205ustar00rootroot00000000000000lua_cliargs-3.0-1/examples/00_general.lua000077500000000000000000000046021264514405200202440ustar00rootroot00000000000000--[[ Try this file with the following commands lines; example.lua --help example.lua -o myfile -d --compress=gzip inputfile example.lua --__DUMP__ -o myfile -d --compress=gzip inputfile --]] local cli = require "cliargs" -- this is called when the flag -v or --version is set local function print_version() print("cli_example.lua: version 1.2.1") print("lua_cliargs: version " .. cli.VERSION) os.exit(0) end cli:set_name("cli_example.lua") -- Required arguments: cli:argument("OUTPUT", "path to the output file") -- Optional (repetitive) arguments -- only the last argument can be optional. Being set to maximum 3 optionals. cli:splat("INPUTS", "the source files to read from", "/tmp/foo", 3) -- Optional parameters: cli:option("-c, --compress=FILTER", "the filter to use for compressing output: gzip, lzma, bzip2, or none", "gzip") -- cli:option("-o FILE", "path to output file", "/dev/stdout") -- Flags: a flag is a boolean option. Defaults to false -- A flag with short-key notation only cli:flag("-d", "script will run in DEBUG mode") -- A flag with both the short-key and --expanded-key notations, and callback function cli:flag("-v, --version", "prints the program's version and exits", print_version) -- A flag with --expanded-key notation only cli:flag("--verbose", "the script output will be very verbose") -- A flag that can be negated using --no- as a prefix, but you'll still have -- to access its value without that prefix. See below for an example. cli:flag('--[no-]ice-cream', 'ice cream, or not', true) -- Parses from _G['arg'] local args, err = cli:parse(arg) if not args and err then -- something wrong happened and an error was printed print(string.format('%s: %s; re-run with help for usage', cli.name, err)) os.exit(1) elseif not args['ice-cream'] then print('kernel panic: NO ICE CREAM?!11') os.exit(1000) end -- argument parsing was successful, arguments can be found in `args` -- upon successful parsing cliargs will delete itslef to free resources -- for k,item in pairs(args) do print(k .. " => " .. tostring(item)) end print("Output file: " .. args["OUTPUT"]) print("Input files:") for i, out in ipairs(args.INPUTS) do print(" " .. i .. ". " .. out) end print(args.c) if not args['c'] or args['c'] == 'none' then print("Won't be compressing") else print("Compressing using " .. args['c']) end if args['ice-cream'] then print('And, one ice cream for you.') endlua_cliargs-3.0-1/examples/01_multiple_options.lua000066400000000000000000000022231264514405200222300ustar00rootroot00000000000000--[[ This example shows how to use multiple-value options that get appended into a list. Try this file with the following invocations; multiple_options.lua --help multiple_options.lua \ -i http://www.google.com \ -i http://www.yahoo.com \ -j 2 \ combined.html --]] local cli = require "cliargs" cli:set_name("example.lua") cli:splat("OUTPUT", "Path to where the combined HTML output should be saved.", "./a.html") cli:option("-i URLs...", "A url to download. You can pass in as many as needed", {} --[[ this is the important bit! ]]) cli:option("-j THREADS", "Concurrency threshold; the higher the number, the more files will be downloaded in parallel.", "2") -- Parses from _G['arg'] local args, err = cli:parse() if not args and err then print(err) os.exit(1) -- something wrong happened and an error was printed end if #args.i > 0 then print("Source URLs:") for i, url in ipairs(args.i) do print(" " .. i .. ". " .. url) end print("Downloading ".. #args.i .. " files in " .. tonumber(args.j) .. " threads.") print("Output will be found at " .. args.OUTPUT) else print("No source URLs provided, nothing to do!") end lua_cliargs-3.0-1/examples/02_parse_callbacks.lua000066400000000000000000000015651264514405200217440ustar00rootroot00000000000000--[[ Shows how to define a callback to be invoked as soon as an option is parsed. Callbacks are useful for abruptive options like "--help" or "--version" where you might want to stop the execution of the parser/program if passed. Try this file with the following commands lines; example.lua --version example.lua -v example.lua --]] local cli = require "cliargs" -- this is called when the flag -v or --version is set local function print_version() print(cli.name .. ": version 1.2.1") os.exit(0) end cli:set_name("try_my_version.lua") cli:flag("-v, --version", "prints the program's version and exits", print_version) -- Parses from _G['arg'] local args, err = cli:parse() -- something wrong happened, we print the error and exit if not args then print(err) os.exit(1) end -- if we got to this point, it means -v (or --version) were not passed: print "Why, hi!" lua_cliargs-3.0-1/examples/03_config_file.lua000066400000000000000000000032441264514405200210740ustar00rootroot00000000000000local cli = require 'cliargs' local tablex = require 'pl.tablex' -- we'll need this for merging tables cli:option('--config=FILEPATH', 'path to a config file', '.programrc') cli:flag('--quiet', 'Do not output anything to STDOUT', false) -- This example shows how to read default values from a base configuration file -- and optionally, if the user passes in a custom config file using --config -- we merge those with the parsed ones. local function load_config_file(file_path) local config = {} local success = pcall(function() config = loadfile(file_path)() end) if success then return config end end -- first, let's load from a ".programrc" file in the current-working directory -- if it exists and tell cliargs to use the defaults specified in that file: local base_config = load_config_file('.programrc') if base_config then cli:load_defaults(base_config) end -- now we parse the options like usual: local args, err = cli:parse() if not args and err then print(err) os.exit(1) end -- finally, let's check if the user passed in a config file using --config: if args.config then local custom_config = load_config_file(args.config) if custom_config then -- We merge the user defaults with the run-time ones. Note that run-time -- arguments should always have precedence over config defined in files. args = tablex.merge({}, custom_config, args, true) end end -- args is now ready for use: -- args.quiet will be whatever was set in the following priority: -- -- 1. --quiet or --no-quiet on the CLI -- 2. ["quiet"] in the user config file if --config was present -- 3. ["quiet"] in the base config file (.programrc) if it existed print(args.quiet) lua_cliargs-3.0-1/examples/04_commands--git-log.lua000066400000000000000000000005221264514405200220430ustar00rootroot00000000000000local cli = require('cliargs') cli:set_name('git-log') cli:set_description('Show commit logs') cli:flag('--[no-]follow', 'Continue listing the history of a file beyond renames (works only for a single file).') local args, err = cli:parse() if not args and err then print(err) os.exit(1) end print("git-log: follow?", args.follow)lua_cliargs-3.0-1/examples/04_commands--git.lua000066400000000000000000000014251264514405200212670ustar00rootroot00000000000000local cli = require('cliargs') cli:set_name('git') cli:set_description('the stupid content tracker') cli :command('diff', 'Show changes between commits, commit and working tree, etc') :splat('path', 'This form is to view the changes you made relative to the index (staging area for the next commit)', nil, 999) :flag('-p, --patch', 'This form is to view the changes you made relative to the index (staging area for the next commit)', true) :action(function(options) -- diff implementation goes here print("git-diff called with:", options.path, options.flag, options.patch) end) cli:command('log'):file('examples/04_commands--git-log.lua') local args, err = cli:parse() if not args and err then return print(err) elseif args then print('git with no command') endlua_cliargs-3.0-1/lua_cliargs-3.0-1.rockspec000066400000000000000000000027441264514405200204650ustar00rootroot00000000000000package = "lua_cliargs" version = "3.0-1" source = { url = "https://github.com/amireh/lua_cliargs/archive/v3.0-1.tar.gz", dir = "lua_cliargs-3.0-1" } description = { summary = "A command-line argument parser.", detailed = [[ This module adds support for accepting CLI arguments easily using multiple notations and argument types. cliargs allows you to define required, optional, and flag arguments. ]], homepage = "https://github.com/amireh/lua_cliargs", license = "MIT " } dependencies = { "lua >= 5.1" } build = { type = "builtin", modules = { ["cliargs"] = "src/cliargs.lua", ["cliargs.config_loader"] = "src/cliargs/config_loader.lua", ["cliargs.constants"] = "src/cliargs/constants.lua", ["cliargs.core"] = "src/cliargs/core.lua", ["cliargs.parser"] = "src/cliargs/parser.lua", ["cliargs.printer"] = "src/cliargs/printer.lua", ["cliargs.utils.disect"] = "src/cliargs/utils/disect.lua", ["cliargs.utils.disect_argument"] = "src/cliargs/utils/disect_argument.lua", ["cliargs.utils.filter"] = "src/cliargs/utils/filter.lua", ["cliargs.utils.lookup"] = "src/cliargs/utils/lookup.lua", ["cliargs.utils.shallow_copy"] = "src/cliargs/utils/shallow_copy.lua", ["cliargs.utils.split"] = "src/cliargs/utils/split.lua", ["cliargs.utils.trim"] = "src/cliargs/utils/trim.lua", ["cliargs.utils.wordwrap"] = "src/cliargs/utils/wordwrap.lua", } } lua_cliargs-3.0-1/spec/000077500000000000000000000000001264514405200147345ustar00rootroot00000000000000lua_cliargs-3.0-1/spec/cliargs_parsing_spec.lua000066400000000000000000000056731264514405200216330ustar00rootroot00000000000000describe("Testing cliargs library parsing commandlines", function() local cli before_each(function() cli = require("cliargs.core")() end) -- TODO, move to feature specs describe("Tests argument parsing with callback", function() local cb = {} local function callback(key, value) cb.key, cb.value = key, value return true end local function callback_arg(key, value) table.insert(cb, { key = key, value = value }) return true end local function callback_fail(key) return nil, "bad argument for " .. key end before_each(function() cb = {} end) it("tests one required argument", function() cli:argument("ARG", "arg description", callback) local expected = { ARG = "arg_val" } local result = cli:parse({ "arg_val" }) assert.are.same(expected, result) assert.are.equal("ARG", cb.key) assert.are.equal("arg_val", cb.value) end) it("tests required argument callback returning error", function() cli:argument("ARG", "arg description", callback_fail) local _, err = cli:parse({ "arg_val" }) assert.matches('bad argument for ARG', err) end) it("tests many required arguments", function() cli:argument("ARG1", "arg1 description", callback_arg) cli:argument("ARG2", "arg2 description", callback_arg) cli:argument("ARG3", "arg3 description", callback_arg) local expected = { ARG1 = "arg1_val", ARG2 = "arg2_val", ARG3 = "arg3_val" } local result = cli:parse({ "arg1_val", "arg2_val", "arg3_val" }) assert.are.same(expected, result) assert.are.same({ key = "ARG1", value = "arg1_val"}, cb[1]) assert.are.same({ key = "ARG2", value = "arg2_val"}, cb[2]) assert.are.same({ key = "ARG3", value = "arg3_val"}, cb[3]) end) it("tests one optional argument", function() cli:splat("OPTARG", "optional arg description", nil, 1, callback) local expected = { OPTARG = "opt_arg" } local result = cli:parse({ "opt_arg" }) assert.are.same(expected, result) assert.are.equal("OPTARG", cb.key) assert.are.equal("opt_arg", cb.value) end) it("tests optional argument callback returning error", function() cli:set_name('myapp') cli:splat("OPTARG", "optinoal arg description", nil, 1, callback_fail) local _, err = cli:parse({ "opt_arg" }) assert.matches('bad argument for OPTARG', err) end) it("tests many optional arguments", function() cli:splat("OPTARG", "optional arg description", nil, 3, callback_arg) local expected = { OPTARG = { "opt_arg1", "opt_arg2", "opt_arg3" } } local result = cli:parse({ "opt_arg1", "opt_arg2", "opt_arg3" }) assert.are.same(expected, result) assert.are.same({ key = "OPTARG", value = "opt_arg1"}, cb[1]) assert.are.same({ key = "OPTARG", value = "opt_arg2"}, cb[2]) assert.are.same({ key = "OPTARG", value = "opt_arg3"}, cb[3]) end) end) end) lua_cliargs-3.0-1/spec/cliargs_spec.lua000066400000000000000000000025251264514405200201010ustar00rootroot00000000000000require 'spec_helper' local cliargs = require 'cliargs' describe('cliargs', function() setup(function() cliargs:flag('--foo', '...') end) after_each(function() cliargs = require 'cliargs' end) it('does not blow up!', function() end) it('yields a default core instance', function() assert.equal(type(cliargs), 'table') end) describe('#parse', function() it('works', function() local args assert.has_no_errors(function() args = cliargs:parse({}) end) assert.equal(type(args), 'table') end) it('propagates errors', function() local args, err = cliargs:parse({ '--bar' }, true) assert.equal(type(err), 'string') assert.is_nil(args) end) end) describe('#cleanup', function() it('exposes a cleanup routine', function() assert.equal(type(cliargs.cleanup), 'function') end) it('actually cleans up', function() local modules = {} for k, _ in pairs(package.loaded) do if k:match('cliargs') then table.insert(modules, k) end end assert.is_not_equal(#modules, 0) assert.is_not_nil(package.loaded['cliargs']) cliargs:cleanup() for k, _ in pairs(modules) do assert.is_nil(package.loaded[k]) end assert.is_nil(package.loaded['cliargs']) end) end) end)lua_cliargs-3.0-1/spec/config_loader_spec.lua000066400000000000000000000023661264514405200212530ustar00rootroot00000000000000require 'spec_helper' describe("cliargs.config_loader", function() local cli, args, err before_each(function() cli = require("cliargs.core")() cli:flag('-q, --quiet', '...', false) cli:option('-c, --compress=VALUE', '...', 'lzma') cli:option('--config=FILE', '...', nil, function(_, path) local config config, err = cli:read_defaults(path) if config and not err then cli:load_defaults(config) end end) end) after_each(function() assert.equal(err, nil) assert.equal(args.c, 'bz2') assert.equal(args.compress, 'bz2') assert.equal(args.q, true) assert.equal(args.quiet, true) end) describe('#from_json', function() it('works', function() args, err = cli:parse({ '--config=spec/fixtures/config.json' }) end) end) describe('#from_ini', function() it('works', function() args, err = cli:parse({ '--config=spec/fixtures/config.ini' }) end) end) describe('#from_yaml', function() it('works', function() args, err = cli:parse({ '--config', 'spec/fixtures/config.yml' }) end) end) describe('#from_lua', function() it('works', function() args, err = cli:parse({ '--config', 'spec/fixtures/config.lua' }) end) end) end)lua_cliargs-3.0-1/spec/core_spec.lua000066400000000000000000000111541264514405200174030ustar00rootroot00000000000000local helpers = require "spec_helper" describe("cliargs::core", function() local cli before_each(function() cli = require("cliargs.core")() end) describe('#parse', function() context('when invoked without the arguments table', function() local global_arg before_each(function() global_arg = _G['arg'] end) after_each(function() _G['arg'] = global_arg end) it('uses the global _G["arg"] one', function() _G["arg"] = {"--quiet"} cli:option('--quiet', '...') assert.equal(cli:parse().quiet, true) end) end) it('does not mutate the argument table', function() local arguments = { "--quiet" } cli:option('--quiet', '...') cli:parse(arguments) assert.equal(#arguments, 1) assert.equal(arguments[1], "--quiet") end) it("generates the help listing but does not print it to STDOUT", function() local res, err = cli:parse({'--help'}) assert.equal(type(res), "nil") assert.equal(type(err), "string") end) it("returns error strings but does not print them to STDOUT", function() local res, err = cli:parse({ "arg1" }) assert.equal(type(res), "nil") assert.equal(type(err), "string") end) describe('displaying the help listing', function() local res, err before_each(function() cli:argument('INPUT', '...') cli:flag('--quiet', '...') end) after_each(function() assert.equal(type(res), "nil") assert.equal(type(err), "string") assert.equal(err, cli.printer.generate_help_and_usage()) end) it('works with --help in the beginning', function() res, err = helpers.parse(cli, '--help something') end) it('works with --help in the end of options', function() res, err = helpers.parse(cli, '--quiet --help something') end) it('works with --help after an argument', function() res, err = helpers.parse(cli, '--quiet something --help') end) end) end) describe('#parse - the --__DUMP__ special option', function() it('dumps the state and errors out', function() stub(cli.printer, 'print') cli:argument('OUTPUT', '...') cli:splat('INPUTS', '...', nil, 5) cli:option('-c, --compress=VALUE', '...') cli:flag('-q, --quiet', '...', true) local _, err = cli:parse({'--__DUMP__', '/tmp/out', '/tmp/in.1', '/tmp/in.2', '/tmp/in.3' }) assert.matches('======= Provided command line =============', err) end) end) describe('#redefine_default', function() it('allows me to change the default for an optargument', function() cli:splat('ROOT', '...', 'foo') assert.equal(cli:parse({}).ROOT, 'foo') cli:redefine_default('ROOT', 'bar') assert.equal(cli:parse({}).ROOT, 'bar') end) it('allows me to change the default for an option', function() cli:option('-c, --compress=VALUE', '...', 'lzma') assert.equal(cli:parse({}).compress, 'lzma') cli:redefine_default('compress', 'bz2') assert.equal(cli:parse({}).compress, 'bz2') end) it('allows me to change the default for a flag', function() cli:flag('-q, --quiet', '...', false) assert.equal(cli:parse({}).quiet, false) cli:redefine_default('quiet', true) assert.equal(cli:parse({}).quiet, true) end) end) describe('#load_defaults', function() local args, err before_each(function() cli:option('-c, --compress=VALUE', '...', 'lzma') cli:flag('-q, --quiet', '...', false) end) it('works', function() cli:load_defaults({ compress = 'bz2', quiet = true }) args, err = cli:parse({}) assert.equal(err, nil) assert.same(args, { c = 'bz2', compress = 'bz2', q = true, quiet = true }) end) context('when @strict is not true', function() it('ignores keys that could not be mapped', function() cli:load_defaults({ compress = 'bz2', quiet = true, what = 'woot!' }) args, err = cli:parse({}) assert.equal(err, nil) assert.same(args, { c = 'bz2', compress = 'bz2', q = true, quiet = true }) end) end) context('when @strict is true', function() it('returns an error message if a key could not be mapped', function() args, err = cli:load_defaults({ what = 'woot!' }, true) assert.equal(args, nil) assert.equal(err, "Unrecognized option with the key 'what'") end) end) end) end)lua_cliargs-3.0-1/spec/features/000077500000000000000000000000001264514405200165525ustar00rootroot00000000000000lua_cliargs-3.0-1/spec/features/argument_spec.lua000066400000000000000000000065031264514405200221150ustar00rootroot00000000000000local helpers = require("spec_helper") describe("cliargs - arguments", function() local cli before_each(function() cli = require("cliargs.core")() end) describe('defining arguments', function() it('works', function() assert.has_no_errors(function() cli:argument('PATH', 'path to a file') end) end) it('requires a key', function() assert.error_matches(function() cli:argument() end, 'Key and description are mandatory arguments') end) it('requires a description', function() assert.error_matches(function() cli:argument('PATH') end, 'Key and description are mandatory arguments') end) it('rejects a bad callback', function() assert.error_matches(function() cli:argument('PATH', 'path to a file', 'lolol') end, 'Callback argument must be a function') end) it('rejects duplicate arguments', function() cli:argument('PATH', 'path to a file') assert.error_matches(function() cli:argument('PATH', '...') end, 'Duplicate argument') end) end) describe('parsing arguments', function() it('works with a single argument', function() cli:argument('PATH', 'path to a file') local args = helpers.parse(cli, '/some/where') assert.equal(args.PATH, '/some/where') end) it('works with multiple arguments', function() cli:argument('INPUT', 'path to the input file') cli:argument('OUTPUT', 'path to the output file') local args = helpers.parse(cli, '/some/where /some/where/else') assert.equal(args.INPUT, '/some/where') assert.equal(args.OUTPUT, '/some/where/else') end) it('bails on missing arguments', function() cli:argument('INPUT', 'path to the input file') cli:argument('OUTPUT', 'path to the output file') local _, err = helpers.parse(cli, '/some/where') assert.matches('bad number of arguments', err) end) it('bails on too many arguments', function() cli:argument('INPUT', 'path to the input file') local _, err = helpers.parse(cli, 'foo bar') assert.matches('bad number of arguments', err) end) end) describe('@callback', function() local call_args local function capture(key, value, altkey) table.insert(call_args, { key, value, altkey }) end before_each(function() call_args = {} end) context('given a single argument', function() before_each(function() cli:argument('PATH', 'path to a file', capture) end) it('invokes the callback when the argument is parsed', function() helpers.parse(cli, '/some/where') assert.equal(call_args[1][1], 'PATH') assert.equal(call_args[1][2], '/some/where') assert.equal(call_args[1][3], nil) end) end) context('given multiple arguments', function() before_each(function() cli:argument('INPUT', '...', capture) cli:argument('OUTPUT', '...', capture) end) it('invokes the callback for each argument parsed', function() helpers.parse(cli, '/some/where /some/where/else') assert.equal(call_args[1][1], 'INPUT') assert.equal(call_args[1][2], '/some/where') assert.equal(call_args[2][1], 'OUTPUT') assert.equal(call_args[2][2], '/some/where/else') end) end) end) end)lua_cliargs-3.0-1/spec/features/command_spec.lua000066400000000000000000000040061264514405200217050ustar00rootroot00000000000000describe("cliargs - commands", function() local cli before_each(function() cli = require("cliargs.core")() end) describe('defining commands', function() it('works', function() assert.has_no_errors(function() cli:command('run', '...') end) end) end) describe('running commands', function() context('given an action callback', function() local cmd local action before_each(function() action = stub() cmd = cli:command('run', '...') cmd:action(action) end) it('works with no arguments', function() cli:parse({'run'}) end) it('runs the command parser and passes on the args to the command', function() cmd:argument('ROOT', '...') cli:parse({'run', '/some/path'}) assert.stub(action).called_with({ ROOT ='/some/path' }) end) it('propagates parsing errors', function() local _, err = cli:parse({'run', 'some_undefined_arg'}) assert.match("bad number of arguments", err) end) end) context('given a command file', function() local cmd before_each(function() cmd = cli:command('run', '...') cmd:file('spec/fixtures/test-command.lua') end) it('works with no arguments', function() cli:parse({'run'}) end) it('returns an error on bad file', function() cmd:file('foo') assert.error_matches(function() cli:parse({'run'}) end, 'cannot open foo'); end) it('passes on arguments to the command', function() cmd:argument('ROOT', '...') local res, err = cli:parse({'run', '/some/path'}) assert.equal(nil, err); assert.equal(res.ROOT, '/some/path') end) it('propagates parsing errors', function() cmd:argument('ROOT', '...') local res, err = cli:parse({'run', '/some/path', 'foo'}) assert.equal(nil, res); assert.match('bad number of arguments', err) end) end) end) end)lua_cliargs-3.0-1/spec/features/flag_spec.lua000066400000000000000000000126061264514405200212050ustar00rootroot00000000000000local helpers = require("spec_helper") describe("cliargs - flags", function() local cli before_each(function() cli = require("cliargs.core")() end) describe('defining flags', function() it('works', function() assert.has_no_errors(function() cli:flag('--quiet', 'suppress output') end) end) it('requires a key', function() assert.error_matches(function() cli:flag() end, 'Key and description are mandatory arguments') end) it('requires a description', function() assert.error_matches(function() cli:flag('--quiet') end, 'Key and description are mandatory arguments') end) it('rejects a value label', function() assert.error_matches(function() cli:flag('--quiet=QUIET', '...') end, 'A flag type option cannot have a value set') end) it('rejects a duplicate flag', function() cli:flag('--quiet', '...') assert.error_matches(function() cli:flag('--quiet', '...') end, 'Duplicate') end) end) describe('parsing', function() it('works with only a short key: -v', function() cli:flag('-v', '...') assert.equal(helpers.parse(cli, '-v').v, true) end) it('works with only an expanded key: --verbose', function() cli:flag('--verbose', '...') assert.equal(helpers.parse(cli, '--verbose').verbose, true) end) it('works with both: -v, --verbose', function() cli:flag('-v, --verbose', '...') assert.equal(helpers.parse(cli, '--verbose').verbose, true) assert.equal(helpers.parse(cli, '-v').verbose, true) end) context('given a default value', function() it('accepts a nil', function() assert.has_no_errors(function() cli:flag('--quiet', '...', nil) end) assert.equal(helpers.parse(cli, '').quiet, nil) end) it('accepts a true value', function() assert.has_no_errors(function() cli:flag('--quiet', '...', true) end) assert.equal(helpers.parse(cli, '').quiet, true) end) it('accepts a false value', function() assert.has_no_errors(function() cli:flag('--quiet', '...', false) end) assert.equal(helpers.parse(cli, '').quiet, false) end) end) context('given an unknown flag', function() it('bails', function() local _, err = helpers.parse(cli, '--asdf', true) assert.matches('unknown', err) end) end) end) describe('parsing an option with a short key longer than 1 char', function() before_each(function() cli:flag('-Wno-unsigned', '...') end) it('works', function() local args = helpers.parse(cli, '-Wno-unsigned') assert.equal(args['Wno-unsigned'], true) end) end) describe('parsing negatable flags', function() context('when a flag is negatable (-q, --[no-]quiet)', function() before_each(function() cli:flag('-q, --[no-]quiet', '...') end) it('works', function() local args = helpers.parse(cli, '--no-quiet') assert.equal(args.quiet, false) end) it('overrides the original version (-q --no-quiet => false)', function() local args = helpers.parse(cli, '-q --no-quiet') assert.equal(args.quiet, false) end) it('ignores the negated version (--no-quiet -q => true)', function() local args = helpers.parse(cli, '--no-quiet -q') assert.equal(args.quiet, true) end) end) context('when a flag is NON-negatable (-q, --quiet)', function() before_each(function() cli:flag('-q, --quiet', '...') end) it('bails', function() local _, err = helpers.parse(cli, '--no-quiet') assert.matches('may not be negated', err) end) end) end) describe('@callback', function() local call_args local function capture(key, value, altkey) table.insert(call_args, { key, value, altkey }) end context('given a single flag', function() before_each(function() call_args = {} cli:flag('-q, --quiet', '...', nil, capture) end) it('invokes the callback when the flag is parsed', function() helpers.parse(cli, '--quiet') assert.equal(call_args[1][1], 'quiet') assert.equal(call_args[1][2], true) assert.equal(call_args[1][3], 'q') end) end) context('given a negated flag', function() before_each(function() call_args = {} cli:flag('-q, --[no-]quiet', '...', nil, capture) end) it('invokes the callback when the flag is parsed', function() helpers.parse(cli, '--no-quiet') assert.equal(call_args[1][1], 'quiet') assert.equal(call_args[1][2], false) assert.equal(call_args[1][3], 'q') end) end) context('given multiple flags', function() before_each(function() call_args = {} cli:flag('-q, --quiet', '...', nil, capture) cli:flag('--verbose', '...', nil, capture) end) it('invokes the callback for each flag parsed', function() helpers.parse(cli, '--quiet --verbose') assert.equal(call_args[1][1], 'quiet') assert.equal(call_args[1][2], true) assert.equal(call_args[1][3], 'q') assert.equal(call_args[2][1], 'verbose') assert.equal(call_args[2][2], true) assert.equal(call_args[2][3], nil) end) end) end) end)lua_cliargs-3.0-1/spec/features/integration_spec.lua000066400000000000000000000073511264514405200226200ustar00rootroot00000000000000local helpers = require "spec_helper" describe("integration: parsing", function() local cli before_each(function() cli = require("cliargs.core")() end) it('is a no-op when no arguments or options are defined', function() assert.are.same(helpers.parse(cli, ''), {}) end) context('given a set of arguments', function() it('works when all are passed in', function() cli:argument('FOO', '...') cli:argument('BAR', '...') local args = helpers.parse(cli, 'foo bar') assert.same(args, { FOO = "foo", BAR = "bar" }) end) end) context('given an argument and a splat', function() before_each(function() cli:argument('FOO', '...') cli:splat('BAR', '...', nil, 2) end) it('works when only the argument is passed in', function() local args = helpers.parse(cli, 'foo') assert.same(args, { FOO = "foo", BAR = {} }) end) it('works when both are passed in', function() local args = helpers.parse(cli, 'foo bar') assert.same(args, { FOO = "foo", BAR = { "bar" } }) end) it('works when both are passed in with repetition for the splat', function() local args = helpers.parse(cli, 'foo bar zoo') assert.same(args, { FOO = "foo", BAR = { "bar", "zoo" } }) end) end) context('given a set of options', function() it('works when nothing is passed in', function() cli:option('--foo FOO', '...') cli:option('--bar BAR', '...') local args = helpers.parse(cli, '') assert.same(args, {}) end) it('works when they are passed in', function() cli:option('-f, --foo FOO', '...') cli:option('--bar BAR', '...') local args = helpers.parse(cli, '-f something --bar=BAZ') assert.same(args, { f = "something", foo = "something", bar = "BAZ" }) end) end) context('given arguments, options, and flags', function() before_each(function() cli:argument('FOO', '...') cli:option('--input=SOURCE', '...') cli:flag('--quiet', '...') end) it('works when nothing but arguments are passed in', function() local args = helpers.parse(cli, 'asdf') assert.same(args, { FOO = 'asdf', input = nil, quiet = nil }) end) it('works when arguments and options are passed in', function() local args = helpers.parse(cli, '--input /tmp/file asdf') assert.same(args, { FOO = 'asdf', input = '/tmp/file', quiet = nil }) end) it('works when everything is passed in', function() local args = helpers.parse(cli, '--input /tmp/file --quiet asdf') assert.same(args, { FOO = 'asdf', input = '/tmp/file', quiet = true }) end) it('works when an option comes after an argument', function() local args, err = helpers.parse(cli, 'asdf --quiet') assert.equal(err, nil) assert.same(args, { FOO = 'asdf', quiet = true }) end) end) describe('using -- to separate options from arguments', function() before_each(function() cli:argument('INPUT', '...') cli:splat('OUTPUT', '...', nil, 1) cli:flag('--verbose', '...') cli:flag('--quiet', '...') end) it('works', function() local args = helpers.parse(cli, '--verbose -- --input -d') assert.same(args, { INPUT = "--input", OUTPUT = "-d", verbose = true, quiet = nil }) end) it('does not actually parse an option if it comes after --', function() local args = helpers.parse(cli, '-- --input --quiet') assert.same(args, { INPUT = "--input", OUTPUT = "--quiet", verbose = nil, quiet = nil }) end) end) end)lua_cliargs-3.0-1/spec/features/option_spec.lua000066400000000000000000000165621264514405200216110ustar00rootroot00000000000000local helpers = require("spec_helper") describe("cliargs - options", function() local cli before_each(function() cli = require("cliargs.core")() end) describe('defining options', function() it('requires a key', function() assert.error_matches(function() cli:option() end, 'Key and description are mandatory arguments') end) it('requires a description', function() assert.error_matches(function() cli:option('--url=URL') end, 'Key and description are mandatory arguments') end) it('works', function() assert.has_no_errors(function() cli:option('--url=URL', '...') end) end) it('rejects a duplicate option', function() cli:option('--url=URL', '...') assert.error_matches(function() cli:option('--url=URL', '...') end, 'Duplicate') end) end) it('works with only a short key: -u VALUE', function() cli:option('-u VALUE', '...') assert.equal(helpers.parse(cli, '-u something').u, 'something') end) it('works with only an expanded key: --url=VALUE', function() cli:option('--url=VALUE', '...') assert.equal(helpers.parse(cli, '--url=something').url, 'something') end) it('works with only an expanded key using space as a delimiter: --url VALUE', function() cli:option('--url VALUE', '...') assert.equal(helpers.parse(cli, '--url something').url, 'something') end) it('works with both: -u, --url=VALUE', function() cli:option('-u, --url=VALUE', '...') assert.equal(helpers.parse(cli, '--url=something').url, 'something') assert.equal(helpers.parse(cli, '-u=something').url, 'something') end) it('works with both keys and no comma between them: -u --url VALUE', function() cli:option('-u --url=VALUE', '...') assert.equal(helpers.parse(cli, '--url something').url, 'something') assert.equal(helpers.parse(cli, '-u something').url, 'something') end) context('given no value indicator (an implicit flag, e.g. --quiet)', function() it('proxies to #flag', function() stub(cli, 'flag') cli:option('-q', '...') assert.stub(cli.flag).was.called(); end) end) describe('parsing', function() before_each(function() cli:option('-s, --source=SOURCE', '...') end) context('using a -short key and space as a delimiter', function() it('works', function() local args = helpers.parse(cli, '-s /foo/**/*.lua') assert.equal(args.source, '/foo/**/*.lua') end) end) context('using a -short key and = as a delimiter', function() it('works', function() local args = helpers.parse(cli, '-s=/foo/**/*.lua') assert.equal(args.source, '/foo/**/*.lua') end) end) context('using an --expanded-key and space as a delimiter', function() it('works', function() local args = helpers.parse(cli, '--source /foo/**/*.lua') assert.equal(args.source, '/foo/**/*.lua') end) end) context('using an --expanded-key and = as a delimiter', function() it('works', function() local args = helpers.parse(cli, '--source=/foo/**/*.lua') assert.equal(args.source, '/foo/**/*.lua') end) end) context('for an option with a short key longer than 1 char', function() before_each(function() cli:option('-Xassembler OPTIONS', '...') end) it('works', function() local args = helpers.parse(cli, '-Xassembler foo') assert.equal(args.Xassembler, 'foo') end) end) context('given multiple values', function() before_each(function() cli:option('-k, --key=OPTIONS', '...', {}) end) it('works', function() local args = helpers.parse(cli, '-k 1 --key=3 -k asdf') assert.equal(type(args.k), 'table') assert.equal(#args.k, 3) assert.equal(args.k[1], '1') assert.equal(args.k[2], '3') assert.equal(args.k[3], 'asdf') end) end) context('given an unknown option', function() it('bails', function() local _, err = helpers.parse(cli, '--asdf=jkl;', true) assert.matches('unknown', err) end) end) it('bails if no value was passed', function() local _, err = helpers.parse(cli, '-s') assert.matches("option %-s requires a value to be set", err) end) end) describe('parsing with a default value', function() it('accepts a nil', function() cli:option('--compress=VALUE', '...', nil) assert.equal(helpers.parse(cli, '').compress, nil) end) it('accepts a string', function() cli:option('--compress=VALUE', '...', 'lzma') assert.equal(helpers.parse(cli, '').compress, 'lzma') end) it('accepts a number', function() cli:option('--count=VALUE', '...', 5) assert.equal(helpers.parse(cli, '').count, 5) end) it('accepts a boolean', function() cli:option('--quiet=VALUE', '...', true) assert.equal(helpers.parse(cli, '').quiet, true) end) it('accepts an empty table', function() cli:option('--sources=VALUE', '...', {}) assert.same(helpers.parse(cli, '').sources, {}) end) it('lets me override/reset the default value', function() cli:option('--compress=URL', '...', 'lzma') assert.equal(helpers.parse(cli, '--compress=').compress, nil) end) end) describe('@callback', function() local call_args local function capture(key, value, altkey) table.insert(call_args, { key, value, altkey }) end context('given a single option', function() before_each(function() call_args = {} cli:option('-c, --compress=VALUE', '...', nil, capture) end) it('invokes the callback when the option is parsed', function() helpers.parse(cli, '--compress=lzma') assert.equal(call_args[1][1], 'compress') assert.equal(call_args[1][2], 'lzma') assert.equal(call_args[1][3], 'c') end) it('invokes the callback with the latest value when the option is a list', function() cli:option('--tags=VALUE', '...', {}, capture) helpers.parse(cli, '--tags only --tags foo') assert.equal(call_args[1][1], 'tags') assert.equal(call_args[1][2], 'only') assert.equal(call_args[1][3], nil) assert.equal(call_args[2][1], 'tags') assert.equal(call_args[2][2], 'foo') assert.equal(call_args[2][3], nil) end) end) context('when the callback returns an error message', function() it('propagates the error', function() cli:option('-c, --compress=VALUE', '...', nil, function() return nil, ">>> bad argument <<<" end) local _, err = helpers.parse(cli, '-c lzma', true) assert.equal('>>> bad argument <<<', err) end) end) context('given multiple options', function() before_each(function() call_args = {} cli:option('-c, --compress=VALUE', '...', nil, capture) cli:option('--input=PATH', '...', nil, capture) end) it('invokes the callback for each option parsed', function() helpers.parse(cli, '-c lzma --input=/tmp') assert.equal(call_args[1][1], 'c') assert.equal(call_args[1][2], 'lzma') assert.equal(call_args[1][3], 'compress') assert.equal(call_args[2][1], 'input') assert.equal(call_args[2][2], '/tmp') assert.equal(call_args[2][3], nil) end) end) end) end)lua_cliargs-3.0-1/spec/features/splatarg_spec.lua000066400000000000000000000064171264514405200221140ustar00rootroot00000000000000local helpers = require("spec_helper") describe("cliargs - splat arguments", function() local cli before_each(function() cli = require("cliargs.core")() end) describe('defining the splat arg', function() it('works', function() assert.has_no_error(function() cli:splat('SPLAT', 'some repeatable arg') end) end) it('requires a key', function() assert.error_matches(function() cli:splat() end, 'Key and description are mandatory arguments') end) it('requires a description', function() assert.error_matches(function() cli:splat('SPLAT') end, 'Key and description are mandatory arguments') end) it('rejects multiple definitions', function() cli:splat('SPLAT', 'some repeatable arg') assert.error_matches(function() cli:splat('SOME_SPLAT', 'some repeatable arg') end, 'Only one splat') end) end) describe('default value', function() it('allows me to define a default value', function() cli:splat('SPLAT', 'some repeatable arg', 'foo') end) context('when only 1 occurrence is allowed', function() before_each(function() cli:splat('SPLAT', 'some repeatable arg', 'foo') end) it('uses the default value when nothing is passed in', function() assert.equal(helpers.parse(cli, '').SPLAT, 'foo') end) end) context('when more than 1 occurrence is allowed', function() before_each(function() cli:splat('SPLAT', 'some repeatable arg', 'foo', 3) end) it('uses the default value only once when nothing is passed in', function() assert.same(helpers.parse(cli, '').SPLAT, { 'foo' }) end) it('does not use the default value if something was passed in at least once', function() assert.same(helpers.parse(cli, 'asdf').SPLAT, { 'asdf' }) end) end) end) describe('repetition count', function() it('accepts a repetition count', function() assert.has_no_error(function() cli:splat('SPLAT', 'some repeatable arg', nil, 2) end) end) it('appends the values to a list', function() cli:splat('SPLAT', 'some repeatable arg', nil, 2) local args = helpers.parse(cli, 'a b') assert.equal(#args.SPLAT, 2) assert.equal(args.SPLAT[1], 'a') assert.equal(args.SPLAT[2], 'b') end) it('bails if more values were passed than acceptable', function() cli:splat('SPLAT', 'foobar', nil, 2) local _, err = helpers.parse(cli, 'a b c') assert.matches("bad number of arguments", err) end) end) context("given a splatarg as the only argument/option", function() it("works", function() cli:splat('SPLAT', 'foobar', nil, 1) local args = helpers.parse(cli, 'asdf') assert.equal(type(args.SPLAT), "string") assert.equal(args.SPLAT, "asdf") end) end) describe('@callback', function() it('invokes the callback every time a value for the splat arg is parsed', function() local call_args = {} cli:splat('SPLAT', 'foobar', nil, 2, function(_, value) table.insert(call_args, value) end) helpers.parse(cli, 'a b') assert.equal(#call_args, 2) assert.equal(call_args[1], 'a') assert.equal(call_args[2], 'b') end) end) end)lua_cliargs-3.0-1/spec/fixtures/000077500000000000000000000000001264514405200166055ustar00rootroot00000000000000lua_cliargs-3.0-1/spec/fixtures/config.ini000066400000000000000000000000411264514405200205460ustar00rootroot00000000000000[cli] quiet = true compress = bz2lua_cliargs-3.0-1/spec/fixtures/config.json000066400000000000000000000000501264514405200207400ustar00rootroot00000000000000{ "quiet": true, "compress": "bz2" }lua_cliargs-3.0-1/spec/fixtures/config.lua000066400000000000000000000000651264514405200205560ustar00rootroot00000000000000return { ["quiet"] = true, ["compress"] = "bz2" }lua_cliargs-3.0-1/spec/fixtures/config.yml000066400000000000000000000000351264514405200205730ustar00rootroot00000000000000--- quiet: true compress: bz2lua_cliargs-3.0-1/spec/fixtures/test-command.lua000066400000000000000000000001541264514405200217030ustar00rootroot00000000000000local cli = require('cliargs') cli:set_name('test-command') cli:argument('ROOT', '...') return cli:parse()lua_cliargs-3.0-1/spec/printer_spec.lua000066400000000000000000000153531264514405200201430ustar00rootroot00000000000000local helpers = require 'spec_helper' local trim = helpers.trim describe('printer', function() local cli before_each(function() cli = require("cliargs.core")() end) describe('#generate_usage', function() local function assert_msg(expected_msg) local actual_msg = cli.printer.generate_usage() assert.equal(trim(expected_msg), trim(actual_msg)) end it('works with 0 arguments', function() assert_msg 'Usage:' end) it('works with 1 argument', function() cli:argument('INPUT', 'path to the input file') assert_msg [==[ Usage: [--] INPUT ]==] end) it('works with 2+ arguments', function() cli:argument('INPUT', '...') cli:argument('OUTPUT', '...') assert_msg [==[ Usage: [--] INPUT OUTPUT ]==] end) it('prints the app name', function() cli:set_name('foo') assert_msg 'Usage: foo' end) it('prints options', function() cli:option('--foo=VALUE', '...') assert_msg [==[ Usage: [OPTIONS] ]==] end) it('prints flags', function() cli:flag('--foo', '...') assert_msg [==[ Usage: [OPTIONS] ]==] end) it('prints a splat arg with reptitions == 1', function() cli:splat('OUTPUT', '...', nil, 1) assert_msg [==[ Usage: [--] [OUTPUT] ]==] end) it('prints a splat arg with reptitions == 2', function() cli:splat('OUTPUT', '...', nil, 2) assert_msg [==[ Usage: [--] [OUTPUT-1 [OUTPUT-2]] ]==] end) it('prints a splat arg with reptitions > 2', function() cli:splat('OUTPUT', '...', nil, 5) assert_msg [==[ Usage: [--] [OUTPUT-1 [OUTPUT-2 [...]]] ]==] end) end) describe('#generate_help', function() local function assert_msg(expected_msg) local actual_msg = cli.printer.generate_help() assert.equal(trim(expected_msg), trim(actual_msg)) end it('works with nothing', function() assert_msg '' end) it('works with 1 argument', function() cli:argument('INPUT', 'path to the input file') assert_msg [==[ ARGUMENTS: INPUT path to the input file (required) ]==] end) it('works with 2+ arguments', function() cli:argument('INPUT', 'path to the input file') cli:argument('OUTPUT', 'path to the output file') assert_msg [==[ ARGUMENTS: INPUT path to the input file (required) OUTPUT path to the output file (required) ]==] end) it('works with 1 option', function() cli:option('--compress=VALUE', 'compression algorithm to use') assert_msg [==[ OPTIONS: --compress=VALUE compression algorithm to use ]==] end) it("prints an option's default value", function() cli:option('--compress=VALUE', 'compression algorithm to use', 'lzma') assert_msg [==[ OPTIONS: --compress=VALUE compression algorithm to use (default: lzma) ]==] end) it("prints a repeatable option", function() cli:option('--compress=VALUE', 'compression algorithm to use', { 'lzma' }) assert_msg [==[ OPTIONS: --compress=VALUE compression algorithm to use (default: []) ]==] end) it('works with many options', function() cli:option('--compress=VALUE', 'compression algorithm to use') cli:option('-u, --url=URL', '...') assert_msg [==[ OPTIONS: --compress=VALUE compression algorithm to use -u, --url=URL ... ]==] end) context('given a flag', function() it('prints it under OPTIONS', function() cli:flag('-q, --quiet', '...') assert_msg [==[ OPTIONS: -q, --quiet ... ]==] end) end) context('given a flag with a default value but is not negatable', function() it('does not print "on" or "off"', function() cli:flag('--quiet', '...', true) assert_msg [==[ OPTIONS: --quiet ... ]==] end) end) context('given a negatable flag', function() it('prints it along with its default value', function() cli:flag('--[no-]quiet', '...', true) cli:flag('--[no-]debug', '...', false) assert_msg [==[ OPTIONS: --[no-]quiet ... (default: on) --[no-]debug ... (default: off) ]==] end) end) context('given a splat arg', function() it('prints it with a repetition of 1', function() cli:splat("INPUTS", "directories to read from") assert_msg [==[ ARGUMENTS: INPUTS directories to read from (optional) ]==] end) it('prints it with a repetition of > 1', function() cli:splat("INPUTS", "directories to read from", nil, 3) assert_msg [==[ ARGUMENTS: INPUTS directories to read from (optional) ]==] end) it('prints it without a default value', function() cli:splat("INPUTS", "directories to read from") assert_msg [==[ ARGUMENTS: INPUTS directories to read from (optional) ]==] end) it('prints it with a default value', function() cli:splat("INPUTS", "directories to read from", 'foo') assert_msg [==[ ARGUMENTS: INPUTS directories to read from (optional, default: foo) ]==] end) end) end) describe('#dump_internal_state', function() local original_arg before_each(function() original_arg = _G['arg'] _G['arg'] = { 'spec/printer_spec.lua' } end) after_each(function() _G['arg'] = original_arg end) it('works', function() cli:argument('OUTPUT', '...') cli:splat('INPUTS', '...', nil, 100) cli:option('-c, --compress=VALUE', '...') cli:flag('-q, --quiet', '...', true) assert.equal(trim [==[ ======= Provided command line ============= Number of arguments: 1 = 'spec/printer_spec.lua' ======= Parsed command line =============== Arguments: OUTPUT => 'nil' Optional arguments:INPUTS; allowed are 100 arguments Optional parameters: -c, --compress=VALUE => nil (nil) -q, --quiet => nil (nil) =========================================== ]==], trim(cli.printer.dump_internal_state({}))) end) it('does not fail with an optarg of 1 reptitions', function() cli:splat('INPUTS', '...', nil, 1) cli.printer.dump_internal_state({}) end) it('does not fail with an optarg of many reptitions', function() cli:splat('INPUTS', '...', nil, 5) cli.printer.dump_internal_state({}) end) end) end)lua_cliargs-3.0-1/spec/spec_helper.lua000066400000000000000000000013671264514405200177370ustar00rootroot00000000000000-- luacheck: ignore 111 local exports = {} local split = require 'cliargs.utils.split' local busted = require 'busted' function odescribe(desc, runner) busted.describe("#only " .. desc, runner) end function xdescribe() end function oit(desc, runner) busted.it("#only " .. desc, runner) end function xit(desc, _) busted.it(desc) end exports.parse = function(cli, str) return cli:parse(split(str, '%s+')) end exports.trim = function(s) local lines = split(s, "\n") local _ if #lines == 0 then return s end local padding = lines[1]:find('%S') or 0 local buffer = '' for _, line in pairs(lines) do buffer = buffer .. line:sub(padding, -1):gsub("%s+$", '') .. "\n" end return buffer:gsub("%s+$", '') end return exportslua_cliargs-3.0-1/spec/utils/000077500000000000000000000000001264514405200160745ustar00rootroot00000000000000lua_cliargs-3.0-1/spec/utils/disect_argument_spec.lua000066400000000000000000000024631264514405200227730ustar00rootroot00000000000000local disect_argument = require('cliargs.utils.disect_argument') require("spec_helper") describe("utils::disect_argument", function() local function assert_disect(pattern, expected) it("works with '" .. pattern .. "'", function() local symbol, key, value, negated = disect_argument(pattern) assert.equal(symbol, expected[1]) assert.equal(key, expected[2]) assert.equal(value, expected[3]) assert.equal(negated, expected[4]) end) end -- flags assert_disect("", { nil, nil, nil, false }) assert_disect("-q", { '-', 'q', nil, false }) assert_disect("--quiet", { '--', 'quiet', nil, false }) -- -- -- -- flag negation assert_disect("--no-quiet", { '--', 'quiet', nil, true }) assert_disect("--no-q", { '--', 'q', nil, true }) -- -- options assert_disect("-v=VALUE", { '-', 'v', 'VALUE', false }) assert_disect("--value=VALUE", { '--', 'value', 'VALUE', false }) assert_disect('--value=with whitespace', { '--', 'value', 'with whitespace', false }) -- -- end-of-options indicator assert_disect('--', { '--', nil, nil, false }) -- -- values assert_disect('value', { nil, nil, 'value', false }) assert_disect('/path/to/something', { nil, nil, '/path/to/something', false }) assert_disect('oops-look-at--me', { nil, nil, 'oops-look-at--me', false }) end) lua_cliargs-3.0-1/spec/utils/disect_spec.lua000066400000000000000000000020631264514405200210650ustar00rootroot00000000000000local disect = require('cliargs.utils.disect') describe("utils::disect", function() local function assert_disect(pattern, expected) it("works with '" .. pattern .. "'", function() local k, ek, v = disect(pattern) assert.equal(k, expected[1]) assert.equal(ek, expected[2]) assert.equal(v, expected[3]) end) end assert_disect("-q", { 'q', nil, nil }) assert_disect("-Wno-unsigned", { 'Wno-unsigned', nil, nil }) assert_disect("-q, --quiet", { 'q', 'quiet', nil }) assert_disect("-q --quiet", { 'q', 'quiet', nil }) -- now with value indicators assert_disect("-v VALUE", { 'v', nil, 'VALUE' }) assert_disect("-v=VALUE", { 'v', nil, 'VALUE' }) assert_disect("--value VALUE", { nil, 'value', 'VALUE' }) assert_disect("--value=VALUE", { nil, 'value', 'VALUE' }) assert_disect("-v --value=VALUE", { 'v', 'value', 'VALUE' }) assert_disect("-v --value VALUE", { 'v', 'value', 'VALUE' }) assert_disect("-v, --value=VALUE", { 'v', 'value', 'VALUE' }) assert_disect("-v, --value VALUE", { 'v', 'value', 'VALUE' }) end) lua_cliargs-3.0-1/spec/utils/split_spec.lua000066400000000000000000000011171264514405200207440ustar00rootroot00000000000000local subject = require('cliargs.utils.split') describe("utils::split", function() it("should work", function() -- takes: str, split-char local expected, result result = subject("hello,world",",") expected = {"hello", "world"} assert.is.same(result, expected) result = subject("hello,world,",",") expected = {"hello", "world"} assert.is.same(result, expected) result = subject("hello",",") expected = {"hello"} assert.is.same(result, expected) result = subject("",",") expected = {} assert.is.same(result, expected) end) end) lua_cliargs-3.0-1/spec/utils/wordwrap_spec.lua000066400000000000000000000014011264514405200214520ustar00rootroot00000000000000local subject = require('cliargs.utils.wordwrap') describe("utils::wordwrap", function() it("should work", function() -- takes: text, size, padding local text = "123456789 123456789 123456789!" local expected, result result = subject(text, 10) expected = "123456789\n123456789\n123456789!" assert.is.same(result, expected) -- exact length + 1 overflow result = subject(text, 9) expected = "123456789\n123456789\n123456789\n!" assert.is.same(result, expected) result = subject(text, 9, nil, true) expected = "123456789\n123456789\n123456789!" assert.is.same(result, expected) result = subject(text, 8) expected = "12345678\n9\n12345678\n9\n12345678\n9!" assert.is.same(result, expected) end) end) lua_cliargs-3.0-1/src/000077500000000000000000000000001264514405200145715ustar00rootroot00000000000000lua_cliargs-3.0-1/src/cliargs.lua000066400000000000000000000011561264514405200167230ustar00rootroot00000000000000-- luacheck: ignore 212 local core = require('cliargs.core')() local unpack = _G.unpack or table.unpack local cli = setmetatable({},{ __index = core }) function cli:parse(arguments, no_cleanup) if not no_cleanup then cli:cleanup() end local out = { core.parse(self, arguments) } return unpack(out) end -- Clean up the entire module (unload the scripts) as it's expected to be -- discarded after use. function cli:cleanup() for k, v in pairs(package.loaded) do if (v == cli) or (k:match('cliargs')) then package.loaded[k] = nil end end cli = nil end cli.VERSION = "3.0-1" return clilua_cliargs-3.0-1/src/cliargs/000077500000000000000000000000001264514405200162155ustar00rootroot00000000000000lua_cliargs-3.0-1/src/cliargs/config_loader.lua000066400000000000000000000055211264514405200215160ustar00rootroot00000000000000local trim = require 'cliargs.utils.trim' local function read_file(filepath) local f, err = io.open(filepath, "r") if not f then return nil, err end local contents = f:read('*all') f:close() return contents end return { FORMAT_LOADERS = { ["lua"] = "from_lua", ["json"] = "from_json", ["yaml"] = "from_yaml", ["yml"] = "from_yaml", ["ini"] = "from_ini", }, --- Load configuration from a Lua file that exports a table. from_lua = function(filepath) local file, err = loadfile(filepath) if not file and err then return nil, err end return file() end, --- Load configuration from a JSON file. --- --- Requires the "dkjson"[1] module to be present on the system. Get it with: --- --- luarocks install dkjson --- --- [1] http://dkolf.de/src/dkjson-lua.fsl/home from_json = function(filepath) local src, config, _, err local json = require 'dkjson' src, err = read_file(filepath) if not src and err then return nil, err end config, _, err = json.decode(src) if err then return nil, err end return config end, --- Load configuration from an INI file. --- --- Requires the "inifile"[1] module to be present on the system. Get it with: --- --- luarocks install inifile --- --- The INI file must contain a group that lists the default values. For --- example: --- --- [cli] --- quiet = true --- compress = lzma --- --- The routine will automatically cast boolean values ("true" and "false") --- into Lua booleans. You may opt out of this behavior by passing `false` --- to `no_cast`. --- --- [1] http://docs.bartbes.com/inifile from_ini = function(filepath, group, no_cast) local inifile = require 'inifile' local config, err group = group or 'cli' assert(type(group) == 'string', 'You must provide an INI group to read from.' ) config, err = inifile.parse(filepath) if not config and err then return nil, err end if not no_cast then for k, src_value in pairs(config[group]) do local v = trim(src_value) if v == 'true' then v = true elseif v == 'false' then v = false end config[group][k] = v end end return config[group] end, --- Load configuration from a YAML file. --- --- Requires the "yaml"[1] module to be present on the system. Get it with: --- --- luarocks install yaml --- --- [1] http://doc.lubyk.org/yaml.html from_yaml = function(filepath) local src, config, _, err local yaml = require 'yaml' src, err = read_file(filepath) if not src and err then return nil, err end config, err = yaml.load(src) if not config and err then return nil, err end return config end } lua_cliargs-3.0-1/src/cliargs/constants.lua000066400000000000000000000001751264514405200207370ustar00rootroot00000000000000return { TYPE_COMMAND = 'command', TYPE_ARGUMENT = 'argument', TYPE_SPLAT = 'splat', TYPE_OPTION = 'option', } lua_cliargs-3.0-1/src/cliargs/core.lua000066400000000000000000000367241264514405200176640ustar00rootroot00000000000000-- luacheck: ignore 212 local _ local disect = require('cliargs.utils.disect') local lookup = require('cliargs.utils.lookup') local filter = require('cliargs.utils.filter') local shallow_copy = require('cliargs.utils.shallow_copy') local create_printer = require('cliargs.printer') local config_loader = require('cliargs.config_loader') local parser = require('cliargs.parser') local K = require 'cliargs.constants' local function is_callable(fn) return type(fn) == "function" or (getmetatable(fn) or {}).__call end local function cast_to_boolean(v) if v == nil then return v else return v and true or false end end -- -------- -- -- CLI Main -- -- -------- -- local function create_core() --- @module --- --- The primary export you receive when you require the library. For example: --- --- local cli = require 'cliargs' local cli = {} local colsz = { 0, 0 } -- column width, help text. Set to 0 for auto detect local options = {} cli.name = "" cli.description = "" cli.printer = create_printer(function() return { name = cli.name, description = cli.description, options = options, colsz = colsz } end) -- Used internally to add an option local function define_option(k, ek, v, label, desc, default, callback) local flag = (v == nil) -- no value, so it's a flag local negatable = flag and (ek and ek:find('^%[no%-]') ~= nil) if negatable then ek = ek:sub(6) end -- guard against duplicates if lookup(k, ek, options) then error("Duplicate option: " .. (k or ek) .. ", please rename one of them.") end if negatable and lookup(nil, "no-"..ek, options) then error("Duplicate option: " .. ("no-"..ek) .. ", please rename one of them.") end -- below description of full entry record, nils included for reference local entry = { type = K.TYPE_OPTION, key = k, expanded_key = ek, desc = desc, default = default, label = label, flag = flag, negatable = negatable, callback = callback } table.insert(options, entry) end local function define_command_option(key) --- @module --- --- This is a special instance of the [cli]() module that you receive when --- you define a new command using [cli#command](). local cmd = create_core() cmd.__key__ = key cmd.type = K.TYPE_COMMAND --- Specify a file that the command should run. The rest of the arguments --- are forward to that file to process, which is free to use or not use --- lua_cliargs in turn. --- --- @param {string} file_path --- Absolute file-path to a lua script to execute. function cmd:file(file_path) cmd.__file__ = file_path return cmd end --- Define a command handler. This callback will be invoked if the command --- argument was supplied by the user at runtime. What you return from this --- callback will be returned to the parent CLI library's parse routine and --- it will return that in turn! --- --- @param {function} callback function cmd:action(callback) cmd.__action__ = callback return cmd end return cmd end -- ------------------------------------------------------------------------ -- -- PUBLIC API -- ------------------------------------------------------------------------ -- --- CONFIG --- Assigns the name of the program which will be used for logging. function cli:set_name(in_name) cli.name = in_name return self end --- Write down a brief, 1-liner description of what the program does. function cli:set_description(in_description) cli.description = in_description return self end --- Sets the amount of space allocated to the argument keys and descriptions --- in the help listing. --- --- The sizes are used for wrapping long argument keys and descriptions. --- --- @param {number} [key_cols=0] --- The number of columns assigned to the argument keys, set to 0 to --- auto detect. --- --- @param {number} [desc_cols=0] --- The number of columns assigned to the argument descriptions, set to --- 0 to auto set the total width to 72. function cli:set_colsz(key_cols, desc_cols) colsz = { key_cols or colsz[1], desc_cols or colsz[2] } end function cli:redefine_default(key, new_default) local entry = lookup(key, key, options) if not entry then return nil end if entry.flag then new_default = cast_to_boolean(new_default) end entry.default = shallow_copy(new_default) return true end --- Load default values from a table. --- --- @param {table} config --- Your new set of defaults. The keys could either point to the short --- or expanded option keys, and their values are the new defaults. --- --- @param {boolean} [strict=false] --- Turn this on to return nil and an error message if a key in the --- config table could not be mapped to any CLI option. --- --- @return {true} --- When the new defaults were loaded successfully, or strict was not --- set. --- --- @return {union} --- When strict was set and there was an error. function cli:load_defaults(config, strict) for k, v in pairs(config) do local success = self:redefine_default(k, v) if strict and not success then return nil, "Unrecognized option with the key '" .. k .. "'" end end return true end --- Read config values from a configuration file. --- --- @param {string} path --- Absolute file path. --- --- @param {string} [format=nil] --- The config file format, which has to be one of: --- "lua", "json", "ini", or "yaml". --- When this is left blank, we try to auto-detect the format from the --- file extension. --- --- @param {boolean} [strict=false] --- Forwarded to [#load_defaults](). See that method for the parameter --- description. --- --- @return {true|union} --- Returns true on successful load. Otherwise, nil and an error --- message are returned instead. function cli:read_defaults(path, format) if not format then format = path:match('%.([^%.]+)$') end local loader = config_loader.FORMAT_LOADERS[format] if not loader then return nil, 'Unsupported file format "' .. format .. '"' end return config_loader[loader](path) end --- Define a required argument. --- --- --- Required arguments do not take a symbol like `-` or `--`, may not have a --- default value, and are parsed in the order they are defined. --- --- --- For example: --- --- ```lua --- cli:argument('INPUT', 'path to the input file') --- cli:argument('OUTPUT', 'path to the output file') --- ``` --- --- At run-time, the arguments have to be specified using the following --- notation: --- --- ```bash --- $ ./script.lua ./main.c ./a.out --- ``` --- --- If the user does not pass a value to _every_ argument, the parser will --- raise an error. --- --- @param {string} key --- --- The argument identifier that will be displayed to the user and --- be used to reference the run-time value. --- --- @param {string} desc --- --- A description for this argument to display in usage help. --- --- @param {function} [callback] --- Callback to invoke when this argument is parsed. function cli:argument(key, desc, callback) assert(type(key) == "string" and type(desc) == "string", "Key and description are mandatory arguments (Strings)" ) assert(callback == nil or is_callable(callback), "Callback argument must be a function" ) if lookup(key, key, options) then error("Duplicate argument: " .. key .. ", please rename one of them.") end table.insert(options, { type = K.TYPE_ARGUMENT, key = key, desc = desc, callback = callback }) return self end --- Defines a "splat" (or catch-all) argument. --- --- This is a special kind of argument that may be specified 0 or more times, --- the values being appended to a list. --- --- For example, let's assume our program takes a single output file and works --- on multiple source files: --- --- ```lua --- cli:argument('OUTPUT', 'path to the output file') --- cli:splat('INPUTS', 'the sources to compile', nil, 10) -- up to 10 source files --- ``` --- --- At run-time, it could be invoked as such: --- --- ```bash --- $ ./script.lua ./a.out file1.c file2.c main.c --- ``` --- --- If you want to make the output optional, you could do something like this: --- --- ```lua --- cli:option('-o, --output=FILE', 'path to the output file', './a.out') --- cli:splat('INPUTS', 'the sources to compile', nil, 10) --- ``` --- --- And now we may omit the output file path: --- --- ```bash --- $ ./script.lua file1.c file2.c main.c --- ``` --- --- @param {string} key --- The argument's "name" that will be displayed to the user. --- --- @param {string} desc --- A description of the argument. --- --- @param {*} [default=nil] --- A default value. --- --- @param {number} [maxcount=1] --- The maximum number of occurences allowed. --- --- @param {function} [callback] --- A function to call **everytime** a value for this argument is --- parsed. --- function cli:splat(key, desc, default, maxcount, callback) assert(#filter(options, 'type', K.TYPE_SPLAT) == 0, "Only one splat argument may be defined." ) assert(type(key) == "string" and type(desc) == "string", "Key and description are mandatory arguments (Strings)" ) assert(type(default) == "string" or default == nil, "Default value must either be omitted or be a string" ) maxcount = tonumber(maxcount or 1) assert(maxcount > 0 and maxcount < 1000, "Maxcount must be a number from 1 to 999" ) assert(is_callable(callback) or callback == nil, "Callback argument: expected a function or nil" ) local typed_default = default or {} if type(typed_default) ~= 'table' then typed_default = { typed_default } end table.insert(options, { type = K.TYPE_SPLAT, key = key, desc = desc, default = typed_default, maxcount = maxcount, callback = callback }) return self end --- Defines an optional argument. --- --- Optional arguments can use 3 different notations, and can accept a value. --- --- @param {string} key --- --- The argument identifier. This can either be `-key`, or --- `-key, --expanded-key`. --- Values can be specified either by appending a space after the --- identifier (e.g. `-key value` or `--expanded-key value`) or by --- separating them with a `=` (e.g. `-key=value` or --- `--expanded-key=value`). --- --- @param {string} desc --- --- A description for the argument to be shown in --help. --- --- @param {bool} [default=nil] --- --- A default value to use in case the option was not specified at --- run-time (the default value is nil if you leave this blank.) --- --- @param {function} [callback] --- --- A callback to invoke when this option is parsed. --- --- @example --- --- The following option will be stored in `args["i"]` and `args["input"]` --- with a default value of `file.txt`: --- --- cli:option("-i, --input=FILE", "path to the input file", "file.txt") function cli:option(key, desc, default, callback) assert(type(key) == "string" and type(desc) == "string", "Key and description are mandatory arguments (Strings)" ) assert(is_callable(callback) or callback == nil, "Callback argument: expected a function or nil" ) local k, ek, v = disect(key) -- if there's no VALUE indicator anywhere, what they want really is a flag. -- e.g: -- -- cli:option('-q, --quiet', '...') if v == nil then return self:flag(key, desc, default, callback) end define_option(k, ek, v, key, desc, default, callback) return self end --- Define an optional "flag" argument. --- --- Flags are a special subset of options that can either be `true` or `false`. --- --- For example: --- ```lua --- cli:flag('-q, --quiet', 'Suppress output.', true) --- ``` --- --- At run-time: --- --- ```bash --- $ ./script.lua --quiet --- $ ./script.lua -q --- ``` --- --- Passing a value to a flag raises an error: --- --- ```bash --- $ ./script.lua --quiet=foo --- $ echo $? # => 1 --- ``` --- --- Flags may be _negatable_ by prepending `[no-]` to their key: --- --- ```lua --- cli:flag('-c, --[no-]compress', 'whether to compress or not', true) --- ``` --- --- Now the user gets to pass `--no-compress` if they want to skip --- compression, or either specify `--compress` explicitly or leave it --- unspecified to use compression. --- --- @param {string} key --- @param {string} desc --- @param {*} default --- @param {function} callback function cli:flag(key, desc, default, callback) if type(default) == "function" then callback = default default = nil end assert(type(key) == "string" and type(desc) == "string", "Key and description are mandatory arguments (Strings)" ) local k, ek, v = disect(key) if v ~= nil then error("A flag type option cannot have a value set: " .. key) end define_option(k, ek, nil, key, desc, cast_to_boolean(default), callback) return self end --- Define a command argument. --- --- @param {string} name --- The name of the command and the argument that the user has to --- supply to invoke it. --- --- @param {string} [desc] --- An optional string to show in the help listing which should --- describe what the command does. It will be displayed if --help --- was run on the main program. --- --- --- @return {cmd} --- Another instance of the CLI library which is scoped to that --- command. function cli:command(name, desc) local cmd = define_command_option(name) cmd:set_name(cli.name .. ' ' .. name) cmd:set_description(desc) table.insert(options, cmd) return cmd end --- Parse the process arguments table. --- --- @param {table} [arguments=_G.arg] --- The list of arguments to parse. Defaults to the global `arg` table --- which contains the arguments the process was started with. --- --- @return {table} --- A table containing all the arguments, options, flags, --- and splat arguments that were specified or had a default --- (where applicable). --- --- @return {array} --- If a parsing error has occured, note that the --help option is --- also considered an error. function cli:parse(arguments) return parser(arguments, options, cli.printer) end --- Prints the USAGE message. --- --- @return {string} --- The USAGE message. function cli:print_usage() cli.printer.print(cli:get_usage_message()) end function cli:get_usage_message() return cli.printer.generate_usage() end --- Prints the HELP information. --- --- @return {string} --- The HELP message. function cli:print_help() cli.printer.print(cli.printer.generate_help_and_usage()) end return cli end return create_corelua_cliargs-3.0-1/src/cliargs/parser.lua000066400000000000000000000210131264514405200202110ustar00rootroot00000000000000local K = require 'cliargs.constants' ------------------------------------------------------------------------------- -- UTILS ------------------------------------------------------------------------------- local shallow_copy = require 'cliargs.utils.shallow_copy' local filter = require 'cliargs.utils.filter' local disect_argument = require 'cliargs.utils.disect_argument' local lookup = require 'cliargs.utils.lookup' local function clone_table_shift(t) local clone = shallow_copy(t) table.remove(clone, 1) return clone end local function clone_table_remove(t, index) local clone = shallow_copy(t) table.remove(clone, index) return clone end ------------------------------------------------------------------------------- -- PARSE ROUTINES ------------------------------------------------------------------------------- local p = {} function p.invoke_command(args, options, done) local commands = filter(options, 'type', K.TYPE_COMMAND) for index, opt in ipairs(args) do local command = filter(commands, '__key__', opt)[1] if command then local command_args = clone_table_remove(args, index) if command.__action__ then local parsed_command_args, err = command:parse(command_args) if err then return nil, err end return command.__action__(parsed_command_args) elseif command.__file__ then local filename = command.__file__ if type(filename) == 'function' then filename = filename() end local run_command_file = function() _G.arg = command_args local res, err = assert(loadfile(filename))() _G.arg = args return res, err end return run_command_file() end end end return done() end function p.print_help(args, printer, done) -- has --help or -h ? display the help listing and abort! for _, v in pairs(args) do if v == "--help" or v == "-h" then return nil, printer.generate_help_and_usage() end end return done() end function p.track_dump_request(args, done) -- starts with --__DUMP__; set dump to true to dump the parsed arguments if args[1] == "--__DUMP__" then return done(true, clone_table_shift(args)) else return done(false, args) end end function p.process_arguments(args, options, done) local values = {} local cursor = 0 local argument_cursor = 1 local argument_delimiter_found = false local function consume() cursor = cursor + 1 return args[cursor] end local required = filter(options, 'type', K.TYPE_ARGUMENT) while cursor < #args do local curr_opt = consume() local symbol, key, value, flag_negated = disect_argument(curr_opt) -- end-of-options indicator: if curr_opt == "--" then argument_delimiter_found = true -- an option: elseif not argument_delimiter_found and symbol then local entry = lookup(key, key, options) if not key or not entry then local option_type = value and "option" or "flag" return nil, "unknown/bad " .. option_type .. ": " .. curr_opt end if flag_negated and not entry.negatable then return nil, "flag '" .. curr_opt .. "' may not be negated using --no-" end -- a flag and a value specified? that's an error if entry.flag and value then return nil, "flag " .. curr_opt .. " does not take a value" elseif entry.flag then value = not flag_negated -- an option: else -- the value might be in the next argument, e.g: -- -- --compress lzma if not value then -- if the option contained a = and there's no value, it means they -- want to nullify an option's default value. eg: -- -- --compress= if curr_opt:find('=') then value = '__CLIARGS_NULL__' else -- NOTE: this has the potential to be buggy and swallow the next -- entry as this entry's value even though that entry may be an -- actual argument/option -- -- this would be a user error and there is no determinate way to -- figure it out because if there's no leading symbol (- or --) -- in that entry it can be an actual argument. :shrug: value = consume() if not value then return nil, "option " .. curr_opt .. " requires a value to be set" end end end end table.insert(values, { entry = entry, value = value }) if entry.callback then local altkey = entry.key local status, err if key == entry.key then altkey = entry.expanded_key else key = entry.expanded_key end status, err = entry.callback(key, value, altkey, curr_opt) if status == nil and err then return nil, err end end -- a regular argument: elseif argument_cursor <= #required then local entry = required[argument_cursor] table.insert(values, { entry = entry, value = curr_opt }) if entry.callback then local status, err = entry.callback(entry.key, curr_opt) if status == nil and err then return nil, err end end argument_cursor = argument_cursor + 1 -- a splat argument: else local entry = filter(options, 'type', K.TYPE_SPLAT)[1] if entry then table.insert(values, { entry = entry, value = curr_opt }) if entry.callback then local status, err = entry.callback(entry.key, curr_opt) if status == nil and err then return nil, err end end end argument_cursor = argument_cursor + 1 end end return done(values, argument_cursor - 1) end function p.validate(options, arg_count, done) local required = filter(options, 'type', K.TYPE_ARGUMENT) local splatarg = filter(options, 'type', K.TYPE_SPLAT)[1] or { maxcount = 0 } local min_arg_count = #required local max_arg_count = #required + splatarg.maxcount -- missing any required arguments, or too many? if arg_count < min_arg_count or arg_count > max_arg_count then if splatarg.maxcount > 0 then return nil, ( "bad number of arguments: " .. min_arg_count .. "-" .. max_arg_count .. " argument(s) must be specified, not " .. arg_count ) else return nil, ( "bad number of arguments: " .. min_arg_count .. " argument(s) must be specified, not " .. arg_count ) end end return done() end function p.collect_results(cli_values, options) local results = {} local function collect_with_default(entry) local entry_values = {} local _ for _, item in ipairs(cli_values) do if item.entry == entry then table.insert(entry_values, item.value) end end if #entry_values == 0 then return type(entry.default) == 'table' and entry.default or { entry.default } else return entry_values end end local function write(entry, value) if entry.key then results[entry.key] = value end if entry.expanded_key then results[entry.expanded_key] = value end end for _, entry in pairs(options) do local entry_cli_values = collect_with_default(entry) local maxcount = entry.maxcount if maxcount == nil then maxcount = type(entry.default) == 'table' and 999 or 1 end local entry_value = entry_cli_values if maxcount == 1 and type(entry_cli_values) == 'table' then -- take the last value entry_value = entry_cli_values[#entry_cli_values] if entry_value == '__CLIARGS_NULL__' then entry_value = nil end end write(entry, entry_value) end return results end return function(arguments, options, printer) assert(arguments == nil or type(arguments) == "table", "expected an argument table to be passed in, " .. "got something of type " .. type(arguments) ) local args = arguments or _G.arg or {} -- the spiral of DOOM: return p.invoke_command(args, options, function() return p.track_dump_request(args, function(dump, args_without_dump) return p.print_help(args_without_dump, printer, function() return p.process_arguments(args_without_dump, options, function(values, arg_count) return p.validate(options, arg_count, function() if dump then return nil, printer.dump_internal_state(values) else return p.collect_results(values, options) end end) end) end) end) end) end lua_cliargs-3.0-1/src/cliargs/printer.lua000066400000000000000000000160401264514405200204040ustar00rootroot00000000000000local wordwrap = require('cliargs.utils.wordwrap') local filter = require('cliargs.utils.filter') local K = require('cliargs.constants') local MAX_COLS = 72 local _ local function create_printer(get_parser_state) local printer = {} function printer.print(msg) return _G.print(msg) end local function get_max_label_length() local maxsz = 0 local state = get_parser_state() local optargument = filter(state.options, 'type', K.TYPE_SPLAT)[1] local commands = filter(state.options, 'type', K.TYPE_COMMAND) for _, entry in ipairs(commands) do if #entry.__key__ > maxsz then maxsz = #entry.__key__ end end for _,table_name in ipairs({"options"}) do for _, entry in ipairs(state[table_name]) do local key = entry.label or entry.key or entry.__key__ if #key > maxsz then maxsz = #key end end end if optargument and #optargument.key > maxsz then maxsz = #optargument.key end return maxsz end -- Generate the USAGE heading message. function printer.generate_usage() local state = get_parser_state() local msg = "Usage:" local required = filter(state.options, 'type', K.TYPE_ARGUMENT) local optional = filter(state.options, 'type', K.TYPE_OPTION) local optargument = filter(state.options, 'type', K.TYPE_SPLAT)[1] if #state.name > 0 then msg = msg .. ' ' .. tostring(state.name) end if #optional > 0 then msg = msg .. " [OPTIONS]" end if #required > 0 or optargument then msg = msg .. " [--]" end if #required > 0 then for _,entry in ipairs(required) do msg = msg .. " " .. entry.key end end if optargument then if optargument.maxcount == 1 then msg = msg .. " [" .. optargument.key .. "]" elseif optargument.maxcount == 2 then msg = msg .. " [" .. optargument.key .. "-1 [" .. optargument.key .. "-2]]" elseif optargument.maxcount > 2 then msg = msg .. " [" .. optargument.key .. "-1 [" .. optargument.key .. "-2 [...]]]" end end return msg end function printer.generate_help() local msg = '' local state = get_parser_state() local col1 = state.colsz[1] local col2 = state.colsz[2] local required = filter(state.options, 'type', K.TYPE_ARGUMENT) local optional = filter(state.options, 'type', K.TYPE_OPTION) local commands = filter(state.options, 'type', K.TYPE_COMMAND) local optargument = filter(state.options, 'type', K.TYPE_SPLAT)[1] local function append(label, desc) label = " " .. label .. string.rep(" ", col1 - (#label + 2)) desc = wordwrap(desc, col2) -- word-wrap desc = desc:gsub("\n", "\n" .. string.rep(" ", col1)) -- add padding msg = msg .. label .. desc .. "\n" end if col1 == 0 then col1 = get_max_label_length(state) end -- add margins col1 = col1 + 3 if col2 == 0 then col2 = MAX_COLS - col1 end if col2 < 10 then col2 = 10 end if #commands > 0 then msg = msg .. "\nCOMMANDS: \n" for _, entry in ipairs(commands) do append(entry.__key__, entry.description or '') end end if required[1] or optargument then msg = msg .. "\nARGUMENTS: \n" for _,entry in ipairs(required) do append(entry.key, entry.desc .. " (required)") end end if optargument then local optarg_desc = ' ' .. optargument.desc local default_value = optargument.maxcount > 1 and optargument.default[1] or optargument.default if #optargument.default > 0 then optarg_desc = optarg_desc .. " (optional, default: " .. tostring(default_value[1]) .. ")" else optarg_desc = optarg_desc .. " (optional)" end append(optargument.key, optarg_desc) end if #optional > 0 then msg = msg .. "\nOPTIONS: \n" for _,entry in ipairs(optional) do local desc = entry.desc if not entry.flag and entry.default and #tostring(entry.default) > 0 then local readable_default = type(entry.default) == "table" and "[]" or tostring(entry.default) desc = desc .. " (default: " .. readable_default .. ")" elseif entry.flag and entry.negatable then local readable_default = entry.default and 'on' or 'off' desc = desc .. " (default: " .. readable_default .. ")" end append(entry.label, desc) end end return msg end function printer.dump_internal_state(values) local state = get_parser_state() local required = filter(state.options, 'type', K.TYPE_ARGUMENT) local optional = filter(state.options, 'type', K.TYPE_OPTION) local optargument = filter(state.options, 'type', K.TYPE_SPLAT)[1] local maxlabel = get_max_label_length() local msg = '' local function print(fragment) msg = msg .. fragment .. '\n' end print("\n======= Provided command line =============") print("\nNumber of arguments: ", #arg) for i,v in ipairs(arg) do -- use gloabl 'arg' not the modified local 'args' print(string.format("%3i = '%s'", i, v)) end print("\n======= Parsed command line ===============") if #required > 0 then print("\nArguments:") end for _, entry in ipairs(required) do print( " " .. entry.key .. string.rep(" ", maxlabel + 2 - #entry.key) .. " => '" .. tostring(values[entry]) .. "'" ) end if optargument then print( "\nOptional arguments:" .. optargument.key .. "; allowed are " .. tostring(optargument.maxcount) .. " arguments" ) if optargument.maxcount == 1 then print( " " .. optargument.key .. string.rep(" ", maxlabel + 2 - #optargument.key) .. " => '" .. optargument.key .. "'" ) else for i = 1, optargument.maxcount do if values[optargument] and values[optargument][i] then print( " " .. tostring(i) .. string.rep(" ", maxlabel + 2 - #tostring(i)) .. " => '" .. tostring(values[optargument][i]) .. "'" ) end end end end if #optional > 0 then print("\nOptional parameters:") end local doubles = {} for _, entry in pairs(optional) do if not doubles[entry] then local value = values[entry] if type(value) == "string" then value = "'"..value.."'" else value = tostring(value) .." (" .. type(value) .. ")" end print(" " .. entry.label .. string.rep(" ", maxlabel + 2 - #entry.label) .. " => " .. value) doubles[entry] = entry end end print("\n===========================================\n\n") return msg end function printer.generate_help_and_usage() local msg = '' msg = msg .. printer.generate_usage() .. '\n' msg = msg .. printer.generate_help() return msg end return printer end return create_printerlua_cliargs-3.0-1/src/cliargs/utils/000077500000000000000000000000001264514405200173555ustar00rootroot00000000000000lua_cliargs-3.0-1/src/cliargs/utils/disect.lua000066400000000000000000000030421264514405200213320ustar00rootroot00000000000000local split = require('cliargs.utils.split') local RE_ADD_COMMA = "^%-([%a%d]+)[%s]%-%-" local RE_ADJUST_DELIMITER = "(%-%-?)([%a%d]+)[%s]" -- parameterize the key if needed, possible variations: -- -- -key -- -key VALUE -- -key=VALUE -- -- -key, --expanded -- -key, --expanded VALUE -- -key, --expanded=VALUE -- -- -key --expanded -- -key --expanded VALUE -- -key --expanded=VALUE -- -- --expanded -- --expanded VALUE -- --expanded=VALUE local function disect(key) -- characters allowed are a-z, A-Z, 0-9 -- extended + values also allow; # @ _ + - local k, ek, v, _ local dummy -- leading "-" or "--" local prefix -- if there is no comma, between short and extended, add one _, _, dummy = key:find(RE_ADD_COMMA) if dummy then key = key:gsub(RE_ADD_COMMA, "-" .. dummy .. ", --", 1) end -- replace space delimiting the value indicator by "=" -- -- -key VALUE => -key=VALUE -- --expanded-key VALUE => --expanded-key=VALUE _, _, prefix, dummy = key:find(RE_ADJUST_DELIMITER) if prefix and dummy then key = key:gsub(RE_ADJUST_DELIMITER, prefix .. dummy .. "=", 1) end -- if there is no "=", then append one if not key:find("=") then key = key .. "=" end -- get value _, _, v = key:find(".-%=(.+)") -- get key(s), remove spaces key = split(key, "=")[1]:gsub(" ", "") -- get short key & extended key _, _, k = key:find("^%-([^-][^%s,]*)") _, _, ek = key:find("%-%-(.+)$") if v == "" then v = nil end return k,ek,v end return disectlua_cliargs-3.0-1/src/cliargs/utils/disect_argument.lua000066400000000000000000000013071264514405200232360ustar00rootroot00000000000000local function disect_argument(str) local _, symbol, key, value local negated = false _, _, symbol, key = str:find("^([%-]*)(.*)") if key then local actual_key -- split value and key _, _, actual_key, value = key:find("([^%=]+)[%=]?(.*)") if value then key = actual_key end if key:sub(1,3) == "no-" then key = key:sub(4,-1) negated = true end end -- no leading symbol means the sole fragment is the value. if #symbol == 0 then value = str key = nil end return #symbol > 0 and symbol or nil, key and #key > 0 and key or nil, value and #value > 0 and value or nil, negated and true or false end return disect_argumentlua_cliargs-3.0-1/src/cliargs/utils/filter.lua000066400000000000000000000002371264514405200213470ustar00rootroot00000000000000return function(t, k, v) local out = {} for _, item in ipairs(t) do if item[k] == v then table.insert(out, item) end end return out endlua_cliargs-3.0-1/src/cliargs/utils/lookup.lua000066400000000000000000000007561264514405200214010ustar00rootroot00000000000000 -- Used internally to lookup an entry using either its short or expanded keys local function lookup(k, ek, ...) local _ for _, t in ipairs({...}) do for _, entry in ipairs(t) do if k and entry.key == k then return entry end if ek and entry.expanded_key == ek then return entry end if entry.negatable then if ek and ("no-"..entry.expanded_key) == ek then return entry end end end end return nil end return lookuplua_cliargs-3.0-1/src/cliargs/utils/shallow_copy.lua000066400000000000000000000005111264514405200225600ustar00rootroot00000000000000-- courtesy of http://lua-users.org/wiki/CopyTable local function shallow_copy(orig) if type(orig) == 'table' then local copy = {} for orig_key, orig_value in pairs(orig) do copy[orig_key] = orig_value end return copy else -- number, string, boolean, etc return orig end end return shallow_copylua_cliargs-3.0-1/src/cliargs/utils/split.lua000066400000000000000000000006171264514405200212170ustar00rootroot00000000000000local function split(str, pat) local t = {} local fpat = "(.-)" .. pat local last_end = 1 local s, e, cap = str:find(fpat, 1) while s do if s ~= 1 or cap ~= "" then table.insert(t,cap) end last_end = e + 1 s, e, cap = str:find(fpat, last_end) end if last_end <= #str then cap = str:sub(last_end) table.insert(t, cap) end return t end return splitlua_cliargs-3.0-1/src/cliargs/utils/trim.lua000066400000000000000000000001721264514405200210330ustar00rootroot00000000000000-- courtesy of the jungle: http://lua-users.org/wiki/StringTrim return function(str) return str:match "^%s*(.-)%s*$" endlua_cliargs-3.0-1/src/cliargs/utils/wordwrap.lua000066400000000000000000000023701264514405200217270ustar00rootroot00000000000000local split = require('cliargs.utils.split') local function buildline(words, size, overflow) -- if overflow is set, a word longer than size, will overflow the size -- otherwise it will be chopped in line-length pieces local line = "" if string.len(words[1]) > size then -- word longer than line if overflow then line = words[1] table.remove(words, 1) else line = words[1]:sub(1, size) words[1] = words[1]:sub(size + 1, -1) end else while words[1] and (#line + string.len(words[1]) + 1 <= size) or (line == "" and #words[1] == size) do if line == "" then line = words[1] else line = line .. " " .. words[1] end table.remove(words, 1) end end return line, words end local function wordwrap(str, size, pad, overflow) -- if overflow is set, then words longer than a line will overflow -- otherwise, they'll be chopped in pieces pad = pad or 0 local line local out = "" local padstr = string.rep(" ", pad) local words = split(str, ' ') while words[1] do line, words = buildline(words, size, overflow) if out == "" then out = padstr .. line else out = out .. "\n" .. padstr .. line end end return out end return wordwrap