diff --git a/src/cligen.cr b/src/cligen.cr index 3c00be6..a093171 100644 --- a/src/cligen.cr +++ b/src/cligen.cr @@ -3,17 +3,17 @@ require "option_parser" module CliGen VERSION = "0.1.0" + APPNAME = File.basename(PROGRAM_NAME) record AdditionalDefaultFlag, - short : String?, - long : String?, + short : String, + long : String, description : String, - work : Proc(Nil) + work : String -> - private ADDITIONAL_DEFAULT_FLAGS = [] of AdditionalDefaultFlag + ADDITIONAL_DEFAULT_FLAGS = [] of AdditionalDefaultFlag - def self.add_default_flag(short : String? = nil, long : String? = nil, description : String? = nil, &work : -> ) + def self.add_default_flag(short : String, long : String, description : String, &work : String -> ) raise "ERROR : add_default_flag : You must provide a description" unless description - raise "ERROR : add_default_flag : You must provide at least long or short" unless [short, long].any? ADDITIONAL_DEFAULT_FLAGS << AdditionalDefaultFlag.new( short: short, long: long, @@ -32,18 +32,19 @@ module CliGen end + alias OnType = Tuple(String, String) | Tuple(String, String, String) macro define_default_flags(parser) - define_section("Misc Flags", {{parser}}) + CliGen.define_section("Misc Flags", {{parser}}) {{parser}}.on("-h", "--help", "Print out this help output"){ abort {{parser}} } {{parser}}.invalid_option{|opt| - abort "#{PROGRAM_NAME} : invalid_option : Inavlid option provided #{opt}" + abort "#{CliGen::APPNAME} : invalid_option : Inavlid option provided #{opt}" } {{parser}}.invalid_option{|opt| case opt when /^-+[a-z-]+/ - Logger.debug "#{PROGRAM_NAME} : ERROR : {{parser}} : invalid_option : Inavlid option provided #{opt}" + Logger.debug "#{CliGen::APPNAME} : ERROR : {{parser}} : invalid_option : Inavlid option provided #{opt}" else - abort "#{PROGRAM_NAME} : ERROR : {{parser}} : invalid_option : Inavlid option provided #{opt}" + abort "#{CliGen::APPNAME} : ERROR : {{parser}} : invalid_option : Inavlid option provided #{opt}" end } {{parser}}.missing_option{|opt| @@ -60,23 +61,23 @@ module CliGen end } - ADDITIONAL_DEFAULT_FLAGS.each do |flag| - args = [flag.short, flag.long, flag.description].reject(&.nil?) - {{parser}}.on(*args) &flag.work + CliGen::ADDITIONAL_DEFAULT_FLAGS.each do |flag| + {{parser}}.on(flag.short, flag.long, flag.description){|var| flag.work.call(var) } end end macro define_root_parser ROOT_COMMAND = OptionParser.new do |parser| - parser.banner = "#{PROGRAM_NAME} [command] [flags]" + parser.banner = "#{CliGen::APPNAME} [command] [flags]" {% commands = ::CliGen::Command.subclasses %} {% raise "ERROR : No commands defined (no subclasses of ::CliGen::Command were found)" if commands.empty? %} + CliGen.define_section("Commands", parser) {% for command in commands %} {{command.name}}.make_parser(parser) {% end %} - define_default_flags(parser) + CliGen.define_default_flags(parser) abort parser if ARGV.empty? end diff --git a/src/command.cr b/src/command.cr index 1676560..0697698 100644 --- a/src/command.cr +++ b/src/command.cr @@ -21,7 +21,6 @@ module CliGen class Command extend CliGen::Parser - @@action : String = "" macro inherited macro finished @@ -29,10 +28,12 @@ module CliGen define_header define_runner define_parser + define_action_setter end end macro define_actions + @@action : String = "" ACTIONS = {{@type.class.methods.select(&.annotation(::CliGen::SubCommand)).map(&.name.stringify)}} of String end @@ -42,7 +43,7 @@ module CliGen {% examples = [] of StringLiteral %} {% info_annos.select(&.[](:examples)).map(&.[](:examples).resolve).each(&.each{|example| examples << example}) %} HEADER = [ - "#{PROGRAM_NAME} {{name}} [[flags]]", + "#{CliGen::APPNAME} {{name}} [[flags]]", "", {% unless examples.empty? %} "Examples:".colorize(:green), @@ -140,15 +141,17 @@ module CliGen {{method.name}} {% end %} else - abort "ERROR : No action provided to command #{@type.name}" + abort "ERROR : No action provided to command {{@type.name}}" end {% end %} end end - def self.action=(action : String) - abort "ERROR : Action(#{action}) is not valid. Only #{ACTIONS.join(", ")} are acceptable" unless ACTIONS.includes?(action) - @@action = action + macro define_action_setter + def self.action=(action : String) + abort "ERROR : Action(#{action}) is not valid. Only #{ACTIONS.join(", ")} are acceptable" unless ACTIONS.includes?(action) + @@action = action + end end end diff --git a/src/command/parser.cr b/src/command/parser.cr index 3e085e6..649aa76 100644 --- a/src/command/parser.cr +++ b/src/command/parser.cr @@ -3,12 +3,12 @@ module CliGen::Parser macro extended {% verbatim do %} macro define_parser - def self.make_parser(parent_parser : OptionParser) : OptionParser + def self.make_parser(parent_parser : OptionParser) : Nil {% puts "#{@type.name} OptionParser is being generated" %} {% name = @type.name.split("::").last %} {% var = name.downcase %} {% info = @type.annotation(::CliGen::CommandInfo) %} - {% raise "ERROR : No CommandInfo annotation provided to #{@type.name}" unless info %} + {% raise "ERROR : No CommandInfo annotation provided to {{@type.name}}" unless info %} subparser = OptionParser.new do |parser| parser.banner = {{@type.name}}::HEADER {% subcommands = @type.class.methods.select(&.annotation(::CliGen::SubCommand)) %} @@ -38,11 +38,11 @@ module CliGen::Parser } {% end %} {% end %} - define_default_flags(parser) + CliGen.define_default_flags(parser) end parent_parser.on({{var}}, {{info[:description]}}){ ARGV.delete({{var}}) - abort {{var.id}} if ARGV.empty? + abort subparser if ARGV.empty? subparser.parse {{@type.name}}.run }