lib/texas/cli/option_parser.rb
require 'optparse'
require 'optparse/time'
require 'ostruct'
require 'pathname'
module Texas
module CLI
class OptionParser
include Texas::CLI::OutputHelper
attr_reader :args, :options
def initialize(args)
@args = args
@options = OpenStruct.new
end
# Returns a structure describing the options.
#
def parse
set_default_options
lookup_and_execute_require_option(args)
parse_options
set_contents_template_from_args unless args.empty?
check_mandatory! if options.check_mandatory_arguments
options
end
private
# Kills the program if any mandatory options are missing.
#
def check_mandatory!
if options.work_dir.nil?
kill "missing file operand"
end
if options.contents_template.nil?
kill "could not find contents template"
end
end
# Displays an error message and exits the program afterwards.
#
def kill(msg)
trace "texas: #{msg}\nTry `texas --help' for more information."
exit 1
end
def find_work_dir(start_dir = Dir.pwd)
results = Dir[File.join(start_dir, Texas.contents_subdir_name)]
if !results.empty?
start_dir
else
path = Pathname.new(start_dir)
if path.realpath.to_s == "/"
nil
else
find_work_dir File.join(start_dir, '..')
end
end
end
def find_contents_dir(file)
if file =~ /#{Texas.contents_subdir_name}/
Texas.contents_subdir_name
else
nil
end
end
def find_contents_template(file)
file = file.gsub("#{Texas.contents_subdir_name}/", "")
glob = File.join(Texas.contents_subdir_name, "#{file}*")
if Dir[glob].empty?
nil
else
file
end
end
# Parses the given arguments for the --require option and requires
# it if present. This is done separately from the regular option parsing
# to enable the required library to modify Texas,
# e.g. overwrite OptionParser#parse_additional_options.
#
def lookup_and_execute_require_option(args)
args.each_with_index do |v, i|
if %w(-r --require).include?(v)
require args[i+1]
end
end
end
def parse_options
parser = ::OptionParser.new do |parser|
parser.banner = "Usage: texas [CONTENTS_TEMPLATE] [options]"
parse_specific_options(parser)
parse_additional_options(parser)
parse_common_options(parser)
end
parser.parse!(args)
end
def parse_additional_options(parser)
if arr = self.class.parse_options_procs
parser.separator ""
parser.separator "Custom options:"
arr.each do |proc|
proc.(parser, options)
end
end
end
def self.parse_options_procs
@@parse_options_procs ||= []
end
def self.parse_additional_options(&block)
parse_options_procs << block
end
def parse_common_options(parser)
parser.separator ""
parser.separator "Common options:"
parser.on("--[no-]backtrace", "Switch backtrace") do |v|
options.backtrace = v
end
parser.on("-c", "--[no-]color", "Switch colors") do |v|
options.colors = v
end
parser.on("-v", "--[no-]verbose", "Run verbosely") do |v|
options.verbose = v
end
parser.on("-w", "--[no-]warnings", "Switch warnings") do |v|
options.warnings = v
end
# No argument, shows at tail. This will print an options summary.
# Try it and see!
parser.on_tail("-h", "--help", "Show this message") do
trace parser
exit
end
# Another typical switch to print the version.
parser.on_tail("--version", "Show version") do
trace Texas::VERSION::STRING
exit
end
end
# Parses the specific options.
#
def parse_specific_options(parser)
parser.separator ""
parser.separator "Specific options:"
parser.on("-d", "--dry-run", "Run without pdf generation") do |contents_template|
options.task = :dry
end
parser.on("-m", "--merge-config [CONFIG]",
"Merge config with key from .texasrc") do |key|
options.merge_config = key
end
parser.on("-n", "--new [NAME]",
"Create new texas project directory") do |name|
options.task = :new_project
options.check_mandatory_arguments = false
options.load_local_libs = false
options.new_project_name = name
end
parser.on("-r", "--require [LIBRARY]", "Require library before running texas") do |lib|
# this block does nothing
# require was already performed by lookup_and_execute_require_option
# this option is here to ensure the -r switch is listed in the help option
end
parser.on("--watch", "Watch the given template") do |contents_template|
options.task = :watch
options.open_pdf = false
end
end
def set_default_options
options.task = :build
options.work_dir = find_work_dir
options.check_mandatory_arguments = true
options.load_local_libs = true
options.contents_dir = Texas.contents_subdir_name
options.contents_template = find_contents_template("contents")
options.backtrace = false
options.colors = true
options.merge_config = nil
options.verbose = false
options.warnings = true
options.open_pdf = true
end
def set_contents_template_from_args
f = args.shift
options.contents_template = find_contents_template(f)
options.contents_dir = find_contents_dir(f)
end
end
end
end