This commit is contained in:
Tristan Ancelet
2026-02-23 12:58:15 -06:00
parent b91ecad7e5
commit 9b50633c0e
6 changed files with 165 additions and 19 deletions

View File

@@ -3,6 +3,25 @@ require "option_parser"
module CliGenerator
VERSION = "0.1.0"
record AdditionalDefaultFlag,
short : String?,
long : String?,
description : String,
work : Proc(Nil)
private ADDITIONAL_DEFAULT_FLAGS = [] of AdditionalDefaultFlag
def self.add_default_flag(short : String? = nil, long : String? = nil, description : String? = nil, &work : -> )
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,
description: description,
work: work
)
end
annotation DefaultFlag
end
@@ -40,6 +59,11 @@ module CliGenerator
end
end
}
ADDITIONAL_DEFAULT_FLAGS.each do |flag|
args = [flag.short, flag.long, flag.description].reject(&.nil?)
{{parser}}.on(*args) &flag.work
end
end
macro define_root_parser

View File

@@ -33,23 +33,22 @@ module CliGenerator
end
macro define_actions
ACTIONS : Array(String) = {{@type.class.methods.select(&.annotation(::CliGenerator::SubCommand)).map(&.name.stringify)}}
ACTIONS = {{@type.class.methods.select(&.annotation(::CliGenerator::SubCommand)).map(&.name.stringify)}} of String
end
macro define_header
{% name = @type.name.split("::").last.downcase.id %}
{% info_annos = @type.class.methods.select(&.annotation(::CliGenerator::SubCommand)).map(&.annotation(::CliGenerator::SubCommand)) %}
{% examples = [] of StringLiteral %}
{% info_annos.select(&.[](:examples)).map(&.[](:examples).resolve).each(&.each{|example| examples << example}) %}
HEADER = [
"#{PROGRAM_NAME} {{name}} [[flags]]",
"",
{% unless info_annos.empty? %}
{% unless examples.empty? %}
"Examples:".colorize(:green),
"-------------------------------------------------------------------------------".colorize(:blue),
{% for anno in info_annos %}
{% examples = anno[:examples].resolve %}
{% for example in examples %}
{{example}},
{% end %}
{% for example in examples %}
{{example}},
{% end %}
{% end %}
].join("\n")
@@ -79,7 +78,7 @@ module CliGenerator
end
{% end %}
@[CommandArgument(type: {{type}}, short: {{short}}, long: {{long}}, description: {{description}})]
@[::CliGenerator::CommandArgument(type: {{type}}, short: {{short}}, long: {{long}}, description: {{description}})]
def self.{{arg_name}}(var : String) : Nil
{% if check %}
## If the check exists go ahead and call it

View File

@@ -1,12 +1,14 @@
module CliGenerator::Parser
macro extended
{% verbatim do %}
macro define_parser
def self.make_parser(parent_parser : OptionParser) : OptionParser
{% puts "#{@type.name} OptionParser is being generated" %}
{% name = @type.name.split("::").last %}
{% var = name.downcase %}
{% info = @type.annotation(::CliGenerator::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(::CliGenerator::SubCommand)) %}
@@ -46,6 +48,7 @@ module CliGenerator::Parser
}
end
end
{% end %}
end
end