Compare commits

..

2 Commits

Author SHA1 Message Date
Tristan Ancelet
37ea36cfdd Pushing changes 2026-03-20 19:01:33 -05:00
Tristan Ancelet
3775096cc3 had to add thing 2026-03-11 13:39:14 -05:00
3 changed files with 69 additions and 19 deletions

View File

@@ -44,21 +44,21 @@ module CliGen
{{parser}}.invalid_option{|opt|
case opt
when /^-+[a-z-]+/
Logger.debug "#{CliGen::APPNAME} : ERROR : {{parser}} : invalid_option : Inavlid option provided #{opt}"
STDERR.puts "#{CliGen::APPNAME} : ERROR : {{@type.name}} : {{parser}} : invalid_option : Inavlid option provided #{opt}"
else
abort "#{CliGen::APPNAME} : ERROR : {{parser}} : invalid_option : Inavlid option provided #{opt}"
abort "#{CliGen::APPNAME} : ERROR : {{@type.name}} : {{parser}} : invalid_option : Inavlid option provided #{opt}"
end
}
{{parser}}.missing_option{|opt|
abort "ERROR : {{parser}} : missing_option : Argument was not provided to #{opt}"
abort "ERROR : {{@type.name}} : {{parser}} : missing_option : Argument was not provided to #{opt}"
}
{{parser}}.unknown_args{|opt|
unless opt.empty?
case opt.first
when /^-+[a-z-]+$/
Logger.debug "ERROR : {{parser}} : unknown_args : #{opt} not a configured argument"
STDERR.puts "ERROR : {{@type.name}} : {{parser}} : unknown_args : #{opt} not a configured argument"
else
abort "ERROR : {{parser}} : unknown_args : #{opt} not a configured argument"
abort "ERROR : {{@type.name}} : {{parser}} : unknown_args : #{opt} not a configured argument"
end
end
}

View File

@@ -14,6 +14,9 @@ module CliGen
annotation CommandArgument
end
annotation CommandSelection
end
annotation SubCommand
end
@@ -23,13 +26,18 @@ module CliGen
macro inherited
{% verbatim do %}
macro finished
define_actions
define_header
{% anno = @type.annotation(::CliGen::CommandInfo) %}
{% unless anno[:def_runner] == false %}
define_runner
{% end %}
define_parser
define_action_setter
end
{% end %}
end
macro define_actions
@@ -40,6 +48,7 @@ module CliGen
macro define_header
{% name = @type.name.split("::").last.downcase.id %}
{% info_annos = @type.class.methods.select(&.annotation(::CliGen::SubCommand)).map(&.annotation(::CliGen::SubCommand)) %}
{% info_annos += @type.class.methods.select(&.annotation(::CliGen::CommandSelection)).map(&.annotation(::CliGen::CommandSelection)) %}
{% examples = [] of StringLiteral %}
{% info_annos.select(&.[](:examples)).map(&.[](:examples).resolve).each(&.each{|example| examples << example}) %}
HEADER = [
@@ -55,9 +64,28 @@ module CliGen
].join("\n")
end
macro define_argument(arg_name, variable = nil, type = String, short = "", long = "", description = nil, subtype = Nil, format = nil, check = nil, def_getter = false, default = nil, logger = nil)
{% raise "define_argument : You must provide a format or set it to \"auto\" to use builtin formats when defining a Time argument" if type.id.stringify == "Time" && format == nil %}
{% raise "define_argument : You MUST provide a description" unless description %}
macro define_selection(selection_name, short = "", long = "", description = nil, default = "", values = [] of StringLiteral)
{% if values.is_a? Path %}
{% values = values.resolve %}
{% end %}
{% raise "ERROR : define_selection : You MUST provide a description" unless description %}
{% raise "ERROR : define_selection : You must provide a valid set of values in Array(String) format" if values.empty? %}
{% description = "#{description.id} (valid: #{values.join(", ").id})" %}
{% unless default.empty? %}
{% description = "#{description.id} (default: #{default.id})" %}
{% end %}
@@{{selection_name}} : String = {{default}}
@[::CliGen::CommandArgument(short: {{short}}, long: {{long}}, description: {{description}} )]
def self.{{selection_name}}= (selection : String)
raise "ERROR : {{selection_name}} : Invalid Selection(#{selection}) (valid: {{values.map(&.id).join(", ").id}})" unless {{values}}.includes?(selection)
@@{{selection_name}} = selection
end
end
macro define_argument(arg_name, variable = nil, type = String, short = "", long = "", description = nil, subtype = Nil, format = nil, check = nil, def_getter = false, default = nil, logger = nil, &block?)
{% raise "ERROR : define_argument : You must provide a format or set it to \"auto\" to use builtin formats when defining a Time argument" if type.id.stringify == "Time" && format == nil %}
{% raise "ERROR : define_argument : You MUST provide a description" unless description %}
{% variable = arg_name unless variable %}
{% _type = type.id.stringify %}
{% _subtype = subtype.id.stringify %}
@@ -86,9 +114,6 @@ module CliGen
{{check}}(var)
{% end %}
{% if format %}
abort "ERROR : Action : {{arg_name}} : Incorrect format for provided data #{var}" unless var =~ {{format}}
{% end %}
## If a logger method has been provided by the user
{% if logger %}
{{logger.id}} "Command : subclass : argument_setter : {{arg_name}} : Entered with #{var}"
@@ -132,13 +157,22 @@ module CliGen
{% end %}
{% end %}
{% selections = @type.class.methods.select(&.annotation(::CliGen::CommandSelection)) %}
{% methods = @type.class.methods.select(&.annotation(::CliGen::SubCommand)) %}
{% raise "ERROR : No commands defined for #{@type.name}" if methods.empty? %}
{% raise "ERROR : No commands or selections defined for #{@type.name}" if methods.empty? && selections.empty? %}
{% raise "ERROR : Can't define both selections and commands for work in #{@type.name}" if ! methods.empty? && ! selections.empty? %}
{% var = methods.empty? ? nil : "action" %}
{% targets = methods.empty? ? selections : methods %}
{% if targets == selections %}
{% selectors = selections.map(&.annotation(::CliGen::CommandSelection)).map(&.[:selector]).uniq %}
{% raise "ERROR : Can't provide more than a single selector for runner" if selectors.size > 1 %}
{% var = selectors.first %}
{% end %}
{% begin %}
case @@action
{% for method in methods %}
when {{method.name.stringify}}
{{method.name}}
case @@{{var.id}}
{% for target in targets %}
when {{target.name.stringify}}
{{target.name}}
{% end %}
else
abort "ERROR : No action provided to command {{@type.name}}"

View File

@@ -7,11 +7,24 @@ module CliGen::Parser
{% puts "#{@type.name} OptionParser is being generated" %}
{% name = @type.name.split("::").last %}
{% var = name.downcase %}
{% methods = @type.class.methods %}
{% info = @type.annotation(::CliGen::CommandInfo) %}
{% 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)) %}
{% selections = methods.select(&.annotation(::CliGen::CommandSelection)) %}
{% if selections.size > 0 %}
CliGen.define_section("Selections", parser)
{% for selection in selections %}
{% selection_anno = selection.annotation(::CliGen::CommandSelection) %}
parser.on({{selection.name.stringify}}, {{selection_anno[:description]}}){
{{@type.name}}.{{selection_anno[:selector]}}= {{selection.name.stringify}}
}
{% end %}
{% end %}
{% subcommands = methods.select(&.annotation(::CliGen::SubCommand)) %}
{% if subcommands.size > 0 %}
CliGen.define_section("Subcommands", parser)
{% for subcommand in subcommands %}
@@ -22,7 +35,7 @@ module CliGen::Parser
{% end %}
{% end %}
{% arguments = @type.class.methods.select(&.annotation(::CliGen::CommandArgument)) %}
{% arguments = methods.select(&.annotation(::CliGen::CommandArgument)) %}
{% if arguments.size > 0 %}
CliGen.define_section("Provide Arguments", parser)
{% for argument in arguments %}
@@ -41,7 +54,10 @@ module CliGen::Parser
CliGen.define_default_flags(parser)
end
parent_parser.on({{var}}, {{info[:description]}}){
ARGV.delete({{var}})
raise "ERROR : {{var.id}} not found in ARGV" unless i = ARGV.index({{var}})
## Removing all preceeding arguments so that only the actual required
## args for the next command are present
ARGV.shift(i+1)
abort subparser if ARGV.empty?
subparser.parse
{{@type.name}}.run