Added format support for filtering arguments
This commit is contained in:
@@ -30,7 +30,8 @@ module CliGen
|
|||||||
validate: {% if anno[:validation] %} {{anno[:validation]}} {% else %} nil {% end %},
|
validate: {% if anno[:validation] %} {{anno[:validation]}} {% else %} nil {% end %},
|
||||||
on_match: {% if anno[:on_match] %} {{anno[:on_match]}} {% else %} nil {% end %},
|
on_match: {% if anno[:on_match] %} {{anno[:on_match]}} {% else %} nil {% end %},
|
||||||
options: {% if anno[:options] %} {{anno[:options]}} {% else %} nil {% end %},
|
options: {% if anno[:options] %} {{anno[:options]}} {% else %} nil {% end %},
|
||||||
delimiter: {% if anno[:delimiter] %} {{anno[:delimiter]}} {% else %} nil {% end %}
|
delimiter: {% if anno[:delimiter] %} {{anno[:delimiter]}} {% else %} nil {% end %},
|
||||||
|
format: {% if anno[:format] %} {{anno[:format]}} {% else %} nil {% end %}
|
||||||
)
|
)
|
||||||
{% debug if env("DEBUG") %}
|
{% debug if env("DEBUG") %}
|
||||||
{% end %}
|
{% end %}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
module CliGen
|
module CliGen
|
||||||
class Command
|
class Command
|
||||||
macro argument(variable, description, long = nil, short = nil, validation = nil, on_match = nil, def_setter = false, def_getter = false, options = nil, delimiter = ",")
|
macro argument(variable, description, long = nil, short = nil, validation = nil, on_match = nil, def_setter = false, def_getter = false, options = nil, delimiter = ",", format = nil)
|
||||||
{% raise "ERROR : CliGen::Command.argument : def_setter must be a Bool" unless def_setter.is_a? BoolLiteral %}
|
{% raise "ERROR : CliGen::Command.argument : def_setter must be a Bool" unless def_setter.is_a? BoolLiteral %}
|
||||||
{% raise "ERROR : CliGen::Command.argument : First argument (#{variable}) must be a TypeDeclaration (ex: '<var> : <type> [= val]')" unless variable.is_a? TypeDeclaration %}
|
{% raise "ERROR : CliGen::Command.argument : First argument (#{variable}) must be a TypeDeclaration (ex: '<var> : <type> [= val]')" unless variable.is_a? TypeDeclaration %}
|
||||||
{% name = variable.var %}
|
{% name = variable.var %}
|
||||||
@@ -37,8 +37,12 @@ module CliGen
|
|||||||
{% options = options.resolve if options.is_a? Path %}
|
{% options = options.resolve if options.is_a? Path %}
|
||||||
{% raise "ERROR : CliGen::Command.argument(#{name}) : Provided options must be an ArrayLiteral" unless options.is_a? ArrayLiteral %}
|
{% raise "ERROR : CliGen::Command.argument(#{name}) : Provided options must be an ArrayLiteral" unless options.is_a? ArrayLiteral %}
|
||||||
{% end %}
|
{% end %}
|
||||||
|
{% if format %}
|
||||||
|
{% format = format.resolve if format.is_a? Path %}
|
||||||
|
{% raise "ERROR : CliGen::Command.argument(#{name}) : Provided format must be a RegexLiteral" unless format.is_a? RegexLiteral %}
|
||||||
|
{% end %}
|
||||||
|
|
||||||
@[CliGen::Argument(short: {{short}}, long: {{long}}, description: {{description}}, validation: {{validation}}, on_match: {{on_match}}, options: {{options}}, delimiter: {{delimiter}})]
|
@[CliGen::Argument(short: {{short}}, long: {{long}}, description: {{description}}, validation: {{validation}}, on_match: {{on_match}}, options: {{options}}, delimiter: {{delimiter}}, format: {{format}})]
|
||||||
@{{variable}}
|
@{{variable}}
|
||||||
|
|
||||||
{% if def_getter %}
|
{% if def_getter %}
|
||||||
|
|||||||
+36
-13
@@ -87,8 +87,6 @@ module CliGen
|
|||||||
end
|
end
|
||||||
when CliGen::Regex::FLAG_WITH_ARG
|
when CliGen::Regex::FLAG_WITH_ARG
|
||||||
CliGen::MatchType::FlagWithArg
|
CliGen::MatchType::FlagWithArg
|
||||||
when CliGen::Regex::SHORT_WITH_INLINE_ARG
|
|
||||||
CliGen::MatchType::ShortWithInlineArg
|
|
||||||
when CliGen::Regex::FLAG_MULTIPLE_SHORT
|
when CliGen::Regex::FLAG_MULTIPLE_SHORT
|
||||||
CliGen::MatchType::FlagMultipleShort
|
CliGen::MatchType::FlagMultipleShort
|
||||||
else
|
else
|
||||||
@@ -108,7 +106,7 @@ module CliGen
|
|||||||
subcommands.any?{|f| f.name == arg}
|
subcommands.any?{|f| f.name == arg}
|
||||||
end
|
end
|
||||||
|
|
||||||
def flag?(arg : String) : BaseFlag
|
def flag?(arg : String) : Bool
|
||||||
@flags.any?(&.matches?(arg))
|
@flags.any?(&.matches?(arg))
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -221,17 +219,43 @@ module CliGen
|
|||||||
raise "Oh good, you broke regex. How the hell did it match in find_match but not above? What the hell is going on"
|
raise "Oh good, you broke regex. How the hell did it match in find_match but not above? What the hell is going on"
|
||||||
end
|
end
|
||||||
|
|
||||||
when MatchType::ShortWithInlineArg
|
|
||||||
abort "#{CliGen::APPNAME}: invalid flag '#{arg.value}' — inline values are not supported. Did you mean '#{arg.value[0..1]} #{arg.value[2..]}' ?"
|
|
||||||
|
|
||||||
when MatchType::FlagMultipleShort
|
when MatchType::FlagMultipleShort
|
||||||
arg.value.gsub(/^-/, "").chars.map { |c| "-#{c}" }.each do |flag|
|
val = arg.value.gsub(/^-/,"")
|
||||||
case match = find_match(flag)
|
|
||||||
|
# If the next character in the series is a flag assume the remaining are flags as well.
|
||||||
|
if flag?("-#{val[1]}")
|
||||||
|
chars = val.chars
|
||||||
|
chars.map { |c| "-#{c}" }.each do |flag|
|
||||||
|
case match = find_match(flag)
|
||||||
|
when BaseFlag
|
||||||
|
# If this is the last flag in the series let it process others
|
||||||
|
if flag == "-#{chars.last}"
|
||||||
|
if match.requires_arg?
|
||||||
|
match.process(args.reject(&.processed?))
|
||||||
|
else
|
||||||
|
match.process
|
||||||
|
end
|
||||||
|
else
|
||||||
|
abort "#{CliGen::APPNAME}: cannot bundle flag that requires an argument: #{flag}" if match.requires_arg?
|
||||||
|
match.process
|
||||||
|
end
|
||||||
|
when MatchType::NoMatch
|
||||||
|
abort "ERROR : CommandNode(#{@name}).process : No flag match for '#{flag}'"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
# In this case we assume the characters following the flag is the argument
|
||||||
|
flg = "-#{val[0]}"
|
||||||
|
argument = Arg.new(value: val[1..], index: 0)
|
||||||
|
case match = find_match(flg)
|
||||||
when BaseFlag
|
when BaseFlag
|
||||||
abort "#{CliGen::APPNAME}: cannot bundle flag that requires an argument: #{flag}" if match.requires_arg?
|
if match.requires_arg?
|
||||||
match.process
|
match.process([argument])
|
||||||
|
else
|
||||||
|
abort "ERROR : CommandNode(#{@name}).process : Unknown characters proceeding a boolean flag(#{flg}) : #{val[1..]}"
|
||||||
|
end
|
||||||
when MatchType::NoMatch
|
when MatchType::NoMatch
|
||||||
raise "ERROR : CommandNode(#{@name}).process : No flag match for '#{flag}'"
|
abort "ERROR : CommandNode(#{@name}).process : No flag match for '#{arg.value}'"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -246,8 +270,7 @@ module CliGen
|
|||||||
{% unless T == Nil %}
|
{% unless T == Nil %}
|
||||||
unless passed_execution
|
unless passed_execution
|
||||||
cls = T.new(handler: self.as(CliGen::BaseCommandNode))
|
cls = T.new(handler: self.as(CliGen::BaseCommandNode))
|
||||||
{% prerun = T.methods.select(&.annotation(CliGen::PreRunCommand)) %}
|
{% for cmd in T.methods.select(&.annotation(CliGen::PreRunCommand)) %}
|
||||||
{% for cmd in prerun %}
|
|
||||||
cls.{{cmd.name}}
|
cls.{{cmd.name}}
|
||||||
{% end %}
|
{% end %}
|
||||||
{% subcmds = T.methods.select(&.annotation(CliGen::SubCommand)) %}
|
{% subcmds = T.methods.select(&.annotation(CliGen::SubCommand)) %}
|
||||||
|
|||||||
+6
-1
@@ -42,6 +42,7 @@ module CliGen
|
|||||||
@options : Array(T)?
|
@options : Array(T)?
|
||||||
@validate : (T -> Bool)?
|
@validate : (T -> Bool)?
|
||||||
@on_match : Proc(Nil)?
|
@on_match : Proc(Nil)?
|
||||||
|
@format : ::Regex?
|
||||||
|
|
||||||
def initialize(
|
def initialize(
|
||||||
var : String,
|
var : String,
|
||||||
@@ -53,7 +54,8 @@ module CliGen
|
|||||||
@default : T? = nil,
|
@default : T? = nil,
|
||||||
@options : Array(T)? = nil,
|
@options : Array(T)? = nil,
|
||||||
@validate : (T -> Bool)? = nil,
|
@validate : (T -> Bool)? = nil,
|
||||||
@on_match : Proc(Nil)? = nil
|
@on_match : Proc(Nil)? = nil,
|
||||||
|
@format : ::Regex? = nil
|
||||||
)
|
)
|
||||||
super(var, short, long, env_var, description, delimiter)
|
super(var, short, long, env_var, description, delimiter)
|
||||||
end
|
end
|
||||||
@@ -76,6 +78,9 @@ module CliGen
|
|||||||
{% elem = T.type_vars.first %}
|
{% elem = T.type_vars.first %}
|
||||||
argv.each do |arg|
|
argv.each do |arg|
|
||||||
break if arg.flag?
|
break if arg.flag?
|
||||||
|
unless @format.nil?
|
||||||
|
break unless arg.value =~ @format
|
||||||
|
end
|
||||||
{% if elem == Int32 %}
|
{% if elem == Int32 %}
|
||||||
abort "ERROR : Flag({{T}}) : Provided arguemnt(#{arg.value}) was not an integer" unless arg.int?
|
abort "ERROR : Flag({{T}}) : Provided arguemnt(#{arg.value}) was not an integer" unless arg.int?
|
||||||
(@value ||= [] of Int32) << arg.value.to_i
|
(@value ||= [] of Int32) << arg.value.to_i
|
||||||
|
|||||||
+2
-3
@@ -1,8 +1,7 @@
|
|||||||
module CliGen::Regex
|
module CliGen::Regex
|
||||||
FLAG_REGEX=/^(-[a-zA-Z]|--[a-zA-Z-_0-9]+)/
|
FLAG_REGEX=/^(-[a-zA-Z]|--[a-zA-Z-_0-9]+)$/
|
||||||
FLAG_WITH_ARG=/^(?<flag>(-[a-zA-Z]|--[a-zA-Z-_]+))="?(?<arg>\S+?)"?$/
|
FLAG_WITH_ARG=/^(?<flag>(-[a-zA-Z]|--[a-zA-Z-_]+))="?(?<arg>\S+?)"?$/
|
||||||
FLAG_MULTIPLE_SHORT=/^-[a-zA-Z]+$/
|
FLAG_MULTIPLE_SHORT=/^-[a-zA-Z0-9]+/
|
||||||
SHORT_WITH_INLINE_ARG=/^-[a-zA-Z][a-zA-Z0-9]+$/
|
|
||||||
|
|
||||||
INPUT_DATETIME_REGEX = /^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}$/
|
INPUT_DATETIME_REGEX = /^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}$/
|
||||||
INPUT_DATE_REGEX = /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/
|
INPUT_DATE_REGEX = /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/
|
||||||
|
|||||||
Reference in New Issue
Block a user