Top Level Namespace
Defined Under Namespace
Classes: Arg, BaseOptArg, NoTarget, Option
Instance Method Summary collapse
- #access(*types) ⇒ Object
- #arg(name, &b) ⇒ Object
- #at_least(n) ⇒ Object
- #c_string ⇒ Object
- #check_conflict_exclude ⇒ Object
- #conflict(*a) ⇒ Object
- #default(str) ⇒ Object
- #default_val(val, type, *argv) ⇒ Object
- #description(str) ⇒ Object
- #dflt_typestr(type, *argv) ⇒ Object
- #display_man_page(out) ⇒ Object
- #display_stub_yaggo_file(file) ⇒ Object
- #double ⇒ Object
- #enum(*argv) ⇒ Object
- #find_error_header(bt) ⇒ Object
- #flag ⇒ Object
- #hidden ⇒ Object
- #imply(*a) ⇒ Object
- #int ⇒ Object
-
#int32 ⇒ Object
def set_type t raise “More than 1 type specified: ‘#$target$target.type’ and ‘#t’” unless $target.type.nil? $target.type = t end.
- #int64 ⇒ Object
- #license(str) ⇒ Object
- #long ⇒ Object
- #main ⇒ Object
- #multiple ⇒ Object
- #name(str) ⇒ Object
- #no ⇒ Object
- #off ⇒ Object
- #on ⇒ Object
- #option(name1, name2 = nil, &b) ⇒ Object
- #output(str) ⇒ Object
- #output_conversion_code(file) ⇒ Object
- #output_cpp_parser(h, class_name) ⇒ Object
- #output_options_descriptions(out, opts, hidden) ⇒ Object
- #output_zsh_completion(fd, filename) ⇒ Object
- #package(str) ⇒ Object
- #posix(*args) ⇒ Object
- #purpose(str) ⇒ Object
-
#quote_newline_dquotes(str, spaces = "") ⇒ Object
You should have received a copy of the GNU General Public License along with Yaggo.
- #required ⇒ Object
- #run_block(name, b) ⇒ Object
- #secret ⇒ Object
- #str_conv(arg, type, *argv) ⇒ Object
- #string ⇒ Object
- #suffix ⇒ Object
- #suffix_arg(suffix) ⇒ Object
- #text(str) ⇒ Object
- #typestr(str) ⇒ Object
- #uint32 ⇒ Object
- #uint64 ⇒ Object
- #usage(str) ⇒ Object
- #version(str) ⇒ Object
- #zsh_conflict_option(o) ⇒ Object
- #zsh_switches_option(o) ⇒ Object
- #zsh_type_completion(o, with_type = true) ⇒ Object
Instance Method Details
#access(*types) ⇒ Object
77 |
# File 'lib/yaggo/dsl.rb', line 77 def access *types; $target.access= types; end |
#arg(name, &b) ⇒ Object
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 |
# File 'lib/yaggo/dsl.rb', line 559 def arg(name, &b) a = Arg.new(name) $args.any? { |la| la.name == name } and raise "#{b.source_location.join(":")}: Arg '#{name}' already exists" $args << a $target = a name = "Arg #{name}" run_block(name, b) $target = NoTarget.new begin a.check rescue => e raise "#{b.source_location.join(":")}: #{e.}" end end |
#at_least(n) ⇒ Object
74 |
# File 'lib/yaggo/dsl.rb', line 74 def at_least n; $target.at_least = n; end |
#c_string ⇒ Object
60 |
# File 'lib/yaggo/dsl.rb', line 60 def c_string; $target.type = :c_string; end |
#check_conflict_exclude ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/yaggo/general.rb', line 108 def check_conflict_exclude $options.each { |o| $opt_hash[o.long] = o unless o.long.nil? $opt_hash[o.short] = o unless o.short.nil? } $options.each { |o| o.conflict.each { |co| $opt_hash[co] or raise "Unknown conflict option '#{co}' for switch #{o.long}|#{o.short}" } } $options.each { |o| o.imply.each { |ios| io = $opt_hash[ios] or raise "Unknown implied option '#{io}' for switch #{o.long}|#{o.short}" io.type == :flag or raise "Implied option '#{io}' for switch #{o.long}|#{o.short} is not a flag" } } end |
#conflict(*a) ⇒ Object
75 |
# File 'lib/yaggo/dsl.rb', line 75 def conflict *a; $target.conflict= a; end |
#default(str) ⇒ Object
71 |
# File 'lib/yaggo/dsl.rb', line 71 def default str; $target.default = str; end |
#default_val(val, type, *argv) ⇒ Object
84 85 86 87 88 89 90 91 92 93 |
# File 'lib/yaggo/dsl.rb', line 84 def default_val(val, type, *argv) case type when :string, :c_string "\"#{val || $type_default[type]}\"" when :uint32, :uint64, :int32, :int64, :int, :long, :double val ? "(#{$type_to_C_type[type]})#{val}" : $type_default[type] else val.to_s || $type_default[type] end end |
#description(str) ⇒ Object
39 |
# File 'lib/yaggo/dsl.rb', line 39 def description str; $target.description = str; end |
#dflt_typestr(type, *argv) ⇒ Object
45 46 47 48 49 50 51 52 53 54 |
# File 'lib/yaggo/general.rb', line 45 def dflt_typestr(type, *argv) case type when :c_string "string" when :enum argv[0].join("|") else type.to_s end end |
#display_man_page(out) ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 |
# File 'lib/yaggo/man_page.rb', line 18 def display_man_page out manual = <<EOS .TH yaggo 1 "2015-06-24" "version #{$yaggo_version}" "USER COMMANDS" .SH NAME yaggo \- command line switch parser generator .SH SYNOPSIS .B yaggo [-o|--output FILE] [-l|--license PATH] [-s|--stub] [--zc PATH] [-e|--extended-syntax] [--man] [-h|--help] .SH DESCRIPTION Yaggo stands for Yet Another GenGetOpt. It is inspired by gengetopt software from the FSF. Yaggo generates a C++ class to parse command line switches (usually argc and argv passed to main) using getopt_long. The switches and arguments to the program are specified in a description file. To each description file, yaggo generates one C++ header file containing the parsing code. .PP See the EXAMPLES section for a complete and simple example. .SH OPTIONS .TP \-l|\-\-license Display the file at the top of the generated headers. It usually contains the license governing the distribution of the headers. .TP -m|\-\-man Display this man page .TP \-s|\-\-stub Generate a stub: a simple yaggo file that can be modified for one's use. .TP \-e|--extended-syntax Use the extended syntax: blocks can be defined on the next line of a command. .TP \-h|--help Display a short help text .PP .SH EXAMPLE Consider the description files 'example_args.yaggo' which defines a switch "-i" (or "--int") that takes an unsigned integer and defaults to 42; a switch "-s" (or "--string") that takes a string and can be given multiple times; a switch "--flag" which does not take any argument; a switch "--severity" which can take only 3 values: "low", "middle" and "high". It takes the following arguments: a string followed by zero or more floating point numbers. .nf purpose "Example of yaggo usage" package "example" description "This is just an example. And a multi-line description." option("int", "i") { description "Integer switch" uint32; default "42" } option("string", "s") { description "Many strings" string; multiple } option("flag") { description "A flag switch" flag; off } option("severity") { description "An enum switch" enum "low", "middle", "high" } arg("first") { description "First arg" c_string } arg("rest") { description "Rest of'em" double; multiple } .fi The associated simple C++ program 'examples.cpp' which display information about the switches and arguments passed: .nf #include <iostream> #include "example_args.hpp" int main(int argc, char *argv[]) { example_args args(argc, argv); std::cout << "Integer switch: " << args.int_arg << "\\\\n"; if(args.string_given) std::cout << "Number of string(s): " << args.string_arg.size() << "\\\\n"; else std::cout << "No string switch\\\\n"; std::cout << "Flag is " << (args.flag_flag ? "on" : "off") << "\\\\n"; std::cout << "First arg: " << args.first_arg << "\\\\n"; std::cout << "Severity arg: " << args.severity_arg << " " << example_args::severity::strs[args.severity_arg] << "\\\\n"; if(args.severity_arg == example_args::severity::high) std::cout << "Warning: severity is high\\\\n"; std::cout << "Rest:"; for(example_args::rest_arg_it it = args.rest_arg.begin(); it != args.rest_arg.end(); ++it) std::cout << " " << *it; std::cout << std::endl; return 0; } .fi This can be compiled with the following commands: .nf % yaggo example_args.yaggo % g++ -o example example.cpp .fi The yaggo command above will create by default the file 'example_args.hpp' (changed '.yaggo' extension to '.hpp'). The output file name can be changed with the 'output' keyword explained below. .SH DESCRIPTION FORMAT A description file is a sequence of statements. A statement is a keyword followed by some arguments. Strings must be surrounded by quotes ("" or '') and can span multiple lines. The order of the statements is irrelevant. Statements are separated by new lines or semi-colons ';'. .IP * Technically speaking, yaggo is implemented as a DSL (Domain Specific Language) using ruby. The description file is a valid ruby script and the keywords are ruby functions. .PP The following statements are global, not attached to a particular option or argument. .TP purpose A one line description of the program. .TP package The name of the package for the usage string. Defaults to the name of the class. .TP usage The usage string. If none given a standard one is generated by yaggo. .TP description A longer description of the program displayed before the list of switch. Displayed by the help. .TP text Some text to be displayed after the list of switches. Displayed by the help. .TP version The version string of the software. .TP license The license and copyright string of the software. .TP name The name of the class generated. Defaults to the name of the description file minus the .yaggo extension. .TP posix Posix correct behavior (instead of GNU behavior): switch processing stops at the first non-option argument .TP output The name of the output file. Defaults to the name of the description file with the .yaggo extension changed to .hpp. .PP The 'option' statement takes one or two arguments, which must be in parentheses, and a block of statements surrounded by curly braces ({...}). The arguments are the long and short version of the option. Either one of the long or short version can be omitted. The block of statements describe the option in more details, as described below. A switch is named after the long version, or the short version if no long version. An 'option' statement for an option named 'switch' defines one or two public members in the class. For a flag, it creates 'switch_flag' as a boolean. Otherwise, it creates 'switch_arg', with a type as specified, and 'switch_given', a boolean indicating whether or not the switch was given on the command line. For example, the statement: .nf option("integer", "i") { int; default 5 } .fi will add the following members to the C++ class: .nf int integer_arg; bool integer_given; .fi where "integer_arg" is initialized to 5 and "integer_given" is initialized to "false". If the switch "--integer 10" or "-i 10" is passed on the command line "integer_arg" is set to 10 and integer_given is set to "true". The statement: .nf option("verbose") { off } .fi will add the following member to the C++ class: .nf bool verbose_flag; .fi where "verbose_flag" is initialized to "false". Passing the switch "--verbose" on the command line sets "verbose_flag" to true". In addition to the switch created by 'option', the following switches are defined by default (unless some option statement overrides them): .TP \-h, \-\-help Display the help message. .TP \-\-full\-help Display hidden options as well. .TP \-\-version Display version string. .PP The following statement are recognized in an option block: .TP description "str" A short description for this switch. .TP int32, int64, uint32, uint64, double, int, long This switch is parsed as a number with the corresponding type int32_t, int64_t, uint32_t, uint64_t, double, int and long. .TP suffix Valid for numerical type switches as above. It can be appended with a SI suffix (e.g. 1M mean 1000000). The suffixes k, M, G, T, P, and E are supported for all the numerical types. The suffixes m, u, n, p, f, and a are supported for the double type. .TP c_string, string This switch is taken as a C string (const char *) or a C++ string (inherits from std::string). The C++ string type has the extra methods '<type> as_<type>(bool suffix)', where <type> is any numerical type as above, to convert the string into that type. If the 'suffix' boolean is true, parsing is done using SI suffixes. .TP enum This statement must be followed by a comma separated list of strings (as in 'enum "choice0", "choice1", "choice2"'). This switch takes value a string in the list and is converted to int. C enum type named "switchname::enum" is defined with the same choices in the given order. .TP required This switch is required. An error is generated if not given on the command line. .TP conflict Specify a comma separated list of switches that conflicts with this one. .TP imply Specify a comma separated list of switches (of type flag) which are implied by this one. .TP hidden This switch is not shown with --help. Use --full-help to see the hidden switches, if any. .TP secret This switch is not shown in any help message. Neither --help nor --full-help. .TP multiple This switch can be passed multiple times. The values are stored in a std::vector. A type for the iterator is also defined in the class with the name 'switch_arg_it', where 'switch' is the name of the option. .TP flag This switch is a flag and does not take an argument. .TP on, off The default state for a flag switch. Implies flag. Unless the 'no' option is used (see below), with 'off', the default value of the flag is "false" and passing --flag sets it to true. With 'on', the default value of the flag is "true" and passing --flag sets it to false. .TP no A flag with two switches. If the switch is named "flag", two switches are generated: --flag and --noflag, respectively setting it to "true" and "false". The 'on' and 'off' options define the default value. .TP default "val" The default value for this switch. It can be a string or a valid number. SI suffixes are supported as well (for example "1M" means 1 m`illion). .TP typestr "str" In the help message, by default, the type of the option is displayed. It can be replaced by the string given to 'typestr'. .TP at_least n The given switch must be given at least n times. Implies multiple. .TP access "type" Make sure that the string passed is a path to which we have access. "type" is a comma separated list of "read", "write" or "exec". It is checked with access(2). The same warning applies: "Warning: Using access() to check if a user is authorized to, for example, open a file before actually doing so using open(2) creates a security hole, because the user might exploit the short time interval between checking and opening the file to manipulate it. For this reason, the use of this system call should be avoided. (In the example just described, a safer alternative would be to temporarily switch the process's effective user ID to the real ID and then call open(2).)" .PP A 'arg' statement defines an arg passed to the command line. The statement takes a single argument, the name of the arg, and a block of statements. The block of statements are similar to the option block, except that "hidden", "flag", "on", "off" and "no" are not allowed. At most one arg can have the 'multiple' statement, and it must be the last one. .SH EXAMPLE USAGE The argument object parses the switches on construction or later on using the parse method. For example, the two pieces code show these two different usage. Using parse method: .nf example_args args; // Global variable with switches int main(int argc, char* argv[]) { args.parse(argc, argv); } .fi Parse on construction: .nf int main(int argc, char* argv[]) { example_args args(argc, argv); } .fi The subclass error can be used to output error messsage (and terminate program). It output an error message, the usage string, etc. The error class behave like an output stream, it can be used to create complicated error message. For example: .nf if(false_condition) example_args::error() << "Failed to open file '" << args.file_arg << "'"; .fi An error object prints an error message and terminate the program with exit upon destruction. An exit code can be passed to error. By default the exit code (passed to exit) is the constant EXIT_FAILURE (normally 1). For example: .nf example_args::error(77) << "Failed with return code 77"; .fi .SH LICENSE There are 2 parts to the software: the yaggo ruby script itself, and the header files generated by yaggo from the description files. The licenses are as follow: .TP yaggo the ruby script This software is licensed under the GNU General Public License version 3 or any later version. Copyright (c) 2011 Guillaume Marcais. .TP The generated header files. These files have the license and copyright that you, the user of yaggo, assign with the 'license' keyword. .PP In short: only yaggo the software is GPL. The generated header files are considered derivative of your work (e.g. the description), and you define the copyright and license of those as you see fit. .SH BUGS .IP * The error message returned by ruby can be a little confusing. .SH AUTHOR Guillaume Marcais ([email protected]) .SH SEE ALSO getopt_long(3), gengetopt(1), exit(2) EOS if !out && STDOUT.isatty require 'tempfile' Tempfile.open("yaggo_man") do |fd| begin fd.write(manual) fd.flush system("man", fd.path) ensure fd.unlink end end elsif !out STDOUT.puts(manual) else path = Pathname.new(out) path.write manual end end |
#display_stub_yaggo_file(file) ⇒ Object
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/yaggo/stub.rb', line 17 def display_stub_yaggo_file file stub = <<EOS # Stub file generated by yaggo. Modify to your liking purpose = "Foo software to do bar and baz, one line description" description = "A longer multiline description of how Foo does bar and baz Really, it works great, you should try all the options below " option("b", "bar") { description "Insist on bar" flag } option("z", "baz") { description "Baz parameter" int64; default "5" } option("l", "long") { description "Long switch can be used multiple time" int32; multiple } arg("OneArg") { description "first arg" string } EOS out = file ? open(file, "W") : STDOUT out.write(stub) end |
#double ⇒ Object
58 |
# File 'lib/yaggo/dsl.rb', line 58 def double; $target.type = :double; end |
#enum(*argv) ⇒ Object
62 |
# File 'lib/yaggo/dsl.rb', line 62 def enum(*argv); $target.type = :enum; $target.enum = argv; end |
#find_error_header(bt) ⇒ Object
87 88 89 90 |
# File 'lib/yaggo/general.rb', line 87 def find_error_header bt bt.each { |l| l =~ /^\(eval\):\d+:/ and return $& } return "" end |
#flag ⇒ Object
61 |
# File 'lib/yaggo/dsl.rb', line 61 def flag; $target.type = :flag; end |
#hidden ⇒ Object
66 |
# File 'lib/yaggo/dsl.rb', line 66 def hidden; $target.hidden = true; end |
#imply(*a) ⇒ Object
76 |
# File 'lib/yaggo/dsl.rb', line 76 def imply *a; $target.imply= a; end |
#int ⇒ Object
56 |
# File 'lib/yaggo/dsl.rb', line 56 def int; $target.type = :int; end |
#int32 ⇒ Object
def set_type t
raise "More than 1 type specified: '#{$target.type}' and '#{t}'" unless $target.type.nil?
$target.type = t
end
52 |
# File 'lib/yaggo/dsl.rb', line 52 def int32; $target.type = :int32; end |
#int64 ⇒ Object
53 |
# File 'lib/yaggo/dsl.rb', line 53 def int64; $target.type = :int64; end |
#license(str) ⇒ Object
42 |
# File 'lib/yaggo/dsl.rb', line 42 def license str; $license = str; end |
#long ⇒ Object
57 |
# File 'lib/yaggo/dsl.rb', line 57 def long; $target.type = :long; end |
#main ⇒ Object
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/yaggo/main.rb', line 27 def main $yaggo_options = { :output => nil, :license => nil, :stub => false, :zc => nil, :extended => false, :debug => false, } parser = OptionParser.new do |o| o.version = $yaggo_version o. = "Usage: #{$0} [options] [file.yaggo]" o.separator "" o.separator "Specific options:" o.on("-o", "--output FILE", "Output file") { |v| $yaggo_options[:output] = v } o.on("-l", "--license PATH", "License file to copy in header") { |v| $yaggo_options[:license] = v } o.on("-m", "--man [FILE]", "Display or write manpage") { |v| display_man_page v exit 0; } o.on("-s", "--stub", "Output a stub yaggo file") { $yaggo_options[:stub] = true } o.on("--zc PATH", "Write zsh completion file") { |v| $yaggo_options[:zc] = v } o.on("-e", "--extended-syntax", "Use extended syntax") { $yaggo_options[:extended] = true } o.on("--debug", "Debug yaggo") { $yaggo_options[:debug] = true } o.on_tail("-h", "--help", "Show this message") { puts o exit 0 } end parser.parse! ARGV if $yaggo_options[:stub] begin display_stub_yaggo_file $yaggo_options[:output] rescue => e STDERR.puts("Failed to write stub: #{e.}") exit 1 end exit end if !$yaggo_options[:stub] && !$yaggo_options[:manual] && ARGV.empty? STDERR.puts "Error: some yaggo files and/or --lib switch is required", parser exit 1 end if !$yaggo_options[:output].nil? if $yaggo_options[:stub] if ARGV.size > 0 STDERR.puts "Error: no input file needed with the --stub switch", parser exit 1 end elsif ARGV.size != 1 STDERR.puts "Error: output switch meaningfull only with 1 input file", parser exit 1 end end ARGV.each do |input_file| pid = fork do begin yaggo_script = File.read(input_file) if $yaggo_options[:extended] yaggo_script.gsub!(/\)\s*\n\s*\{/, ") {") end eval(File.read(input_file)) parsed = true check_conflict_exclude rescue RuntimeError, SyntaxError, Errno::ENOENT, Errno::EACCES => e raise e if $yaggo_options[:debug] STDERR.puts(e..gsub(/^\(eval\)/, input_file)) exit 1 rescue NoMethodError => e raise e if $yaggo_options[:debug] STDERR.puts("Invalid keyword '#{e.name}'") exit 1 end fsplit = File.basename(input_file).split(/\./) $klass ||= fsplit.size > 1 ? fsplit[0..-2].join(".") : fsplit[0] $output = $yaggo_options[:output] if $yaggo_options[:output] $output ||= input_file.gsub(/\.yaggo$/, "") + ".hpp" begin out_fd = open($output, "w") output_cpp_parser(out_fd, $klass) rescue RuntimeError => e raise e if $yaggo_options[:debug] STDERR.puts("#{input_file}: #{e.}") exit 1 ensure out_fd.close if out_fd end if $yaggo_options[:zc] begin out_fd = open($yaggo_options[:zc], "w") output_zsh_completion(out_fd, $yaggo_options[:zc]) rescue RuntimeError => e raise e if $yaggo_options[:debug] STDERR.puts("#{input_file}: #{e.}") exit 1 ensure out_fd.close if out_fd end end end Process.waitpid pid exit 1 if !$?.exited? || ($?.exited? && $?.exitstatus != 0) end end |
#multiple ⇒ Object
73 |
# File 'lib/yaggo/dsl.rb', line 73 def multiple; $target.multiple = true; end |
#name(str) ⇒ Object
34 |
# File 'lib/yaggo/dsl.rb', line 34 def name str; $klass = str; end |
#no ⇒ Object
70 |
# File 'lib/yaggo/dsl.rb', line 70 def no; $target.no; end |
#off ⇒ Object
69 |
# File 'lib/yaggo/dsl.rb', line 69 def off; $target.off; end |
#on ⇒ Object
68 |
# File 'lib/yaggo/dsl.rb', line 68 def on; $target.on; end |
#option(name1, name2 = nil, &b) ⇒ Object
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 |
# File 'lib/yaggo/dsl.rb', line 529 def option(name1, name2 = nil, &b) long = short = nil if name1 =~ /^--/ || name1.length >= 2 long, short = name1, name2 elsif !name2.nil? && (name2 =~ /^--/ || name2.length >= 2) long, short = name2, name1 else long, short = nil, name1 end long.gsub!(/^--/, "") unless long.nil? short.gsub!(/^-/, "") unless short.nil? o = Option.new(long, short) $options.each { |lo| if (!long.nil? && lo.long == long) || (!short.nil? && lo.short == short) raise "#{b.source_location.join(":")}: Option #{long}|#{short} conflicts with existing option #{lo.long}|#{lo.short}" end } $options << o $target = o name = "Option #{long || ""}|#{short || ""}" run_block(name, b) $target = NoTarget.new begin o.check rescue => e raise "#{b.source_location.join(":")}: #{e.}" end end |
#output(str) ⇒ Object
33 |
# File 'lib/yaggo/dsl.rb', line 33 def output str; $output = str; end |
#output_conversion_code(file) ⇒ Object
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/yaggo/library.rb', line 17 def output_conversion_code file file.puts(<<EOS) static bool adjust_double_si_suffix(double &res, const char *suffix) { if(*suffix == '\\0') return true; if(*(suffix + 1) != '\\0') return false; switch(*suffix) { case 'a': res *= 1e-18; break; case 'f': res *= 1e-15; break; case 'p': res *= 1e-12; break; case 'n': res *= 1e-9; break; case 'u': res *= 1e-6; break; case 'm': res *= 1e-3; break; case 'k': res *= 1e3; break; case 'M': res *= 1e6; break; case 'G': res *= 1e9; break; case 'T': res *= 1e12; break; case 'P': res *= 1e15; break; case 'E': res *= 1e18; break; default: return false; } return true; } static double conv_double(const char *str, ::std::string &err, bool si_suffix) { char *endptr = 0; errno = 0; double res = strtod(str, &endptr); if(endptr == str) { err.assign("Invalid floating point string"); return (double)0.0; } if(errno) { err.assign(strerror(errno)); return (double)0.0; } bool invalid = si_suffix ? !adjust_double_si_suffix(res, endptr) : *endptr != '\\0'; if(invalid) { err.assign("Invalid character"); return (double)0.0; } return res; } static int conv_enum(const char* str, ::std::string& err, const char* const strs[]) { int res = 0; for(const char* const* cstr = strs; *cstr; ++cstr, ++res) if(!strcmp(*cstr, str)) return res; err += "Invalid constant '"; err += str; err += "'. Expected one of { "; for(const char* const* cstr = strs; *cstr; ++cstr) { if(cstr != strs) err += ", "; err += *cstr; } err += " }"; return -1; } template<typename T> static bool adjust_int_si_suffix(T &res, const char *suffix) { if(*suffix == '\\0') return true; if(*(suffix + 1) != '\\0') return false; switch(*suffix) { case 'k': res *= (T)1000; break; case 'M': res *= (T)1000000; break; case 'G': res *= (T)1000000000; break; case 'T': res *= (T)1000000000000; break; case 'P': res *= (T)1000000000000000; break; case 'E': res *= (T)1000000000000000000; break; default: return false; } return true; } template<typename T> static T conv_int(const char *str, ::std::string &err, bool si_suffix) { char *endptr = 0; errno = 0; long long int res = strtoll(str, &endptr, 0); if(endptr == str) { err.assign("Invalid signed int string"); return (T)0; } if(errno) { err.assign(strerror(errno)); return (T)0; } bool invalid = si_suffix ? !adjust_int_si_suffix(res, endptr) : *endptr != '\\0'; if(invalid) { err.assign("Invalid character"); return (T)0; } if(res > ::std::numeric_limits<T>::max() || res < ::std::numeric_limits<T>::min()) { err.assign("Value out of range"); return (T)0; } return (T)res; } template<typename T> static T conv_uint(const char *str, ::std::string &err, bool si_suffix) { char *endptr = 0; errno = 0; while(isspace(*str)) { ++str; } if(*str == '-') { err.assign("Negative value"); return (T)0; } unsigned long long int res = strtoull(str, &endptr, 0); if(endptr == str) { err.assign("Invalid unsigned int string"); return (T)0; } if(errno) { err.assign(strerror(errno)); return (T)0; } bool invalid = si_suffix ? !adjust_int_si_suffix(res, endptr) : *endptr != '\\0'; if(invalid) { err.assign("Invalid character"); return (T)0; } if(res > ::std::numeric_limits<T>::max()) { err.assign("Value out of range"); return (T)0; } return (T)res; } template<typename T> static ::std::string vec_str(const std::vector<T> &vec) { ::std::ostringstream os; for(typename ::std::vector<T>::const_iterator it = vec.begin(); it != vec.end(); ++it) { if(it != vec.begin()) os << ","; os << *it; } return os.str(); } class string : public ::std::string { public: string() : ::std::string() {} explicit string(const ::std::string &s) : std::string(s) {} explicit string(const char *s) : ::std::string(s) {} int as_enum(const char* const strs[]) { ::std::string err; int res = #{str_conv("this->c_str()", :enum, "strs")}; if(!err.empty()) throw ::std::runtime_error(err); return res; } EOS [:uint32, :uint64, :int32, :int64, :int, :long, :double].each do |type| file.puts(<<EOS) #{$type_to_C_type[type]} as_#{type}_suffix() const { return as_#{type}(true); } #{$type_to_C_type[type]} as_#{type}(bool si_suffix = false) const { ::std::string err; #{$type_to_C_type[type]} res = #{str_conv("this->c_str()", type, "si_suffix")}; if(!err.empty()) { ::std::string msg("Invalid conversion of '"); msg += *this; msg += "' to #{type}_t: "; msg += err; throw ::std::runtime_error(msg); } return res; } EOS end file.puts(<<EOS) }; EOS # } end |
#output_cpp_parser(h, class_name) ⇒ Object
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 |
# File 'lib/yaggo/parser.rb', line 34 def output_cpp_parser(h, class_name) $options.each { |o| o.check } $args.each { |a| a.check } if $args.size > 1 mul_args = $args[0..-2].select { |a| a.multiple } if mul_args.size > 0 gram = mul_args.size > 1 ? "s are" : " is" raise "The following#{gram} not the last arg but marked multiple: #{mul_args.map { |a| a.name }.join(", ")}" end end # Headers h.puts(<<EOS) /***** This code was generated by Yaggo. Do not edit ******/ EOS if $license lines = $license.split(/\n/) h.puts("/* #{lines[0]}", *(lines[1..-1].map { |l| " * " + l })) h.puts(" */", "") elsif $yaggo_options[:license] open($yaggo_options[:license]) { |fd| h.puts(fd.read) } h.puts("") end h.puts(<<EOS) #ifndef __#{class_name.upcase()}_HPP__ #define __#{class_name.upcase()}_HPP__ #include <stdint.h> #include <unistd.h> #include <stdlib.h> #include <getopt.h> #include <errno.h> #include <string.h> #include <stdexcept> #include <string> #include <limits> #include <vector> #include <iostream> #include <sstream> #include <memory> class #{class_name} { // Boiler plate stuff. Conversion from string to other formats EOS output_conversion_code h h.puts(<<EOS) public: EOS static_decl = $options.map { |o| o.static_decl }.flatten h.puts(" " + static_decl.join("\n "), "") unless static_decl.empty? ($options + $args).each { |o| h.puts(" " + o.var_decl.join("\n ")) } h.puts("") # Create enum if option with no short version only_long = $options.map { |o| o.long_enum }.flatten.compact need_full = $options.any? { |o| o.hidden } help_no_h = $options.any? { |o| o.short == "h" } version_no_V = $options.any? { |o| o.short == "V" } usage_no_U = $options.any? { |o| o.short == "U" } h.print(" enum {\n START_OPT = 1000") h.print(",\n FULL_HELP_OPT") if need_full h.print(",\n HELP_OPT") if help_no_h h.print(",\n VERSION_OPT") if version_no_V h.print(",\n USAGE_OPT") if usage_no_U if only_long.empty? h.puts("\n };") else h.puts(",", " " + only_long.join(",\n "), " };") end # Constructors and initialization h.puts("", " #{class_name}() :") h.puts(" " + ($options + $args).map { |o| o.init }.join(",\n "), " { }") h.puts("", " #{class_name}(int argc, char* argv[]) :") h.puts(" " + ($options + $args).map { |o| o.init }.join(",\n ")) h.puts(" { parse(argc, argv); }", ""); # Main arsing function h.puts(" void parse(int argc, char* argv[]) {", " static struct option long_options[] = {") $options.empty? or h.puts(" " + $options.map { |o| o.struct }.flatten.join(",\n ") + ",") h.puts(" {\"help\", 0, 0, #{help_no_h ? "HELP_OPT" : "'h'"}},") h.puts(" {\"full-help\", 0, 0, FULL_HELP_OPT},") if need_full h.puts(" {\"usage\", 0, 0, #{usage_no_U ? "USAGE_OPT" : "'U'"}},", " {\"version\", 0, 0, #{version_no_V ? "VERSION_OPT" : "'V'"}},", " {0, 0, 0, 0}", " };") short_str = $posix ? "+" : "" short_str += "h" unless help_no_h short_str += "V" unless version_no_V short_str += "U" unless usage_no_U short_str += $options.map { |o| o.short_str }.compact.join("") h.puts(" static const char *short_options = \"#{short_str}\";", "") need_err = $options.any? { |o| o.type != :flag && o.type != :string && o.type != :c_string} need_err ||= $args.any? { |a| a.type != :string && a.type != :c_string } need_err ||= ($options + $args).any? { |o| !o.access_types.empty? } h.puts(" ::std::string err;") if need_err # Actual parsing h.puts(<<EOS) #define CHECK_ERR(type,val,which) if(!err.empty()) { ::std::cerr << "Invalid " #type " '" << val << "' for [" which "]: " << err << "\\n"; exit(1); } while(true) { int index = -1; int c = getopt_long(argc, argv, short_options, long_options, &index); if(c == -1) break; switch(c) { case ':': ::std::cerr << \"Missing required argument for \" << (index == -1 ? ::std::string(1, (char)optopt) : std::string(long_options[index].name)) << ::std::endl; exit(1); case #{help_no_h ? "HELP_OPT" : "'h'"}: ::std::cout << usage() << \"\\n\\n\" << help() << std::endl; exit(0); case #{usage_no_U ? "USAGE_OPT" : "'U'"}: ::std::cout << usage() << \"\\nUse --help for more information.\" << std::endl; exit(0); case 'V': print_version(); exit(0); case '?': ::std::cerr << \"Use --usage or --help for some help\\n\"; exit(1); EOS if need_full h.puts(<<EOS) case FULL_HELP_OPT: ::std::cout << usage() << \"\\n\\n\" << help() << \"\\n\\n\" << hidden() << std::flush; exit(0); EOS end $options.each { |o| if o.type == :flag && o.noflag h.puts(" case #{o.long_enum[0]}:", " " + o.parse_arg.join("\n "), " break;", " case #{o.long_enum[1]}:", " " + o.parse_arg(true).join("\n "), " break;") else h.puts(" case #{o.long_enum ? o.long_enum[0] : "'" + o.short + "'"}:", " " + o.parse_arg.join("\n "), " break;") end } h.puts(" }", # close case " }") # close while(true) # Check required $options.any? { |o| o.required} and h.puts("", " // Check that required switches are present") $options.each { |o| next unless o.required h.puts(<<EOS) if(!#{o.var}_given) error("[#{o.switches}] required switch"); EOS } # Check conflict $options.any? { |o| !o.conflict.empty? } and h.puts("", " // Check mutually exlusive switches") $options.each { |o| o_check = o.var + (o.type == :flag ? "_flag" : "_given") o.conflict.each { |cos| co = $opt_hash[cos] co_check = co.var + (co.type == :flag ? "_flag" : "_given") h.puts(<<EOS) if(#{o_check} && #{co_check}) error("Switches [#{o.switches}] and [#{co.switches}] are mutually exclusive"); EOS } } # Check at_least $options.any? { |o| o.at_least } and h.puts("", " // Check at_least requirements") $options.each { |o| next unless o.multiple && !o.at_least.nil? h.puts(<<EOS) if(#{o.var}_arg.size() < #{o.at_least}) error("[#{o.switches}] must be given at least #{o.at_least} times"); EOS } # Parse arguments h.puts("", " // Parse arguments") if $args.size == 0 || !$args[-1].multiple h.puts(<<EOS) if(argc - optind != #{$args.size}) error("Requires exactly #{$args.size} argument#{$args.size > 1 ? "s" : ""}."); EOS else min_args = $args.size - 1 + $args[-1].at_least h.puts(<<EOS) if(argc - optind < #{min_args}) error("Requires at least #{min_args} argument#{min_args > 1 ? "s" : ""}."); EOS end $args.each { |a| h.puts(" " + a.parse_arg.join("\n ")) } # Check access rights if ($options + $args).any? { |o| !o.access_types.empty? } r_to_f = { "read" => "R_OK", "write" => "W_OK", "exec" => "X_OK" } h.puts("", " // Check access rights") ($args + $options).each { |o| next if o.access_types.empty? mode = o.access_types.map { |t| r_to_f[t] }.join("|") msg = Arg === o ? "Argument " + o.name : "Switch " + o.switches msg += ", access right (#{o.access_types.join("|")}) failed for file '" h.puts(" if(access(#{o.var}_arg, #{mode})) {", " err = \"#{msg}\";", " ((err += #{o.var}_arg) += \"': \") += strerror(errno);", " error(err.c_str());", " }") } end h.puts(" }") # close parser # Usage if !$usage.nil? ausage = quote_newline_dquotes($usage, " ") else ausage = "Usage: #{$package || class_name} [options]" $args.each { |a| ausage += " #{a.name}:#{a.typestr || dflt_typestr(a.type)}#{a.multiple ? "+" : ""}" } end h.puts(<<EOS) static const char * usage() { return "#{ausage}"; } class error { int code_; std::ostringstream msg_; // Select the correct version (GNU or XSI) version of // strerror_r. strerror_ behaves like the GNU version of strerror_r, // regardless of which version is provided by the system. static const char* strerror__(char* buf, int res) { return res != -1 ? buf : "Invalid error"; } static const char* strerror__(char* buf, char* res) { return res; } static const char* strerror_(int err, char* buf, size_t buflen) { return strerror__(buf, strerror_r(err, buf, buflen)); } struct no_t { }; public: static no_t no; error(int code = EXIT_FAILURE) : code_(code) { } explicit error(const char* msg, int code = EXIT_FAILURE) : code_(code) { msg_ << msg; } error(const std::string& msg, int code = EXIT_FAILURE) : code_(code) { msg_ << msg; } error& operator<<(no_t) { char buf[1024]; msg_ << ": " << strerror_(errno, buf, sizeof(buf)); return *this; } template<typename T> error& operator<<(const T& x) { msg_ << x; return (*this); } ~error() { ::std::cerr << "Error: " << msg_.str() << "\\n" << usage() << "\\n" << "Use --help for more information" << ::std::endl; exit(code_); } }; EOS # Help desc = "" unless $purpose.nil? desc += $purpose + "\\n\\n" end unless $description.nil? desc += $description.split(/\n/).join("\\n\" \\\n \"") + "\\n\\n" end h.puts(<<EOS) static const char * help() { return "#{desc}" "Options (default value in (), *required):\\n" EOS (h, $options, false) usage_switch = " -U, " usage_switch = " " * usage_switch.size if usage_no_U usage_switch += "--usage" h.puts(" \"#{usage_switch.ljust($switchesjust)} Usage\\n\"") help_switch = " -h, " help_switch = " " * help_switch.size if help_no_h help_switch += "--help" h.puts(" \"#{help_switch.ljust($switchesjust)} This message\\n\"") h.puts(" \"#{" --full-help".ljust($switchesjust)} Detailed help\\n\"") if need_full version_switch = " -V, " version_switch = " " * version_switch.size if version_no_V version_switch += "--version" h.print(" \"#{version_switch.ljust($switchesjust)} Version") if $after_text.nil? h.puts("\";") else h.puts("\\n\" \\", " \"\\n\"") atext = quote_newline_dquotes($after_text, " ") h.puts(" \"#{atext}\";") end h.puts(" }") # Hidden help has_hidden = $options.any? { |o| o.hidden } if has_hidden h.puts(<<EOS) static const char* hidden() { return "Hidden options:\\n" EOS (h, $options, true) h.puts(<<EOS) ""; } EOS else h.puts(<<EOS) static const char* hidden() { return ""; } EOS end # Version h.puts(" void print_version(::std::ostream &os = std::cout) const {", "#ifndef PACKAGE_VERSION", "#define PACKAGE_VERSION \"0.0.0\"", "#endif", " os << #{$version ? "\"" + $version + "\"" : "PACKAGE_VERSION"} << \"\\n\";", " }") # Dump h.puts(" void dump(::std::ostream &os = std::cout) {") ($options + $args).each { |o| h.puts(" os << #{o.dump.join(" << ")} << \"\\n\";") } h.puts(" }") # Private methods h.puts(<<EOS) }; EOS # Initialize static members # TODO: Should we have an option to put this in a .cc file? $options.each { |o| next unless o.type == :enum h.puts("const char* const #{class_name}::#{o.var}::strs[#{o.enum.size + 1}] = { #{o.enum.map { |x| "\"#{x}\"" }.join(", ") }, (const char*)0 };") } h.puts(<<EOS) #endif // __#{class_name.upcase}_HPP__" EOS end |
#output_options_descriptions(out, opts, hidden) ⇒ Object
20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/yaggo/parser.rb', line 20 def out, opts, hidden opts.each { |o| # need to be improved. break lines if too long next if o.secret || (o.hidden ^ hidden) s = " " + o.switches if s.size >= $switchesjust s += "\\n" + "".ljust($switchesjust) else s = s.ljust($switchesjust) end out.puts(" \"#{s} #{o.help}\\n\"") } end |
#output_zsh_completion(fd, filename) ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/yaggo/zsh_completion.rb', line 72 def output_zsh_completion(fd, filename) cmdname = File.basename(filename).gsub(/^_/, "") fd.puts("#compdef #{cmdname}", "", "local context state state_descr line", "typeset -A opt_args", "") return if $options.empty? && $args.empty? fd.puts("_arguments -s -S \\") $options.each { |o| conflicts = zsh_conflict_option o switches = zsh_switches_option o descr = o.description ? "[#{o.description}]" : "" action = zsh_type_completion o, true fd.puts("#{conflicts}#{switches}'#{descr}#{action}' \\") } $args.each { |a| descr = a.description || " " action = zsh_type_completion a, false many = a.multiple ? "*" : "" fd.puts("'#{many}:#{descr}#{action}' \\") } fd.puts(" && return 0") end |
#package(str) ⇒ Object
36 |
# File 'lib/yaggo/dsl.rb', line 36 def package str; $package = str; end |
#posix(*args) ⇒ Object
41 |
# File 'lib/yaggo/dsl.rb', line 41 def posix *args; $posix = true; end |
#purpose(str) ⇒ Object
35 |
# File 'lib/yaggo/dsl.rb', line 35 def purpose str; $purpose = str; end |
#quote_newline_dquotes(str, spaces = "") ⇒ Object
You should have received a copy of the GNU General Public License along with Yaggo. If not, see <www.gnu.org/licenses/>.
16 17 18 |
# File 'lib/yaggo/parser.rb', line 16 def quote_newline_dquotes str, spaces = "" str.gsub(/"/, '\\"').split(/\n/).join("\\n\" \\\n#{spaces}\"") end |
#required ⇒ Object
65 |
# File 'lib/yaggo/dsl.rb', line 65 def required; $target.required = true; end |
#run_block(name, b) ⇒ Object
92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/yaggo/general.rb', line 92 def run_block(name, b) eval("#{$option_variables.join(" = ")} = nil", $main_binding) b.call $option_variables.each { |n| eval("#{n} #{n} unless #{n}.nil?", $main_binding) } rescue NoMethodError => e header = find_error_header(e.backtrace) raise "#{header} In #{name}: invalid keyword '#{e.name}' in statement '#{e.name} #{e.args.map { |s| "\"#{s}\"" }.join(" ")}'" rescue NameError => e header = find_error_header(e.backtrace) raise "#{header} In #{name}: invalid keyword '#{e.name}'" rescue RuntimeError, ArgumentError => e header = find_error_header(e.backtrace) raise "#{header} In #{name}: #{e.}" end |
#secret ⇒ Object
67 |
# File 'lib/yaggo/dsl.rb', line 67 def secret; $target.secret = true; end |
#str_conv(arg, type, *argv) ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/yaggo/general.rb', line 69 def str_conv(arg, type, *argv) case type when :string "string(#{arg})" when :c_string arg when :uint32, :uint64 "conv_uint<#{$type_to_C_type[type]}>((const char*)#{arg}, err, #{suffix_arg(argv[0])})" when :int32, :int64, :long, :int "conv_int<#{$type_to_C_type[type]}>((const char*)#{arg}, err, #{suffix_arg(argv[0])})" when :double "conv_double((const char*)#{arg}, err, #{suffix_arg(argv[0])})" when :enum # Convert a string to its equivalent enum value "conv_enum((const char*)#{arg}, err, #{argv[0]})" end end |
#string ⇒ Object
59 |
# File 'lib/yaggo/dsl.rb', line 59 def string; $target.type = :string; end |
#suffix ⇒ Object
64 |
# File 'lib/yaggo/dsl.rb', line 64 def suffix; $target.suffix = true; end |
#suffix_arg(suffix) ⇒ Object
56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/yaggo/general.rb', line 56 def suffix_arg(suffix) case suffix when true "true" when false "false" when String suffix else raise "Invalid suffix specifier" end end |
#text(str) ⇒ Object
38 |
# File 'lib/yaggo/dsl.rb', line 38 def text str; $after_text = str; end |
#typestr(str) ⇒ Object
72 |
# File 'lib/yaggo/dsl.rb', line 72 def typestr str; $target.typestr = str; end |
#uint32 ⇒ Object
54 |
# File 'lib/yaggo/dsl.rb', line 54 def uint32; $target.type = :uint32; end |
#uint64 ⇒ Object
55 |
# File 'lib/yaggo/dsl.rb', line 55 def uint64; $target.type = :uint64; end |
#usage(str) ⇒ Object
37 |
# File 'lib/yaggo/dsl.rb', line 37 def usage str; $usage = str; end |
#version(str) ⇒ Object
40 |
# File 'lib/yaggo/dsl.rb', line 40 def version str; $version = str; end |
#zsh_conflict_option(o) ⇒ Object
17 18 19 20 21 22 23 24 25 26 |
# File 'lib/yaggo/zsh_completion.rb', line 17 def zsh_conflict_option o = o.conflict + $options.map { |co| (co.conflict.include?(o.short) || co.conflict.include?(o.long)) ? (co.short || co.long) : nil }.compact.uniq return "" if .empty? "'(" + .map { |co_name| co = $opt_hash[co_name] [co.short && "-#{co.short}", co.long && "--#{co.long}"] }.flatten.compact.uniq.join(" ") + ")'" end |
#zsh_switches_option(o) ⇒ Object
28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/yaggo/zsh_completion.rb', line 28 def zsh_switches_option o switches = if o.type == :flag [o.short && "-#{o.short}", o.long && "--#{o.long}"] else [o.short && "-#{o.short}+", o.long && "--#{o.long}="] end switches.compact! swstr = switches.size > 1 ? "{#{switches.join(",")}}" : switches[0] swstr = "\\*#{swstr}" if o.multiple swstr end |
#zsh_type_completion(o, with_type = true) ⇒ Object
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/yaggo/zsh_completion.rb', line 40 def zsh_type_completion o, with_type = true typedescr = o.typestr || o.type.id2name typename = with_type ? ":" + typedescr : "" guard_help = "#{typedescr} #{o.description || ""}" case o.type when :flag return "" when :enum return "#{typename}:(#{o.enum.join(" ")})" when :string, :c_string case o.typestr || "" when /file|path/i return "#{typename}:_files" when /dir/i return "#{typename}:_files -/" else return typename end when :int32, :int64, :int, :long suffixes = o.suffix ? "[kMGTPE]" : "" return "#{typename}:_guard \"[0-9+-]##{suffixes}\" \"#{guard_help}\"" when :uint32, :uint64 suffixes = o.suffix ? "[kMGTPE]" : "" return "#{typename}:_guard \"[0-9+]##{suffixes}\" \"#{guard_help}\"" when :double suffixes = "[munpfakMGTPE]" if o.suffix return "#{typename}:_guard \"[0-9.eE+-]##{suffixes}\" \"#{guard_help}\"" else return default end end |