gli-2.14.0/ 0000755 0001750 0001750 00000000000 13017317740 011300 5 ustar micah micah gli-2.14.0/.ruby-version 0000644 0001750 0001750 00000000006 13017317740 013741 0 ustar micah micah 2.2.2
gli-2.14.0/lib/ 0000755 0001750 0001750 00000000000 13017317740 012046 5 ustar micah micah gli-2.14.0/lib/gli/ 0000755 0001750 0001750 00000000000 13017317740 012621 5 ustar micah micah gli-2.14.0/lib/gli/argument.rb 0000644 0001750 0001750 00000000464 13017317740 014774 0 ustar micah micah module GLI
class Argument #:nodoc:
attr_reader :name
attr_reader :options
def initialize(name,options = [])
@name = name
@options = options
end
def optional?
@options.include? :optional
end
def multiple?
@options.include? :multiple
end
end
end
gli-2.14.0/lib/gli/command_line_token.rb 0000644 0001750 0001750 00000003504 13017317740 016775 0 ustar micah micah module GLI
# Abstract base class for a logical element of a command line, mostly so that subclasses can have similar
# initialization and interface
class CommandLineToken
attr_reader :name #:nodoc:
attr_reader :aliases #:nodoc:
attr_reader :description #:nodoc:
attr_reader :long_description #:nodoc:
def initialize(names,description,long_description=nil) #:nodoc:
@description = description
@long_description = long_description
@name,@aliases,@names = parse_names(names)
end
# Sort based on primary name
def <=>(other)
self.name.to_s <=> other.name.to_s
end
# Array of the name and aliases, as string
def names_and_aliases
[self.name,self.aliases].flatten.compact.map(&:to_s)
end
private
# Returns a string of all possible forms
# of this flag. Mostly intended for printing
# to the user.
def all_forms(joiner=', ')
forms = all_forms_a
forms.join(joiner)
end
# Handles dealing with the "names" param, parsing
# it into the primary name and aliases list
def parse_names(names)
# Allow strings; convert to symbols
names = [names].flatten.map { |name| name.to_sym }
names_hash = {}
names.each do |name|
raise ArgumentError.new("#{name} has spaces; they are not allowed") if name.to_s =~ /\s/
names_hash[self.class.name_as_string(name)] = true
end
name = names.shift
aliases = names.length > 0 ? names : nil
[name,aliases,names_hash]
end
def negatable?
false;
end
def all_forms_a
forms = [self.class.name_as_string(name,negatable?)]
if aliases
forms |= aliases.map { |one_alias| self.class.name_as_string(one_alias,negatable?) }.sort { |one,two| one.length <=> two.length }
end
forms
end
end
end
gli-2.14.0/lib/gli/app.rb 0000644 0001750 0001750 00000032664 13017317740 013741 0 ustar micah micah require 'etc'
require 'optparse'
require 'gli/dsl'
require 'pathname'
module GLI
# A means to define and parse a command line interface that works as
# Git's does, in that you specify global options, a command name, command
# specific options, and then command arguments.
module App
include DSL
include AppSupport
# Loads ruby files in the load path that start with
# +path+, which are presumed to be commands for your executable.
# This is useful for decomposing your bin file into different classes, but
# can also be used as a plugin mechanism, allowing users to provide additional
# commands for your app at runtime. All that being said, it's basically
# a glorified +require+.
#
# path:: a path from which to load .rb
files that, presumably, contain commands. If this is an absolute path,
# any files in that path are loaded. If not, it is interpretted as relative to somewhere
# in the LOAD_PATH
.
#
# == Example:
#
# # loads *.rb from your app's install - great for decomposing your bin file
# commands_from "my_app/commands"
#
# # loads *.rb files from the user's home dir - great and an extension/plugin mechanism
# commands_from File.join(ENV["HOME"],".my_app","plugins")
def commands_from(path)
if Pathname.new(path).absolute? and File.exist?(path)
load_commands(path)
else
$LOAD_PATH.each do |load_path|
commands_path = File.join(load_path,path)
load_commands(commands_path)
end
end
end
# Describe the overall application/programm. This should be a one-sentence summary
# of what your program does that will appear in the help output.
#
# +description+:: A String of the short description of your program's purpose
def program_desc(description=nil)
if description
@program_desc = description
end
@program_desc
end
# Provide a longer description of the program. This can be as long as needed, and use double-newlines
# for paragraphs. This will show up in the help output.
#
# description:: A String for the description
def program_long_desc(description=nil)
if description
@program_long_desc = description
end
@program_long_desc
end
# Provide a flag to choose whether to hide or not from the help the undescribed commands.
# By default the undescribed commands will be shown in the help.
#
# hide:: A Bool for hide the undescribed commands
def hide_commands_without_desc(hide=nil)
unless hide.nil?
@hide_commands_without_desc = hide
end
@hide_commands_without_desc || false
end
# Use this if the following command should not have the pre block executed.
# By default, the pre block is executed before each command and can result in
# aborting the call. Using this will avoid that behavior for the following command
def skips_pre
@skips_pre = true
end
# Use this if the following command should not have the post block executed.
# By default, the post block is executed after each command.
# Using this will avoid that behavior for the following command
def skips_post
@skips_post = true
end
# Use this if the following command should not have the around block executed.
# By default, the around block is executed, but for commands that might not want the
# setup to happen, this can be handy
def skips_around
@skips_around = true
end
# Sets that this app uses a config file as well as the name of the config file.
#
# +filename+:: A String representing the path to the file to use for the config file. If it's an absolute
# path, this is treated as the path to the file. If it's *not*, it's treated as relative to the user's home
# directory as produced by File.expand_path('~')
.
def config_file(filename)
if filename =~ /^\//
@config_file = filename
else
@config_file = File.join(File.expand_path(ENV['HOME']),filename)
end
commands[:initconfig] = InitConfig.new(@config_file,commands,flags,switches)
@commands_declaration_order << commands[:initconfig]
@config_file
end
# Define a block to run after command line arguments are parsed
# but before any command is run. If this block raises an exception
# the command specified will not be executed.
# The block will receive the global-options,command,options, and arguments
# If this block evaluates to true, the program will proceed; otherwise
# the program will end immediately and exit nonzero
def pre(&a_proc)
@pre_block = a_proc
end
# Define a block to run after the command was executed, only
# if there was not an error.
# The block will receive the global-options,command,options, and arguments
def post(&a_proc)
@post_block = a_proc
end
# This inverts the pre/post concept. This is useful when you have a global shared resource that is governed by a block
# instead of separate open/close methods. The block you pass here will be given four parameters:
#
# global options:: the parsed global options
# command:: The GLI::Command that the user is going to invoke
# options:: the command specific options
# args:: unparsed command-line args
# code:: a block that you must +call+ to execute the command.
#
# #help_now! and #exit_now! work as expected; you can abort the command call by simply not calling it.
#
# You can declare as many #around blocks as you want. They will be called in the order in which they are defined.
#
# Note that if you declare #around blocks, #pre and #post blocks will still work. The #pre is called first, followed by
# the around, followed by the #post.
#
# Call #skips_around before a command that should not have this hook fired
def around(&a_proc)
@around_blocks ||= []
@around_blocks << a_proc
end
# Define a block to run if an error occurs.
# The block will receive any Exception that was caught.
# It should evaluate to false to avoid the built-in error handling (which basically just
# prints out a message). GLI uses a variety of exceptions that you can use to find out what
# errors might've occurred during command-line parsing:
# * GLI::CustomExit
# * GLI::UnknownCommandArgument
# * GLI::UnknownGlobalArgument
# * GLI::UnknownCommand
# * GLI::BadCommandLine
def on_error(&a_proc)
@error_block = a_proc
end
# Indicate the version of your application
#
# +version+:: String containing the version of your application.
def version(version)
@version = version
desc 'Display the program version'
switch :version, :negatable => false
end
# By default, GLI mutates the argument passed to it. This is
# consistent with +OptionParser+, but be less than ideal. Since
# that value, for scaffolded apps, is +ARGV+, you might want to
# refer to the entire command-line via +ARGV+ and thus not want it mutated.
def preserve_argv(preserve=true)
@preserve_argv = preserve
end
# Call this with +true+ will cause the +global_options+ and
# +options+ passed to your code to be wrapped in
# Options, which is a subclass of +OpenStruct+ that adds
# [] and []= methods.
#
# +use_openstruct+:: a Boolean indicating if we should use OpenStruct instead of Hashes
def use_openstruct(use_openstruct)
@use_openstruct = use_openstruct
end
# Configure a type conversion not already provided by the underlying OptionParser.
# This works more or less like the OptionParser version. It's global.
#
# object:: the class (or whatever) that triggers the type conversion
# block:: the block that will be given the string argument and is expected
# to return the converted value
#
# Example
#
# accept(Hash) do |value|
# result = {}
# value.split(/,/).each do |pair|
# k,v = pair.split(/:/)
# result[k] = v
# end
# result
# end
#
# flag :properties, :type => Hash
def accept(object,&block)
accepts[object] = block
end
# Simpler means of exiting with a custom exit code. This will
# raise a CustomExit with the given message and exit code, which will ultimatley
# cause your application to exit with the given exit_code as its exit status
# Use #help_now! if you want to show the help in addition to the error message
#
# message:: message to show the user
# exit_code:: exit code to exit as, defaults to 1
def exit_now!(message,exit_code=1)
raise CustomExit.new(message,exit_code)
end
# Exit now, showing the user help for the command they executed. Use #exit_now! to just show the error message
#
# message:: message to indicate how the user has messed up the CLI invocation or nil to just simply show help
def help_now!(message=nil)
exception = OptionParser::ParseError.new(message)
class << exception
def exit_code; 64; end
end
raise exception
end
# Control how commands and options are sorted in help output. By default, they are sorted alphabetically.
#
# sort_type:: How you want help commands/options sorted:
# +:manually+:: help commands/options are ordered in the order declared.
# +:alpha+:: sort alphabetically (default)
def sort_help(sort_type)
@help_sort_type = sort_type
end
# Set how help text is wrapped.
#
# wrap_type:: Symbol indicating how you'd like text wrapped:
# +:to_terminal+:: Wrap text based on the width of the terminal (default)
# +:verbatim+:: Format text exactly as it was given to the various methods. This is useful if your output has
# formatted output, e.g. ascii tables and you don't want it messed with.
# +:one_line+:: Do not wrap text at all. This will bring all help content onto one line, removing any newlines
# +:tty_only+:: Wrap like +:to_terminal+ if this output is going to a TTY, otherwise don't wrap (like +:one_line+)
def wrap_help_text(wrap_type)
@help_text_wrap_type = wrap_type
end
# Control how the SYNOPSIS is formatted.
#
# format:: one of:
# +:full+:: the default, show subcommand options and flags inline
# +:terminal+:: if :full would be wider than the terminal, use :compact
# +:compact+:: use a simpler and shorter SYNOPSIS. Useful if your app has a lot of options and showing them in the SYNOPSIS makes things more confusing
def synopsis_format(format)
@synopsis_format_type = format
end
def program_name(override=nil) #:nodoc:
warn "#program_name has been deprecated"
end
# Sets a default command to run when none is specified on the command line. Note that
# if you use this, you won't be able to pass arguments, flags, or switches
# to the command when run in default mode. All flags and switches are treated
# as global, and any argument will be interpretted as the command name and likely
# fail.
#
# +command+:: Command as a Symbol to run as default
def default_command(command)
@default_command = command.to_sym
end
# How to handle subcommand options. In general, you want to set this to +:normal+, which
# treats each subcommand as establishing its own namespace for options. This is what
# the scaffolding should generate, but it is *not* what GLI 2.5.x and lower apps had as a default.
# To maintain backwards compatibility, the default is +:legacy+, which is that all subcommands of
# a particular command share a namespace for options, making it impossible for two subcommands
# to have options of the same name.
def subcommand_option_handling(handling_strategy)
@subcommand_option_handling_strategy = handling_strategy
end
# How to handle argument validation.
#
# handling_strategy:: One of:
# +:loose+:: no argument validation. Use of `arg` or `arg_name` is for documentation purposes only. (Default)
# +:strict+:: arguments are validated according to their specification. +action+ blocks may assume
# the value of `arguments` matches the specification provided in `arg`. Note that to use
# this strategy, you must also be sure that +subcommand_option_handling+ is set.
def arguments(handling_strategy)
@argument_handling_strategy = handling_strategy
end
# Enables/Disables command autocomplete, where partially spelled commands are automatically expanded to their full form
#
# Example:
# When enabled, executing 'shake' would execute 'shake_hand' (if no 'shake' command is defined).
# When disabled, executing 'shake' would throw an UnknownCommand error
#
# +boolean+:: Boolean value to enable or disable autocomplete, respectively. True by default.
def autocomplete_commands(boolean)
@autocomplete = boolean
end
private
def load_commands(path)
if File.exist? path
Dir.entries(path).sort.each do |entry|
file = File.join(path,entry)
if file =~ /\.rb$/
require file
end
end
end
end
end
end
gli-2.14.0/lib/gli/version.rb 0000644 0001750 0001750 00000000115 13017317740 014630 0 ustar micah micah module GLI
unless const_defined? :VERSION
VERSION = '2.14.0'
end
end
gli-2.14.0/lib/gli/option_parser_factory.rb 0000644 0001750 0001750 00000005147 13017317740 017570 0 ustar micah micah module GLI
# Factory for creating an OptionParser based on app configuration and DSL calls
class OptionParserFactory
# Create an option parser factory for a command. This has the added
# feature of setting up -h and --help on the command if those
# options aren't otherwise configured, e.g. to allow todo add --help as an
# alternate to todo help add
def self.for_command(command,accepts)
self.new(command.flags,command.switches,accepts).tap { |factory|
add_help_switches_to_command(factory.option_parser,command)
}
end
# Create an OptionParserFactory for the given
# flags, switches, and accepts
def initialize(flags,switches,accepts)
@flags = flags
@switches = switches
@options_hash = {}
@option_parser = OptionParser.new do |opts|
self.class.setup_accepts(opts,accepts)
self.class.setup_options(opts,@switches,@options_hash)
self.class.setup_options(opts,@flags,@options_hash)
end
end
attr_reader :option_parser
attr_reader :options_hash
def options_hash_with_defaults_set!
set_defaults(@flags,@options_hash)
set_defaults(@switches,@options_hash)
@options_hash
end
private
def set_defaults(options_by_name,options_hash)
options_by_name.values.each do |option|
option.names_and_aliases.each do |option_name|
[option_name,option_name.to_sym].each do |name|
options_hash[name] = option.default_value if options_hash[name].nil?
end
end
end
end
def self.setup_accepts(opts,accepts)
accepts.each do |object,block|
opts.accept(object) do |arg_as_string|
block.call(arg_as_string)
end
end
end
def self.setup_options(opts,tokens,options)
tokens.each do |ignore,token|
opts.on(*token.arguments_for_option_parser) do |arg|
token.names_and_aliases.each do |name|
if token.kind_of?(Flag) && token.multiple?
options[name] ||= []
options[name.to_sym] ||= []
options[name] << arg
options[name.to_sym] << arg
else
options[name] = arg
options[name.to_sym] = arg
end
end
end
end
end
def self.add_help_switches_to_command(option_parser,command)
help_args = %w(-h --help).reject { |_| command.has_option?(_) }
unless help_args.empty?
help_args << "Get help for #{command.name}"
option_parser.on(*help_args) do
raise RequestHelp.new(command)
end
end
end
end
end
gli-2.14.0/lib/gli/command.rb 0000644 0001750 0001750 00000015433 13017317740 014572 0 ustar micah micah require 'gli/command_line_token.rb'
require 'gli/dsl.rb'
module GLI
# A command to be run, in context of global flags and switches. You are given an instance of this class
# to the block you use for GLI::DSL#command. This class mixes in GLI::DSL so all of those methods are available
# to describe the command, in addition to the methods documented here, most importantly
# #action.
#
# Example:
#
# command :list do |c| # <- c is an instance of GLI::Command
# c.desc 'use long form'
# c.switch :l
#
# c.action do |global,options,args|
# # list things here
# end
#
# c.command :tasks do |t| # <- t is an instance of GLI::Command
# # this is a "subcommand" of list
#
# t.action do |global,options,args|
# # do whatever list tasks should do
# end
# end
# end
#
class Command < CommandLineToken
include DSL
include CommandSupport
# Key in an options hash to find the parent's parsed options
PARENT = Object.new
# Create a new command.
#
# options:: Keys should be:
# +names+:: A String, Symbol, or Array of String or Symbol that represents the name(s) of this command (required).
# +description+:: short description of this command as a String
# +arguments_name+:: description of the arguments as a String, or nil if this command doesn't take arguments
# +long_desc+:: a longer description of the command, possibly with multiple lines. A double line-break is treated
# as a paragraph break. No other formatting is respected, though inner whitespace is maintained.
# +skips_pre+:: if true, this command advertises that it doesn't want the pre block called first
# +skips_post+:: if true, this command advertises that it doesn't want the post block called after it
# +skips_around+:: if true, this command advertises that it doesn't want the around block called
# +hide_commands_without_desc+:: if true and there isn't a description the command is not going to be shown in the help
def initialize(options)
super(options[:names],options[:description],options[:long_desc])
@arguments_description = options[:arguments_name] || ''
@arguments_options = Array(options[:arguments_options]).flatten
@arguments = options[:arguments] || []
@skips_pre = options[:skips_pre]
@skips_post = options[:skips_post]
@skips_around = options[:skips_around]
@hide_commands_without_desc = options[:hide_commands_without_desc]
@commands_declaration_order = []
@flags_declaration_order = []
@switches_declaration_order = []
clear_nexts
end
# Set the default command if this command has subcommands and the user doesn't
# provide a subcommand when invoking THIS command. When nil, this will show an error and the help
# for this command; when set, the command with this name will be executed.
#
# +command_name+:: The primary name of the subcommand of this command that should be run by default as a String or Symbol.
def default_command(command_name)
@default_command = command_name
end
# Define the action to take when the user executes this command. Every command should either define this
# action block, or have subcommands (or both).
#
# +block+:: A block of code to execute. The block will be given 3 arguments:
# +global_options+:: A Hash of the _global_ options specified
# by the user, with defaults set and config file values used (if using a config file, see
# GLI::App#config_file)
# +options+:: A Hash of the command-specific options specified by the
# user, with defaults set and config file values used (if using a config file, see
# GLI::App#config_file).
# +arguments+:: An Array of Strings representing the unparsed command line arguments
# The block's result value is not used; raise an exception or use GLI#exit_now! if you need an early exit based
# on an error condition
#
def action(&block)
@action = block
end
# Describes this commands action block when it *also* has subcommands.
# In this case, the GLI::DSL#desc value is the general description of the commands
# that this command groups, and the value for *this* method documents what
# will happen if you omit a subcommand.
#
# Note that if you omit the action block and specify a subcommand, that subcommand's
# description will be used to describe what happens by default.
#
# desc:: the description of what this command's action block does.
#
# Example
#
# desc 'list things'
# command :list do |c|
#
# c.desc 'list tasks'
# c.command :tasks do |t|
# t.action do |global,options,args|
# end
# end
#
# c.desc 'list contexts'
# c.command :contexts do |t|
# t.action do |global,options,args|
# end
# end
#
# c.default_desc 'list both tasks and contexts'
# c.action do |global,options,args|
# # list everything
# end
# end
#
#
# > todo help list
# NAME
# list - List things
#
# SYNOPSIS
# todo [global options] list [command options]
# todo [global options] list [command options] tasks
# todo [global options] list [command options] contexts
#
# COMMANDS
# - list both tasks and contexts
# tasks - list tasks
# contexts - list contexts
#
def default_desc(desc)
@default_desc = desc
end
# Returns true if this command has the given option defined
def has_option?(option) #:nodoc:
option = option.gsub(/^\-+/,'')
((flags.values.map { |_| [_.name,_.aliases] }) +
(switches.values.map { |_| [_.name,_.aliases] })).flatten.map(&:to_s).include?(option)
end
# Returns full name for help command including parents
#
# Example
#
# command :remote do |t|
# t.command :add do |global,options,args|
# end
# end
#
# @add_command.name_for_help # => ["remote", "add"]
#
def name_for_help
name_array = [name.to_s]
command_parent = parent
while(command_parent.is_a?(GLI::Command)) do
name_array.unshift(command_parent.name.to_s)
command_parent = command_parent.parent
end
name_array
end
def self.name_as_string(name,negatable=false) #:nodoc:
name.to_s
end
end
end
gli-2.14.0/lib/gli/flag.rb 0000644 0001750 0001750 00000006060 13017317740 014061 0 ustar micah micah require 'gli/command_line_option.rb'
module GLI
# Defines a flag, which is to say a switch that takes an argument
class Flag < CommandLineOption # :nodoc:
# Regexp that is used to see if the flag's argument matches
attr_reader :must_match
# Type to which we want to cast the values
attr_reader :type
# Name of the argument that user configured
attr_reader :argument_name
# Creates a new option
#
# names:: Array of symbols or strings representing the names of this switch
# options:: hash of options:
# :desc:: the short description
# :long_desc:: the long description
# :default_value:: the default value of this option
# :arg_name:: the name of the flag's argument, default is "arg"
# :must_match:: a regexp that the flag's value must match
# :type:: a class to convert the value to
# :required:: if true, this flag must be specified on the command line
# :multiple:: if true, flag may be used multiple times and values are stored in an array
# :mask:: if true, the default value of this flag will not be output in the help.
# This is useful for password flags where you might not want to show it
# on the command-line.
def initialize(names,options)
super(names,options)
@argument_name = options[:arg_name] || "arg"
@must_match = options[:must_match]
@type = options[:type]
@mask = options[:mask]
@required = options[:required]
@multiple = options[:multiple]
end
# True if this flag is required on the command line
def required?
@required
end
# True if the flag may be used multiple times.
def multiple?
@multiple
end
def safe_default_value
if @mask
"********"
else
# This uses @default_value instead of the `default_value` method because
# this method is only used for display, and for flags that may be passed
# multiple times, we want to display whatever is set in the code as the
# the default, or the string "none" rather than displaying an empty
# array.
@default_value
end
end
# The default value for this flag. Uses the value passed if one is set;
# otherwise uses `[]` if the flag support multiple arguments and `nil` if
# it does not.
def default_value
if @default_value
@default_value
elsif @multiple
[]
end
end
def arguments_for_option_parser
args = all_forms_a.map { |name| "#{name} VAL" }
args << @must_match if @must_match
args << @type if @type
args
end
# Returns a string of all possible forms
# of this flag. Mostly intended for printing
# to the user.
def all_forms(joiner=', ')
forms = all_forms_a
string = forms.join(joiner)
if forms[-1] =~ /^\-\-/
string += '='
else
string += ' '
end
string += @argument_name
return string
end
end
end
gli-2.14.0/lib/gli/exceptions.rb 0000644 0001750 0001750 00000005637 13017317740 015342 0 ustar micah micah module GLI
# Mixed into all exceptions that GLI handles; you can use this to catch
# anything that came from GLI intentionally. You can also mix this into non-GLI
# exceptions to get GLI's exit behavior.
module StandardException
def exit_code; 1; end
end
# Hack to request help from within a command
# Will *not* be rethrown when GLI_DEBUG is ON
class RequestHelp < StandardError
include StandardException
def exit_code; 0; end
# The command for which the argument was unknown
attr_reader :command_in_context
def initialize(command_in_context)
@command_in_context = command_in_context
end
end
# Indicates that the command line invocation was bad
class BadCommandLine < StandardError
include StandardException
def exit_code; 64; end
end
class PreconditionFailed < StandardError
include StandardException
def exit_code; 65; end
end
# Indicates the bad command line was an unknown command
class UnknownCommand < BadCommandLine
end
# The command issued partially matches more than one command
class AmbiguousCommand < BadCommandLine
end
# Indicates the bad command line was an unknown global argument
class UnknownGlobalArgument < BadCommandLine
end
class CommandException < BadCommandLine
# The command for which the argument was unknown
attr_reader :command_in_context
# +message+:: the error message to show the user
# +command+:: the command we were using to parse command-specific options
def initialize(message,command_in_context,exit_code=nil)
super(message)
@command_in_context = command_in_context
@exit_code = exit_code
end
def exit_code
@exit_code || super
end
end
class MissingRequiredArgumentsException < BadCommandLine
# The command for which the argument was unknown
attr_reader :command_in_context
# +message+:: the error message to show the user
# +command+:: the command we were using to parse command-specific options
def initialize(message,command)
super(message)
@command_in_context = command
end
end
# Indicates the bad command line was an unknown command argument
class UnknownCommandArgument < CommandException
end
# Raise this if you want to use an exit status that isn't the default
# provided by GLI. Note that GLI::App#exit_now! might be a bit more to your liking.
#
# Example:
#
# raise CustomExit.new("Not connected to DB",-5) unless connected?
# raise CustomExit.new("Bad SQL",-6) unless valid_sql?(args[0])
#
class CustomExit < StandardError
include StandardException
attr_reader :exit_code #:nodoc:
# Create a custom exit exception
#
# +message+:: String containing error message to show the user
# +exit_code+:: the exit code to use (as an Int), overridding GLI's default
def initialize(message,exit_code)
super(message)
@exit_code = exit_code
end
end
end
gli-2.14.0/lib/gli/command_finder.rb 0000644 0001750 0001750 00000003760 13017317740 016121 0 ustar micah micah module GLI
class CommandFinder
attr_accessor :options
DEFAULT_OPTIONS = {
:default_command => nil,
:autocomplete => true
}
def initialize(commands, options = {})
self.options = DEFAULT_OPTIONS.merge(options)
self.commands_with_aliases = expand_with_aliases(commands)
end
def find_command(name)
name = String(name || options[:default_command]).strip
raise UnknownCommand.new("No command name given nor default available") if name == ''
command_found = commands_with_aliases.fetch(name) do |command_to_match|
if options[:autocomplete]
found_match = find_command_by_partial_name(commands_with_aliases, command_to_match)
if found_match.kind_of? GLI::Command
if ENV["GLI_DEBUG"] == 'true'
$stderr.puts "Using '#{name}' as it's is short for #{found_match.name}."
$stderr.puts "Set autocomplete false for any command you don't want matched like this"
end
elsif found_match.kind_of?(Array) && !found_match.empty?
raise AmbiguousCommand.new("Ambiguous command '#{name}'. It matches #{found_match.sort.join(',')}")
end
found_match
end
end
raise UnknownCommand.new("Unknown command '#{name}'") if Array(command_found).empty?
command_found
end
private
attr_accessor :commands_with_aliases
def expand_with_aliases(commands)
expanded = {}
commands.each do |command_name, command|
expanded[command_name.to_s] = command
Array(command.aliases).each do |command_alias|
expanded[command_alias.to_s] = command
end
end
expanded
end
def find_command_by_partial_name(commands_with_aliases, command_to_match)
partial_matches = commands_with_aliases.keys.select { |command_name| command_name =~ /^#{command_to_match}/ }
return commands_with_aliases[partial_matches[0]] if partial_matches.size == 1
partial_matches
end
end
end
gli-2.14.0/lib/gli/terminal.rb 0000644 0001750 0001750 00000006736 13017317740 014775 0 ustar micah micah module GLI
# Class to encapsulate stuff about the terminal. This is useful to application developers
# as a canonical means to get information about the user's current terminal configuraiton.
# GLI uses this to determine the number of columns to use when printing to the screen.
#
# To access it, use Terminal.instance. This is a singleton mostly to facilitate testing, but
# it seems reasonable enough, since there's only one terminal in effect
#
# Example:
#
# Terminal.instance.size[0] # => columns in the terminal
# Terminal.default_size = [128,24] # => change default when we can't figure it out
# raise "no ls?!?!?" unless Terminal.instance.command_exists?("ls")
#
class Terminal
@@default_size = [80,24]
# Get the default size of the terminal when we can't figure it out
#
# Returns an array of int [cols,rows]
def self.default_size
@@default_size
end
# Set the default size of the terminal to use when we can't figure it out
#
# +size+:: array of two int [cols,rows]
def self.default_size=(size)
@@default_size = size
end
# Provide access to the shared instance.
def self.instance; @@instance ||= Terminal.new; end
# Call this to cause methods to throw exceptions rather than return a sane default. You
# probably don't want to call this unless you are writing tests
def make_unsafe! #:nodoc:
@unsafe = true
end
# Returns true if the given command exists on this system
#
# +command+:: The command, as a String, to check for, without any path information.
def self.command_exists?(command)
ENV['PATH'].split(File::PATH_SEPARATOR).any? {|dir| File.exist? File.join(dir, command) }
end
def command_exists?(command)
self.class.command_exists?(command)
end
SIZE_DETERMINERS = [
[
lambda { (ENV['COLUMNS'] =~ /^\d+$/) && (ENV['LINES'] =~ /^\d+$/) },
lambda { [ENV['COLUMNS'].to_i, ENV['LINES'].to_i] }
],
[
lambda { (jruby? || (!STDIN.tty? && ENV['TERM'])) && command_exists?('tput') },
lambda { [run_command('tput cols').to_i, run_command('tput lines').to_i] }
],
[
lambda { (solaris? && STDIN.tty? && command_exists?('stty')) },
lambda { run_command('stty').split("\n")[1].scan(/\d+/)[0..1].map { |size_element| size_element.to_i }.reverse }
],
[
lambda { STDIN.tty? && command_exists?('stty') },
lambda { run_command('stty size').scan(/\d+/).map { |size_element| size_element.to_i }.reverse }
],
[
lambda { true },
lambda { Terminal.default_size },
],
]
# Get the size of the current terminal.
# Ripped from hirb[https://github.com/cldwalker/hirb/blob/master/lib/hirb/util.rb]
#
# Returns an Array of size two Ints representing the terminal width and height
def size
SIZE_DETERMINERS.each do |predicate, get_size|
next unless predicate.call
size = get_size.call
return size unless size == [0, 0]
end
rescue Exception => ex
raise ex if @unsafe
Terminal.default_size
end
private
# Runs a command using backticks. Extracted to allow for testing
def self.run_command(command)
`#{command}`
end
# True if we are JRuby; exposed to allow for testing
def self.jruby?; RUBY_PLATFORM =~ /java/; end
# True if this is running under Solaris Sparc
def self.solaris?; RUBY_PLATFORM =~ /solaris/; end
end
end
gli-2.14.0/lib/gli/command_line_option.rb 0000644 0001750 0001750 00000001753 13017317740 017171 0 ustar micah micah require 'gli/command_line_token.rb'
module GLI
# An option, not a command or argument, on the command line
class CommandLineOption < CommandLineToken #:nodoc:
attr_accessor :default_value
# Command to which this option "belongs", nil if it's a global option
attr_accessor :associated_command
# Creates a new option
#
# names - Array of symbols or strings representing the names of this switch
# options - hash of options:
# :desc - the short description
# :long_desc - the long description
# :default_value - the default value of this option
def initialize(names,options = {})
super(names,options[:desc],options[:long_desc])
@default_value = options[:default_value]
end
def self.name_as_string(name,negatable=true)
string = name.to_s
if string.length == 1
"-#{string}"
elsif negatable
"--[no-]#{string}"
else
"--#{string}"
end
end
end
end
gli-2.14.0/lib/gli/commands/ 0000755 0001750 0001750 00000000000 13017317740 014422 5 ustar micah micah gli-2.14.0/lib/gli/commands/help.rb 0000644 0001750 0001750 00000011064 13017317740 015701 0 ustar micah micah require 'erb'
require 'gli/command'
require 'gli/terminal'
require 'gli/commands/help_modules/list_formatter'
require 'gli/commands/help_modules/text_wrapper'
require 'gli/commands/help_modules/one_line_wrapper'
require 'gli/commands/help_modules/verbatim_wrapper'
require 'gli/commands/help_modules/tty_only_wrapper'
require 'gli/commands/help_modules/options_formatter'
require 'gli/commands/help_modules/global_help_format'
require 'gli/commands/help_modules/command_help_format'
require 'gli/commands/help_modules/help_completion_format'
require 'gli/commands/help_modules/command_finder'
require 'gli/commands/help_modules/arg_name_formatter'
require 'gli/commands/help_modules/full_synopsis_formatter'
require 'gli/commands/help_modules/compact_synopsis_formatter'
require 'gli/commands/help_modules/terminal_synopsis_formatter'
module GLI
module Commands
SORTERS = {
:manually => lambda { |list| list },
:alpha => lambda { |list| list.sort },
}
WRAPPERS = {
:to_terminal => HelpModules::TextWrapper,
:never => HelpModules::OneLineWrapper,
:one_line => HelpModules::OneLineWrapper,
:tty_only => HelpModules::TTYOnlyWrapper,
:none => HelpModules::VerbatimWrapper,
:verbatim => HelpModules::VerbatimWrapper,
}
SYNOPSIS_FORMATTERS = {
:full => HelpModules::FullSynopsisFormatter,
:compact => HelpModules::CompactSynopsisFormatter,
:terminal => HelpModules::TerminalSynopsisFormatter,
}
# The help command used for the two-level interactive help system
class Help < Command
@@skips_pre = true
@@skips_post = true
@@skips_around = true
# Configure help to explicitly skip or not skip the pre block when the help command runs.
# This is here because the creation of the help command is outside of the client programmer's control
def self.skips_pre=(skips_pre) ; @@skips_pre = skips_pre ; end
# Configure help to explicitly skip or not skip the post block when the help command runs.
# This is here because the creation of the help command is outside of the client programmer's control
def self.skips_post=(skips_post) ; @@skips_post = skips_post ; end
# Configure help to explicitly skip or not skip the around block when the help command runs.
# This is here because the creation of the help command is outside of the client programmer's control
def self.skips_around=(skips_around) ; @@skips_around = skips_around ; end
def initialize(app,output=$stdout,error=$stderr)
super(:names => :help,
:description => 'Shows a list of commands or help for one command',
:arguments_name => 'command',
:long_desc => 'Gets help for the application or its commands. Can also list the commands in a way helpful to creating a bash-style completion function',
:arguments => [Argument.new(:command_name, [:multiple, :optional])])
@app = app
@parent = app
@sorter = SORTERS[@app.help_sort_type]
@text_wrapping_class = WRAPPERS[@app.help_text_wrap_type]
@synopsis_formatter_class = SYNOPSIS_FORMATTERS[@app.synopsis_format_type]
desc 'List commands one per line, to assist with shell completion'
switch :c
action do |global_options,options,arguments|
if global_options[:version] && !global_options[:help]
puts "#{@app.exe_name} version #{@app.version_string}"
else
show_help(global_options,options,arguments,output,error)
end
end
end
def skips_pre ; @@skips_pre ; end
def skips_post ; @@skips_post ; end
def skips_around ; @@skips_around ; end
private
def show_help(global_options,options,arguments,out,error)
command_finder = HelpModules::CommandFinder.new(@app,arguments,error)
if options[:c]
help_output = HelpModules::HelpCompletionFormat.new(@app,command_finder,arguments).format
out.puts help_output unless help_output.nil?
elsif arguments.empty? || options[:c]
out.puts HelpModules::GlobalHelpFormat.new(@app,@sorter,@text_wrapping_class).format
else
name = arguments.shift
command = command_finder.find_command(name)
unless command.nil?
out.puts HelpModules::CommandHelpFormat.new(
command,
@app,
@sorter,
@synopsis_formatter_class,
@text_wrapping_class).format
end
end
end
end
end
end
gli-2.14.0/lib/gli/commands/rdoc_document_listener.rb 0000644 0001750 0001750 00000006154 13017317740 021507 0 ustar micah micah require 'stringio'
require 'gli/commands/help_modules/arg_name_formatter'
module GLI
module Commands
class RdocDocumentListener
def initialize(global_options,options,arguments,app)
@io = File.new("#{app.exe_name}.rdoc",'w')
@nest = ''
@arg_name_formatter = GLI::Commands::HelpModules::ArgNameFormatter.new
end
def beginning
end
# Called when processing has completed
def ending
@io.close
end
# Gives you the program description
def program_desc(desc)
@io.puts "== #{@app.exe_name} - #{desc}"
@io.puts
end
def program_long_desc(desc)
@io.puts desc
@io.puts
end
# Gives you the program version
def version(version)
@io.puts "v#{version}"
@io.puts
end
def options
if @nest.size == 0
@io.puts "=== Global Options"
else
@io.puts "#{@nest}=== Options"
end
end
# Gives you a flag in the current context
def flag(name,aliases,desc,long_desc,default_value,arg_name,must_match,type)
invocations = ([name] + Array(aliases)).map { |_| add_dashes(_) }.join('|')
usage = "#{invocations} #{arg_name || 'arg'}"
@io.puts "#{@nest}=== #{usage}"
@io.puts
@io.puts String(desc).strip
@io.puts
@io.puts "[Default Value] #{default_value || 'None'}"
@io.puts "[Must Match] #{must_match.to_s}" unless must_match.nil?
@io.puts String(long_desc).strip
@io.puts
end
# Gives you a switch in the current context
def switch(name,aliases,desc,long_desc,negatable)
if negatable
name = "[no-]#{name}" if name.to_s.length > 1
aliases = aliases.map { |_| _.to_s.length > 1 ? "[no-]#{_}" : _ }
end
invocations = ([name] + aliases).map { |_| add_dashes(_) }.join('|')
@io.puts "#{@nest}=== #{invocations}"
@io.puts String(desc).strip
@io.puts
@io.puts String(long_desc).strip
@io.puts
end
def end_options
end
def commands
@io.puts "#{@nest}=== Commands"
@nest = "#{@nest}="
end
# Gives you a command in the current context and creates a new context of this command
def command(name,aliases,desc,long_desc,arg_name,arg_options)
@io.puts "#{@nest}=== Command: #{([name] + aliases).join('|')} #{@arg_name_formatter.format(arg_name,arg_options,[])}"
@io.puts String(desc).strip
@io.puts
@io.puts String(long_desc).strip
@nest = "#{@nest}="
end
# Ends a command, and "pops" you back up one context
def end_command(name)
@nest.gsub!(/=$/,'')
end
# Gives you the name of the current command in the current context
def default_command(name)
@io.puts "[Default Command] #{name}" unless name.nil?
end
def end_commands
@nest.gsub!(/=$/,'')
end
private
def add_dashes(name)
name = "-#{name}"
name = "-#{name}" if name.length > 2
name
end
end
end
end
gli-2.14.0/lib/gli/commands/initconfig.rb 0000644 0001750 0001750 00000005143 13017317740 017103 0 ustar micah micah require 'gli'
require 'gli/command'
require 'yaml'
require 'fileutils'
module GLI
# Command that initializes the configuration file for apps that use it.
class InitConfig < Command # :nodoc:
COMMANDS_KEY = 'commands'
def initialize(config_file_name,commands,flags,switches)
@filename = config_file_name
super(:names => :initconfig,
:description => "Initialize the config file using current global options",
:long_desc => 'Initializes a configuration file where you can set default options for command line flags, both globally and on a per-command basis. These defaults override the built-in defaults and allow you to omit commonly-used command line flags when invoking this program',
:skips_pre => true,:skips_post => true, :skips_around => true)
@app_commands = commands
@app_flags = flags
@app_switches = switches
self.desc 'force overwrite of existing config file'
self.switch :force
action do |global_options,options,arguments|
if options[:force] || !File.exist?(@filename)
create_config(global_options,options,arguments)
else
raise "Not overwriting existing config file #{@filename}, use --force to override"
end
end
end
private
def create_config(global_options,options,arguments)
config = Hash[(@app_switches.keys + @app_flags.keys).map { |option_name|
option_value = global_options[option_name]
if option_value.kind_of?(String) && option_value.respond_to?(:force_encoding)
[option_name,option_value.force_encoding("utf-8")]
else
[option_name,option_value]
end
}]
config[COMMANDS_KEY] = {}
@app_commands.each do |name,command|
if (command != self) && (name != :rdoc) && (name != :help)
if command != self
config[COMMANDS_KEY][name.to_sym] = config_for_command(@app_commands,name.to_sym)
end
end
end
FileUtils.mkdir_p(File.dirname(@filename)) unless File.dirname(@filename) == '.'
File.open(@filename,'w', 0600) do |file|
YAML.dump(config,file)
puts "Configuration file '#{@filename}' written."
end
end
def config_for_command(commands,command_name)
{}.tap do |hash|
subcommands = commands[command_name].commands
subcommands.each do |name,subcommand|
next unless name.kind_of? Symbol
hash[COMMANDS_KEY] ||= {}
puts "#{command_name}:#{name}"
hash[COMMANDS_KEY][name.to_sym] = config_for_command(subcommands,name)
end
end
end
end
end
gli-2.14.0/lib/gli/commands/help_modules/ 0000755 0001750 0001750 00000000000 13017317740 017102 5 ustar micah micah gli-2.14.0/lib/gli/commands/help_modules/full_synopsis_formatter.rb 0000644 0001750 0001750 00000006741 13017317740 024433 0 ustar micah micah module GLI
module Commands
module HelpModules
class FullSynopsisFormatter
def initialize(app,flags_and_switches)
@app = app
@basic_invocation = @app.exe_name.to_s
@flags_and_switches = flags_and_switches
end
def synopses_for_command(command)
synopses = []
one_line_usage = basic_usage(command)
one_line_usage << ArgNameFormatter.new.format(command.arguments_description,command.arguments_options,command.arguments).strip
if command.commands.empty?
synopses << one_line_usage
else
synopses = sorted_synopses(command)
if command.has_action?
synopses.unshift(one_line_usage)
end
end
synopses
end
protected
def sub_options_doc(sub_options)
sub_options_doc = sub_options.map { |_,option|
doc = option.names_and_aliases.map { |name|
CommandLineOption.name_as_string(name,false) + (option.kind_of?(Flag) ? " #{option.argument_name }" : '')
}.join('|')
option.required?? doc : "[#{doc}]"
}.sort.join(' ').strip
end
private
def path_to_command(command)
path = []
c = command
while c.kind_of? Command
path.unshift(c.name)
c = c.parent
end
path.join(' ')
end
def basic_usage(command)
usage = @basic_invocation.dup
usage << " [global options]" unless global_flags_and_switches.empty?
usage << " #{path_to_command(command)}"
usage << " [command options]" unless @flags_and_switches.empty?
usage << " "
usage
end
def command_with_subcommand_usage(command,sub,is_default_command)
usage = basic_usage(command)
sub_options = if @app.subcommand_option_handling_strategy == :legacy
command.flags.merge(command.switches).select { |_,o| o.associated_command == sub }
else
sub.flags.merge(sub.switches)
end
if is_default_command
usage << "[#{sub.name}]"
else
usage << sub.name.to_s
end
sub_options_doc = sub_options_doc(sub_options)
if sub_options_doc.length > 0
usage << ' '
usage << sub_options_doc
end
arg_name_doc = ArgNameFormatter.new.format(sub.arguments_description,sub.arguments_options,sub.arguments).strip
if arg_name_doc.length > 0
usage << ' '
usage << arg_name_doc
end
usage
end
def sorted_synopses(command)
synopses_command = {}
command.commands.each do |name,sub|
default = command.get_default_command == name
synopsis = command_with_subcommand_usage(command,sub,default)
synopses_command[synopsis] = sub
end
synopses = synopses_command.keys.sort { |one,two|
if synopses_command[one].name == command.get_default_command
-1
elsif synopses_command[two].name == command.get_default_command
1
else
synopses_command[one] <=> synopses_command[two]
end
}
end
def global_flags_and_switches
@app.flags.merge(@app.switches)
end
end
end
end
end
gli-2.14.0/lib/gli/commands/help_modules/text_wrapper.rb 0000644 0001750 0001750 00000003226 13017317740 022156 0 ustar micah micah module GLI
module Commands
module HelpModules
# Handles wrapping text
class TextWrapper
# Create a text_wrapper wrapping at the given width,
# and indent.
def initialize(width,indent)
@width = width
@indent = indent
end
# Return a wrapped version of text, assuming that the first line has already been
# indented by @indent characters. Resulting text does NOT have a newline in it.
def wrap(text)
return text if text.nil?
wrapped_text = ''
current_graf = ''
paragraphs = text.split(/\n\n+/)
paragraphs.each do |graf|
current_line = ''
current_line_length = @indent
words = graf.split(/\s+/)
current_line = words.shift || ''
current_line_length += current_line.length
words.each do |word|
if current_line_length + word.length + 1 > @width
current_graf << current_line << "\n"
current_line = ''
current_line << ' ' * @indent << word
current_line_length = @indent + word.length
else
if current_line == ''
current_line << word
else
current_line << ' ' << word
end
current_line_length += (word.length + 1)
end
end
current_graf << current_line
wrapped_text << current_graf << "\n\n" << ' ' * @indent
current_graf = ''
end
wrapped_text.gsub(/[\n\s]*\Z/,'')
end
end
end
end
end
gli-2.14.0/lib/gli/commands/help_modules/help_completion_format.rb 0000644 0001750 0001750 00000001516 13017317740 024163 0 ustar micah micah module GLI
module Commands
module HelpModules
class HelpCompletionFormat
def initialize(app,command_finder,args)
@app = app
@command_finder = command_finder
@command_finder.squelch_stderr = true
@args = args
end
def format
name = @args.shift
base = @command_finder.find_command(name)
base = @command_finder.last_found_command if base.nil?
base = @app if base.nil?
prefix_to_match = @command_finder.last_unknown_command
base.commands.values.map { |command|
[command.name,command.aliases]
}.flatten.compact.map(&:to_s).sort.select { |command_name|
prefix_to_match.nil? || command_name =~ /^#{prefix_to_match}/
}.join("\n")
end
end
end
end
end
gli-2.14.0/lib/gli/commands/help_modules/list_formatter.rb 0000644 0001750 0001750 00000001343 13017317740 022466 0 ustar micah micah module GLI
module Commands
module HelpModules
# Given a list of two-element lists, formats on the terminal
class ListFormatter
def initialize(list,wrapper_class=TextWrapper)
@list = list
@wrapper_class = wrapper_class
end
# Output the list to the output_device
def output(output_device)
return if @list.empty?
max_width = @list.map { |_| _[0].length }.max
wrapper = @wrapper_class.new(Terminal.instance.size[0],4 + max_width + 3)
@list.each do |(name,description)|
output_device.printf(" %-#{max_width}s - %s\n",name,wrapper.wrap(String(description).strip))
end
end
end
end
end
end
gli-2.14.0/lib/gli/commands/help_modules/tty_only_wrapper.rb 0000644 0001750 0001750 00000001354 13017317740 023053 0 ustar micah micah module GLI
module Commands
module HelpModules
# Formats text in one line, stripping newlines and NOT wrapping
class TTYOnlyWrapper
# Args are ignored entirely; this keeps it consistent with the TextWrapper interface
def initialize(width,indent)
@proxy = if STDOUT.tty?
TextWrapper.new(width,indent)
else
OneLineWrapper.new(width,indent)
end
end
# Return a wrapped version of text, assuming that the first line has already been
# indented by @indent characters. Resulting text does NOT have a newline in it.
def wrap(text)
@proxy.wrap(text)
end
end
end
end
end
gli-2.14.0/lib/gli/commands/help_modules/command_finder.rb 0000644 0001750 0001750 00000003617 13017317740 022403 0 ustar micah micah module GLI
module Commands
module HelpModules
# Finds commands from the application/command data structures
class CommandFinder
attr_reader :last_unknown_command
attr_reader :last_found_command
attr_writer :squelch_stderr
def initialize(app,arguments,error)
@app = app
@arguments = arguments
@error = error
@squelch_stderr = false
@last_unknown_command = nil
end
def find_command(name)
command = find_command_from_base(name,@app)
return if unknown_command?(command,name,@error)
@last_found_command = command
while !@arguments.empty?
name = @arguments.shift
command = find_command_from_base(name,command)
return if unknown_command?(command,name,@error)
@last_found_command = command
end
command
end
private
# Given the name of a command to find, and a base, either the app or another command, returns
# the command object or nil.
def find_command_from_base(command_name,base)
base.commands.values.select { |command|
if [command.name,Array(command.aliases)].flatten.map(&:to_s).any? { |_| _ == command_name }
command
end
}.first
end
# Checks if the return from find_command was unknown and, if so, prints an error
# for the user on the error device, returning true or false if the command was unknown.
def unknown_command?(command,name,error)
if command.nil?
@last_unknown_command = name
unless @squelch_stderr
error.puts "error: Unknown command '#{name}'. Use '#{@app.exe_name} help' for a list of commands."
end
true
else
false
end
end
end
end
end
end
gli-2.14.0/lib/gli/commands/help_modules/verbatim_wrapper.rb 0000644 0001750 0001750 00000000617 13017317740 023004 0 ustar micah micah module GLI
module Commands
module HelpModules
# Leaves text formatting exactly as it was received. Doesn't strip anything.
class VerbatimWrapper
# Args are ignored entirely; this keeps it consistent with the TextWrapper interface
def initialize(width,indent)
end
def wrap(text)
return String(text)
end
end
end
end
end
gli-2.14.0/lib/gli/commands/help_modules/options_formatter.rb 0000644 0001750 0001750 00000003420 13017317740 023204 0 ustar micah micah module GLI
module Commands
module HelpModules
class OptionsFormatter
def initialize(flags_and_switches,sorter,wrapper_class)
@flags_and_switches = sorter.call(flags_and_switches)
@wrapper_class = wrapper_class
end
def format
list_formatter = ListFormatter.new(@flags_and_switches.map { |option|
if option.respond_to? :argument_name
[option_names_for_help_string(option,option.argument_name),description_with_default(option)]
else
[option_names_for_help_string(option),description_with_default(option)]
end
},@wrapper_class)
stringio = StringIO.new
list_formatter.output(stringio)
stringio.string
end
private
def description_with_default(option)
if option.kind_of? Flag
required = option.required? ? 'required, ' : ''
multiple = option.multiple? ? 'may be used more than once, ' : ''
String(option.description) + " (#{required}#{multiple}default: #{option.safe_default_value || 'none'})"
else
String(option.description) + (option.default_value ? " (default: enabled)" : "")
end
end
def option_names_for_help_string(option,arg_name=nil)
names = [option.name,Array(option.aliases)].flatten
names = names.map { |name| CommandLineOption.name_as_string(name,option.kind_of?(Switch) ? option.negatable? : false) }
if arg_name.nil?
names.join(', ')
else
if names[-1] =~ /^--/
names.join(', ') + "=#{arg_name}"
else
names.join(', ') + " #{arg_name}"
end
end
end
end
end
end
end
gli-2.14.0/lib/gli/commands/help_modules/global_help_format.rb 0000644 0001750 0001750 00000003665 13017317740 023261 0 ustar micah micah require 'erb'
module GLI
module Commands
module HelpModules
class GlobalHelpFormat
def initialize(app,sorter,wrapper_class)
@app = app
@sorter = sorter
@wrapper_class = wrapper_class
end
def format
program_desc = @app.program_desc
program_long_desc = @app.program_long_desc
if program_long_desc
wrapper = @wrapper_class.new(Terminal.instance.size[0],4)
program_long_desc = "\n #{wrapper.wrap(program_long_desc)}\n\n" if program_long_desc
else
program_long_desc = "\n"
end
command_formatter = ListFormatter.new(@sorter.call(@app.commands_declaration_order.reject(&:nodoc)).map { |command|
[[command.name,Array(command.aliases)].flatten.join(', '),command.description]
}, @wrapper_class)
stringio = StringIO.new
command_formatter.output(stringio)
commands = stringio.string
global_option_descriptions = OptionsFormatter.new(global_flags_and_switches,@sorter,@wrapper_class).format
GLOBAL_HELP.result(binding)
end
private
GLOBAL_HELP = ERB.new(%q(NAME
<%= @app.exe_name %> - <%= program_desc %>
<%= program_long_desc %>
SYNOPSIS
<%= usage_string %>
<% unless @app.version_string.nil? %>
VERSION
<%= @app.version_string %>
<% end %>
<% unless global_flags_and_switches.empty? %>
GLOBAL OPTIONS
<%= global_option_descriptions %>
<% end %>
COMMANDS
<%= commands %>),nil,'<>')
def global_flags_and_switches
@app.flags_declaration_order + @app.switches_declaration_order
end
def usage_string
"#{@app.exe_name} ".tap do |string|
string << "[global options] " unless global_flags_and_switches.empty?
string << "command "
string << "[command options] [arguments...]"
end
end
end
end
end
end
gli-2.14.0/lib/gli/commands/help_modules/terminal_synopsis_formatter.rb 0000644 0001750 0001750 00000001261 13017317740 025274 0 ustar micah micah module GLI
module Commands
module HelpModules
class TerminalSynopsisFormatter
def initialize(app,flags_and_switches)
@app = app
@basic_invocation = @app.exe_name.to_s
@flags_and_switches = flags_and_switches
end
def synopses_for_command(command)
synopses = FullSynopsisFormatter.new(@app,@flags_and_switches).synopses_for_command(command)
if synopses.any? { |synopsis| synopsis.length > Terminal.instance.size[0] }
CompactSynopsisFormatter.new(@app,@flags_and_switches).synopses_for_command(command)
else
synopses
end
end
end
end
end
end
gli-2.14.0/lib/gli/commands/help_modules/arg_name_formatter.rb 0000644 0001750 0001750 00000002563 13017317740 023271 0 ustar micah micah module GLI
module Commands
module HelpModules
# Handles wrapping text
class ArgNameFormatter
def format(arguments_description,arguments_options,arguments)
# Select which format to use: argname or arguments
# Priority to old way: argname
desc = format_argname(arguments_description, arguments_options)
desc = format_arguments(arguments) if desc.strip == ''
desc
end
def format_arguments(arguments)
return '' if arguments.empty?
desc = ""
# Go through the arguments, building the description string
arguments.each do |arg|
arg_desc = "#{arg.name}"
if arg.optional?
arg_desc = "[#{arg_desc}]"
end
if arg.multiple?
arg_desc = "#{arg_desc}[, #{arg_desc}]*"
end
desc = desc + " " + arg_desc
end
desc
end
def format_argname(arguments_description,arguments_options)
return '' if String(arguments_description).strip == ''
desc = arguments_description
if arguments_options.include? :optional
desc = "[#{desc}]"
end
if arguments_options.include? :multiple
desc = "#{desc}[, #{desc}]*"
end
" " + desc
end
end
end
end
end
gli-2.14.0/lib/gli/commands/help_modules/one_line_wrapper.rb 0000644 0001750 0001750 00000001112 13017317740 022752 0 ustar micah micah module GLI
module Commands
module HelpModules
# Formats text in one line, stripping newlines and NOT wrapping
class OneLineWrapper
# Args are ignored entirely; this keeps it consistent with the TextWrapper interface
def initialize(width,indent)
end
# Return a wrapped version of text, assuming that the first line has already been
# indented by @indent characters. Resulting text does NOT have a newline in it.
def wrap(text)
return String(text).gsub(/\n+/,' ').strip
end
end
end
end
end
gli-2.14.0/lib/gli/commands/help_modules/compact_synopsis_formatter.rb 0000644 0001750 0001750 00000000505 13017317740 025107 0 ustar micah micah module GLI
module Commands
module HelpModules
class CompactSynopsisFormatter < FullSynopsisFormatter
protected
def sub_options_doc(sub_options)
if sub_options.empty?
''
else
'[subcommand options]'
end
end
end
end
end
end
gli-2.14.0/lib/gli/commands/help_modules/command_help_format.rb 0000644 0001750 0001750 00000005040 13017317740 023424 0 ustar micah micah require 'erb'
module GLI
module Commands
module HelpModules
class CommandHelpFormat
def initialize(command,app,sorter,synopsis_formatter_class,wrapper_class=TextWrapper)
@app = app
@command = command
@sorter = sorter
@wrapper_class = wrapper_class
@synopsis_formatter = synopsis_formatter_class.new(@app,flags_and_switches(@command,@app))
end
def format
command_wrapper = @wrapper_class.new(Terminal.instance.size[0],4 + @command.name.to_s.size + 3)
wrapper = @wrapper_class.new(Terminal.instance.size[0],4)
options_description = OptionsFormatter.new(flags_and_switches(@command,@app),@sorter,@wrapper_class).format
commands_description = format_subcommands(@command)
synopses = @synopsis_formatter.synopses_for_command(@command)
COMMAND_HELP.result(binding)
end
private
COMMAND_HELP = ERB.new(%q(NAME
<%= @command.name %> - <%= command_wrapper.wrap(@command.description) %>
SYNOPSIS
<% synopses.each do |s| %>
<%= s %>
<% end %>
<% unless @command.long_description.nil? %>
DESCRIPTION
<%= wrapper.wrap(@command.long_description) %>
<% end %>
<% if options_description.strip.length != 0 %>
COMMAND OPTIONS
<%= options_description %>
<% end %>
<% unless @command.commands.empty? %>
COMMANDS
<%= commands_description %>
<% end %>),nil,'<>')
def flags_and_switches(command,app)
if app.subcommand_option_handling_strategy == :legacy
(
command.topmost_ancestor.flags_declaration_order +
command.topmost_ancestor.switches_declaration_order
).select { |option| option.associated_command == command }
else
(
command.flags_declaration_order +
command.switches_declaration_order
)
end
end
def format_subcommands(command)
commands_array = @sorter.call(command.commands_declaration_order).map { |cmd|
if command.get_default_command == cmd.name
[cmd.names,String(cmd.description) + " (default)"]
else
[cmd.names,cmd.description]
end
}
if command.has_action?
commands_array.unshift(["",command.default_description])
end
formatter = ListFormatter.new(commands_array,@wrapper_class)
StringIO.new.tap { |io| formatter.output(io) }.string
end
end
end
end
end
gli-2.14.0/lib/gli/commands/scaffold.rb 0000644 0001750 0001750 00000027017 13017317740 016537 0 ustar micah micah require 'gli'
require 'fileutils'
module GLI
module Commands
class Scaffold #:nodoc:
def self.create_scaffold(root_dir,
create_test_dir,
create_ext_dir,
project_name,
commands,
force=false,
dry_run=false,
create_rvmrc=false)
dirs = [File.join(root_dir,project_name,'lib')]
dirs << File.join(root_dir,project_name,'bin')
dirs << File.join(root_dir,project_name,'test') if create_test_dir
dirs << File.join(root_dir,project_name,'ext') if create_ext_dir
if mkdirs(dirs,force,dry_run)
mk_binfile(root_dir,create_ext_dir,force,dry_run,project_name,commands)
mk_readme(root_dir,dry_run,project_name)
mk_gemspec(root_dir,dry_run,project_name)
mk_rakefile(root_dir,dry_run,project_name,create_test_dir)
mk_lib_files(root_dir,dry_run,project_name)
if create_rvmrc
rvmrc = File.join(root_dir,project_name,".rvmrc")
File.open(rvmrc,'w') do |file|
file.puts "rvm use #{ENV['rvm_ruby_string']}@#{project_name} --create"
end
puts "Created #{rvmrc}"
end
end
end
def self.mk_readme(root_dir,dry_run,project_name)
return if dry_run
File.open("#{root_dir}/#{project_name}/README.rdoc",'w') do |file|
file << "= #{project_name}\n\n"
file << "Describe your project here\n\n"
file << ":include:#{project_name}.rdoc\n\n"
end
puts "Created #{root_dir}/#{project_name}/README.rdoc"
File.open("#{root_dir}/#{project_name}/#{project_name}.rdoc",'w') do |file|
file << "= #{project_name}\n\n"
file << "Generate this with\n #{project_name} rdoc\nAfter you have described your command line interface"
end
puts "Created #{root_dir}/#{project_name}/#{project_name}.rdoc"
end
def self.mk_gemspec(root_dir,dry_run,project_name)
return if dry_run
File.open("#{root_dir}/#{project_name}/#{project_name}.gemspec",'w') do |file|
file.puts < :features
task 'cucumber:wip' => 'features:wip'
task :wip => 'features:wip'
EOS
end
if create_test_dir
file.puts < [:test,:features]
EOS
File.open("#{root_dir}/#{project_name}/test/default_test.rb",'w') do |test_file|
test_file.puts < :package\n"
end
end
puts "Created #{root_dir}/#{project_name}/Rakefile"
File.open("#{root_dir}/#{project_name}/Gemfile",'w') do |bundler_file|
bundler_file.puts "source 'https://rubygems.org'"
bundler_file.puts "gemspec"
end
puts "Created #{root_dir}/#{project_name}/Gemfile"
if create_test_dir
features_dir = File.join(root_dir,project_name,'features')
FileUtils.mkdir features_dir
FileUtils.mkdir File.join(features_dir,"step_definitions")
FileUtils.mkdir File.join(features_dir,"support")
File.open(File.join(features_dir,"#{project_name}.feature"),'w') do |file|
file.puts <