1package App::Yath::Options; 2use strict; 3use warnings; 4 5our $VERSION = '1.000082'; 6 7use Carp qw/croak confess/; 8use Scalar::Util qw/blessed/; 9use Test2::Harness::Util qw/mod2file/; 10 11use App::Yath::Option(); 12use Test2::Harness::Settings(); 13 14use Test2::Harness::Util::HashBase qw{ 15 <all <lookup 16 17 <pre_list <cmd_list <post_list 18 19 <post_list_sorted 20 21 <settings 22 23 <args 24 <command_class 25 26 <pending_pre <pending_cmd <pending_post 27 28 <used_plugins 29 30 <included 31 32 <set_by_cli 33}; 34 35sub import { 36 my $class = shift; 37 my $caller = caller(); 38 39 croak "$caller already has an 'options' method" 40 if defined(&{"$caller\::options"}); 41 42 my @common; 43 my $instance; 44 my $options = sub { ($instance //= $class->new()) }; 45 my $option = sub { ($instance //= $class->new())->_option([caller()], shift(@_), @common ? (%{$common[-1]}) : (), @_) }; 46 my $include = sub { ($instance //= $class->new())->include_from(@_) }; 47 48 my $post = sub { 49 my $cb = pop; 50 my $weight = shift // 0; 51 my ($applicable) = @_; 52 53 $applicable //= $common[-1]->{applicable} if @common; 54 55 croak "You must provide a callback coderef" unless $cb && ref($cb) eq 'CODE'; 56 57 ($instance //= $class->new())->_post($weight, $applicable, $cb); 58 }; 59 60 my $group = sub { 61 my ($set, $sub) = @_; 62 63 my $common = {@common ? (%{$common[-1]}) : (), %$set}; 64 65 if (my $class = $common->{builds}) { 66 require(mod2file($class)); 67 } 68 69 push @common => $common; 70 my $ok = eval { $sub->(); 1 }; 71 my $err = $@; 72 pop @common; 73 74 die $err unless $ok; 75 }; 76 77 { 78 no strict 'refs'; 79 *{"$caller\::post"} = $post; 80 *{"$caller\::option"} = $option; 81 *{"$caller\::options"} = $options; 82 *{"$caller\::option_group"} = $group; 83 *{"$caller\::include_options"} = $include; 84 } 85 86 return 1; 87} 88 89sub init { 90 my $self = shift; 91 92 $self->{+ALL} //= []; 93 $self->{+LOOKUP} //= {}; 94 95 $self->{+USED_PLUGINS} //= []; 96 97 $self->{+PRE_LIST} //= []; 98 $self->{+CMD_LIST} //= []; 99 $self->{+POST_LIST} //= []; 100 101 $self->{+SETTINGS} //= Test2::Harness::Settings->new(); 102 103 $self->{+INCLUDED} //= {}; 104 105 $self->{+SET_BY_CLI} //= {}; 106 107 return $self; 108} 109 110sub option { 111 my $self = shift; 112 $self->_option([caller()], @_); 113} 114 115sub include { 116 my $self = shift; 117 my ($inc) = @_; 118 119 croak "Include must be an instance of ${ \__PACKAGE__ }, got ${ defined($inc) ? \qq['$inc'] : \'undef' }" 120 unless $inc && blessed($inc) && $inc->isa(__PACKAGE__); 121 122 $self->include_option($_) for @{$inc->all}; 123 124 $self->{+POST_LIST_SORTED} = 0; 125 push @{$self->{+POST_LIST}} => @{$inc->post_list}; 126 127 return; 128} 129 130sub include_from { 131 my $self = shift; 132 133 for my $pkg (@_) { 134 require(mod2file($pkg)) unless $pkg->can('options'); 135 136 next unless $pkg->can('options'); 137 my $options = $pkg->options or next; 138 $self->include($options); 139 140 $self->{+INCLUDED}->{$pkg}++; 141 $self->{+INCLUDED}->{$_}++ for keys %{$options->included}; 142 } 143 144 return; 145} 146 147sub populate_pre_defaults { 148 my $self = shift; 149 150 for my $opt (@{$self->_pre_command_options}) { 151 my $slot = $opt->option_slot($self->{+SETTINGS}); 152 my $val = $opt->get_default($self->{+SETTINGS}); 153 $$slot //= $val; 154 } 155} 156 157sub populate_cmd_defaults { 158 my $self = shift; 159 160 croak "The 'command_class' attribute has not yet been set" 161 unless $self->{+COMMAND_CLASS}; 162 163 for my $opt (@{$self->_command_options()}) { 164 my $slot = $opt->option_slot($self->{+SETTINGS}); 165 my $val = $opt->get_default($self->{+SETTINGS}); 166 $$slot //= $val; 167 } 168} 169 170sub grab_pre_command_opts { 171 my $self = shift; 172 my %config = @_; 173 174 $self->populate_pre_defaults(); 175 176 unshift @{$self->{+PENDING_PRE} //= []} => $self->_grab_opts( 177 '_pre_command_options', 178 'pre-command', 179 stop_at_non_opt => 1, 180 passthrough => 1, 181 %config, 182 ); 183} 184 185sub process_pre_command_opts { 186 my $self = shift; 187 return unless $self->{+PENDING_PRE}; 188 $self->_process_opts(delete $self->{+PENDING_PRE}); 189} 190 191sub set_command_class { 192 my $self = shift; 193 my ($in) = @_; 194 195 croak "Command class has already been set" 196 if $self->{+COMMAND_CLASS}; 197 198 my $class = blessed($in) || $in; 199 200 croak "Invalid command class: $class" 201 unless $class->isa('App::Yath::Command'); 202 203 $self->include_from($class) if $class->can('options'); 204 205 return $self->{+COMMAND_CLASS} = $class; 206} 207 208sub set_args { 209 my $self = shift; 210 my ($in) = @_; 211 212 croak "'args' has already been set" 213 if $self->{+ARGS}; 214 215 return $self->{+ARGS} = $in; 216} 217 218sub grab_command_opts { 219 my $self = shift; 220 my %config = @_; 221 222 croak "The 'command_class' attribute has not yet been set" 223 unless $self->{+COMMAND_CLASS}; 224 225 $self->populate_cmd_defaults(); 226 227 push @{$self->{+PENDING_CMD} //= []} => $self->_grab_opts( 228 '_command_options', 229 "command (" . $self->{+COMMAND_CLASS}->name . ")", 230 %config, 231 ); 232} 233 234sub process_command_opts { 235 my $self = shift; 236 return unless $self->{+PENDING_CMD}; 237 $self->_process_opts(delete $self->{+PENDING_CMD}); 238} 239 240sub process_option_post_actions { 241 my $self = shift; 242 my ($cmd) = @_; 243 244 croak "The 'args' attribute has not yet been set" 245 unless $self->{+ARGS}; 246 247 if ($cmd) { 248 croak "The 'command_class' attribute has not yet been set" 249 unless $self->{+COMMAND_CLASS}; 250 251 croak "The process_option_post_actions requires an App::Yath::Command instance, got: " . ($cmd // "undef") 252 unless blessed($cmd) && $cmd->isa('App::Yath::Command'); 253 254 croak "The command '$cmd' dos not match the expected class '$self->{+COMMAND_CLASS}'" 255 unless blessed($cmd) eq $self->{+COMMAND_CLASS}; 256 } 257 258 unless ($self->{+POST_LIST_SORTED}++) { 259 @{$self->{+POST_LIST}} = sort { $a->[0] <=> $b->[0] } @{$self->{+POST_LIST}}; 260 } 261 262 for my $post (@{$self->{+POST_LIST}}) { 263 next if $post->[1] && !$post->[1]->($post->[2], $self); 264 $post->[2]->( 265 options => $self, 266 args => $self->{+ARGS}, 267 settings => $self->{+SETTINGS}, 268 $cmd ? (command => $cmd) : (), 269 ); 270 } 271} 272 273sub _pre_command_options { $_[0]->{+PRE_LIST} } 274 275sub _command_options { 276 my $self = shift; 277 278 my $class = $self->{+COMMAND_CLASS} or croak "The 'command_class' attribute has not yet been set"; 279 280 my $cmd = $class->name; 281 my $cmd_options = $self->{+CMD_LIST} // []; 282 my $pre_options = $self->{+PRE_LIST} // []; 283 284 return [grep { $_->applicable($self) } @$cmd_options, @$pre_options]; 285} 286 287sub _process_opts { 288 my $self = shift; 289 my ($list) = @_; 290 291 while (my $opt_set = shift @$list) { 292 my ($opt, $meth, @args) = @$opt_set; 293 $opt->$meth(@args, $self->{+SETTINGS}, $self, $list); 294 $self->{+SET_BY_CLI}->{$opt->prefix}->{$opt->field}++; 295 push @{$self->{+USED_PLUGINS}} => $opt->from_plugin if $opt->from_plugin; 296 } 297} 298 299sub _parse_long_option { 300 my $self = shift; 301 my ($arg) = @_; 302 303 $arg =~ m/^--((?:no-)?([^=]+))(=(.*))?$/ or confess "Invalid long option: $arg"; 304 305 #return (main, full, val); 306 return ($2, $1, $3 ? $4 // '' : undef); 307} 308 309sub _parse_short_option { 310 my $self = shift; 311 my ($arg) = @_; 312 313 $arg =~ m/^-([^-])(=)?(.+)?$/ or confess "Invalid short option: $arg"; 314 315 #return (main, remain, assign); 316 return ($1, $3, $2); 317} 318 319sub _handle_long_option { 320 my $self = shift; 321 my ($arg, $lookup, $args) = @_; 322 323 my ($main, $full, $val) = $self->_parse_long_option($arg); 324 325 my $opt; 326 if ($opt = $lookup->{long}->{$full}) { 327 if ($opt->requires_arg) { 328 $val //= shift(@$args) // die "Option --$full requires an argument.\n"; 329 } 330 elsif($opt->allows_arg) { 331 $val //= 1; 332 } 333 else { 334 die "Option --$full does not take an argument\n" if defined $val; 335 $val = 1; 336 } 337 338 return [$opt, 'handle', $val]; 339 } 340 elsif ($opt = $lookup->{long}->{$main}) { 341 die "Option --$full does not take an argument\n" if defined $val; 342 return [$opt, 'handle_negation']; 343 } 344 345 return undef; 346} 347 348sub _handle_short_option { 349 my $self = shift; 350 my ($arg, $lookup, $args) = @_; 351 352 my ($main, $remain, $assign) = $self->_parse_short_option($arg); 353 354 if (my $opt = $lookup->{short}->{$main}) { 355 my $val = 1; 356 if ($opt->allows_arg) { 357 $val = $remain; 358 359 $val //= '' if $assign; 360 361 if ($opt->requires_arg) { 362 $val //= shift(@$args) // die "Option -$main requires an argument.\n"; 363 } 364 else { 365 $val //= 1; 366 } 367 368 return [$opt, 'handle', $val]; 369 } 370 elsif ($assign) { 371 die "Option -$main does not take an argument\n"; 372 } 373 elsif(defined($remain) && length($remain)) { 374 unshift @$args => "-$remain"; 375 } 376 377 return [$opt, 'handle', $val]; 378 } 379 380 return undef; 381} 382 383my %ARG_ENDS = ('--' => 1, '::' => 1); 384 385sub _grab_opts { 386 my $self = shift; 387 my ($opt_fetch, $type, %config) = @_; 388 389 croak "The opt_fetch callback is required" unless $opt_fetch; 390 croak "The arg type is required" unless $type; 391 392 my $args = $config{args} || $self->{+ARGS} or confess "The 'args' attribute has not yet been set"; 393 394 my $lookup = $self->_build_lookup($self->$opt_fetch()); 395 396 my (@keep_args, @opts); 397 while (@$args) { 398 my $arg = shift @$args; 399 400 if ($ARG_ENDS{$arg}) { 401 push @keep_args => $arg; 402 last; 403 } 404 405 if (substr($arg, 0, 1) eq '-') { 406 my $handler = (substr($arg, 1, 1) eq '-') ? '_handle_long_option' : '_handle_short_option'; 407 if(my $opt_set = $self->$handler($arg, $lookup, $args)) { 408 my ($opt, $action, @val) = @$opt_set; 409 410 if (my $pre = $opt->pre_process) { 411 $pre->( 412 opt => $opt, 413 options => $self, 414 action => $action, 415 type => $type, 416 417 @val ? (val => $val[0]) : (), 418 ); 419 } 420 421 $lookup = $self->_build_lookup($self->$opt_fetch()) 422 if $opt->adds_options; 423 424 push @opts => $opt_set; 425 next; 426 } 427 elsif (!$config{passthrough}) { 428 die "Invalid $type option: $arg\n"; 429 } 430 } 431 432 die "Invalid $type option: $arg" if $config{die_at_non_opt}; 433 434 push @keep_args => $arg; 435 436 last if $config{stop_at_non_opt}; 437 } 438 439 unshift @$args => @keep_args; 440 441 return @opts; 442} 443 444sub _build_lookup { 445 my $self = shift; 446 my ($opts) = @_; 447 448 my $lookup = {long => {}, short => {}}; 449 450 my %seen; 451 for my $opt (@$opts) { 452 next if $seen{$opt}++; 453 454 for my $long ($opt->long_args) { 455 $lookup->{long}->{$long} //= $opt; 456 } 457 458 my $short = $opt->short or next; 459 $lookup->{short}->{$short} //= $opt; 460 } 461 462 return $lookup; 463} 464 465sub _post { 466 my $self = shift; 467 my ($weight, $applicable, $cb) = @_; 468 469 $self->{+POST_LIST_SORTED} = 0; 470 471 $weight //= 0; 472 473 push @{$self->{+POST_LIST} //= []} => [$weight, $applicable, $cb]; 474} 475 476sub _option { 477 my $self = shift; 478 my ($trace, @spec) = @_; 479 480 my %proto = $self->_parse_option_args(@spec); 481 482 my $opt = App::Yath::Option->new( 483 trace => $trace, 484 $self->_parse_option_caller($trace->[0], \%proto), 485 %proto, 486 ); 487 488 $self->include_option($opt); 489} 490 491sub include_option { 492 my $self = shift; 493 my ($opt) = @_; 494 495 my $trace = $opt->trace or confess "Options must have a trace!"; 496 497 push @{$self->{+ALL}} => $opt; 498 499 my $new = $self->_index_option($opt); 500 $self->_list_option($opt) if $new; 501 502 return $opt; 503} 504 505sub _parse_option_caller { 506 my $self = shift; 507 my ($caller, $proto) = @_; 508 509 my ($from_plugin, $from_command, $from_prefix, $prefix, $is_top); 510 511 $prefix = $proto->{prefix} if exists $proto->{prefix}; 512 $prefix //= $caller->option_prefix() if $caller->can('option_prefix'); 513 514 if ($caller->isa('App::Yath::Command')) { 515 $from_command = $caller->name() unless $caller eq 'App::Yath::Command'; 516 $is_top = 1; 517 } 518 elsif ($caller =~ m/App::Yath::Command::([^:]+)::.*Options(?:::.*)?$/) { 519 $from_command = $1; 520 $is_top = 1; 521 } 522 elsif ($caller eq 'App::Yath') { 523 $is_top = 1; 524 } 525 elsif ($caller =~ m/^(App::Yath::Plugin::([^:]+))$/) { 526 $from_plugin = $1; 527 $from_prefix = $2; 528 529 unless (defined $prefix) { 530 $prefix = $from_prefix; 531 $prefix =~ s/::.*$//g; 532 } 533 } 534 535 $prefix = lc($prefix) if $prefix; 536 537 croak "Could not find an option prefix and option is not top-level ($proto->{title})" 538 unless $is_top || defined($prefix) || defined($proto->{prefix}); 539 540 return ( 541 $from_plugin ? (from_plugin => $from_plugin) : (), 542 $from_command ? (from_command => $from_command) : (), 543 ($prefix || !$is_top) ? (prefix => $prefix) : (), 544 ); 545} 546 547sub _parse_option_args { 548 my $self = shift; 549 my @spec = @_; 550 551 my %args; 552 if (@spec == 1) { 553 my ($title, $type) = $spec[0] =~ m/^([\w-]+)(?:=(.+))?$/ or croak "Invalid option specification: $spec[0]"; 554 return (title => $title, type => $type); 555 } 556 elsif (@spec == 2) { 557 my ($title, $type) = @spec; 558 return (title => $title, type => $type); 559 } 560 561 my $title = shift @spec; 562 return (title => $title, @spec); 563} 564 565sub _index_option { 566 my $self = shift; 567 my ($opt) = @_; 568 569 my $index = $self->{+LOOKUP}; 570 571 my $out = 0; 572 573 for my $n ($opt->name, @{$opt->alt || []}) { 574 if (my $existing = $index->{$n}) { 575 next if "$existing" eq "$opt"; 576 croak "Option '$n' was already defined (" . $existing->trace_string . ")"; 577 } 578 579 $out++; 580 $index->{$n} = $opt; 581 } 582 583 if (my $short = $opt->short) { 584 if (my $existing = $index->{$short}) { 585 return $out if "$existing" eq "$opt"; 586 croak "Option '$short' was already defined (" . $existing->trace_string . ")"; 587 } 588 589 $out++; 590 $index->{$short} = $opt; 591 } 592 593 return $out; 594} 595 596sub _list_option { 597 my $self = shift; 598 my ($opt) = @_; 599 600 return push @{$self->{+PRE_LIST}} => $opt 601 if $opt->pre_command; 602 603 push @{$self->{+CMD_LIST}} => $opt; 604} 605 606sub pre_docs { 607 my $self = shift; 608 609 return $self->_docs($self->_pre_command_options(), @_); 610} 611 612sub cmd_docs { 613 my $self = shift; 614 615 return unless $self->{+COMMAND_CLASS}; 616 617 return $self->_docs([grep { !$_->pre_command } @{$self->_command_options()}], @_); 618} 619 620my %DOC_FORMATS = ( 621 'cli' => [ 622 'cli_docs', # Method to call on opt 623 "\n", # how to join lines 624 sub { "\n$_[1]" }, # how to render the category 625 sub { $_[0] =~ s/^/ /mg; "$_[0]\n" }, # transform the value from the opt 626 sub { }, # add this at the end 627 ], 628 'pod' => [ 629 'pod_docs', # Method to call on opt 630 "\n\n", # how to join lines 631 sub { ($_[0] ? ("=back") : (), "=head$_[2] $_[1]", "=over 4") }, # how to render the category 632 sub { $_[0] }, # transform the value from the opt 633 sub { $_[0] ? ("=back") : () }, # add this at the end 634 ], 635); 636 637sub _docs { 638 my $self = shift; 639 my ($opts, $format, @args) = @_; 640 641 $format //= "UNDEFINED"; 642 my $fset = $DOC_FORMATS{$format} or croak "Invalid documentation format '$format'"; 643 my ($fmeth, $join, $fcat, $ftrans, $fend) = @$fset; 644 645 return unless $opts; 646 return unless @$opts; 647 648 my @opts = sort _doc_sort_ops @$opts; 649 650 my @out; 651 652 my $cat; 653 for my $opt (@opts) { 654 if (!$cat || $opt->category ne $cat) { 655 push @out => $fcat->($cat, $opt->category, @args); 656 $cat = $opt->category; 657 } 658 659 my $help = $opt->$fmeth(); 660 push @out => $ftrans->($help); 661 } 662 663 push @out => $fend->($cat); 664 665 return join $join => @out; 666} 667 668sub _doc_sort_ops($$) { 669 my ($a, $b) = @_; 670 671 my $anc = $a->category eq 'NO CATEGORY - FIX ME'; 672 my $bnc = $b->category eq 'NO CATEGORY - FIX ME'; 673 674 if($anc xor $bnc) { 675 return 1 if $anc; 676 return -1; 677 } 678 679 my $ret = $a->category cmp $b->category; 680 $ret ||= ($a->prefix || '') cmp ($b->prefix || ''); 681 $ret ||= $a->field cmp $b->field; 682 $ret ||= $a->name cmp $b->name; 683 684 return $ret; 685} 686 687sub clear_env { 688 my $self = shift; 689 690 for my $opt (@{$self->{+ALL}}) { 691 next unless $opt->clear_env_vars; 692 my $env = $opt->env_vars or next; 693 for my $var (@$env) { 694 $var =~ s/^!//; 695 delete $ENV{$var}; 696 } 697 } 698} 699 7001; 701 702__END__ 703 704=pod 705 706=encoding UTF-8 707 708=head1 NAME 709 710App::Yath::Options - Tools for defining and tracking yath CLI options. 711 712=head1 DESCRIPTION 713 714This class represents a collection of options, and holds the logic for 715processing them. This package also exports sugar to help you define options. 716 717=head1 SYNOPSIS 718 719 package My::Options; 720 721 use App::Yath::Options; 722 723 # This package now has a package instance of options, which can be obtained 724 # via the options() method. 725 my $options = __PACKAGE__->options; 726 727 # We can include options from other packages 728 include_options( 729 'Package::With::Options::A', 730 'Package::With::Options::B', 731 ..., 732 ); 733 734 # Define an option group with some options 735 option_group { %common_fields } => sub { 736 737 # Define an option 738 option foo => ( 739 type => 's', 740 default => "FOOOOOOO", 741 category => 'foo', 742 description => "This is foo" 743 long_examples => [' value'], 744 ... 745 ); 746 747 option bar => ( ... ); 748 ... 749 }; 750 751 # Action to call right after options are parsed. 752 post sub { 753 my %params = @_; 754 755 ... 756 }; 757 758=head1 EXPORTS 759 760=over 4 761 762=item $opts = options() 763 764=item $opts = $class->options() 765 766This returns the options instance associated with your package. 767 768=item include_options(@CLASSES) 769 770This lets you include options defined in other packages. 771 772=item option_group \%COMMON_FIELDS => sub { ... } 773 774An option group is simply a block where all calls to C<option()> will have 775common fields added automatically, this makes it easier to define multiple 776options that share common fields. Common fields can be overridden inside the 777option definition. 778 779These are both equivelent: 780 781 # Using option group 782 option_group { category => 'foo', prefix => 'foo' } => sub { 783 option a => (type => 'b'); 784 option b => (type => 's'); 785 }; 786 787 # Not using option group 788 option a => (type => 'b', category => 'foo', prefix => 'foo'); 789 option b => (type => 's', category => 'foo', prefix => 'foo'); 790 791=item option TITLE => %FIELDS 792 793Define an option. The first argument is the C<title> attribute for the new 794option, all other arguments should be attribute/value pairs used to construct 795the option. See L<App::Yath::Option> for the documentation of attributes. 796 797=item post sub { ... } 798 799=item post $weight => sub { ... } 800 801C<post> callbacks are run after all command line arguments have been processed. 802This is a place to verify the result of several options combined, sanity check, 803or even add short-circuit behavior. This is how the C<--help> and 804C<--show-opts> options are implemented. 805 806If no C<$weight> is specified then C<0> is used. C<post> callbacks or sorted 807based on weight with higher values being run later. 808 809=back 810 811=head1 OPTIONS INSTANCES 812 813In general you should not be using the options instance directly. Options 814instances are mostly an implementation detail that should be treated as a black 815box. There are however a few valid reasons to interact with them directly. In 816those cases there are a few public attributes/methods you can work with. This 817section documents the public interface. 818 819=head2 ATTRIBUTES 820 821This section only lists attributes that may be useful to people working with 822options instances. There are a lot of internal (to yath) attributes that are 823implementation details that are not listed here. Attributes not listed here are 824not intended for external use and may change at any time. 825 826=over 4 827 828=item $arrayref = $options->all 829 830Arrayref containing all the L<App::Yath::Option> instances in the options 831instance. 832 833=item $settings = $options->settings 834 835Get the L<Test2::Harness::Settings> instance. 836 837=item $arrayref = $options->args 838 839Get the reference to the list of command line arguments. This list is modified 840as arguments are processed, there are no guarentees about what is in here at 841any given stage of argument processing. 842 843=item $class_name = $options->command_class 844 845If yath has determined what command is being executed this will be populated 846with that command class. This will be undefined if the class has not been 847determined yet. 848 849=item $arrayref = $options->used_plugins 850 851This is a list of all plugins who's options have been used. Plugins may appear 852more than once. 853 854=item $hashref = $options->included 855 856A hashref where every key is a package who's options have been included into 857this options instance. The values are an implementation detail, do not rely on 858them. 859 860=back 861 862=head2 METHODS 863 864This section only lists methods that may be useful to people working with 865options instances. There are a lot of internal (to yath) methods that are 866implementation details that are not listed here. Methods not listed here are 867not intended for external use and may change at any time. 868 869=over 4 870 871=item $opt = $options->option(%OPTION_ATTRIBUTES) 872 873This will create a new option with the provided attributes and add it to the 874options instance. A C<trace> attribute will be automatically set for you. 875 876=item $options->include($options_instance) 877 878This method lets you directly include options from a second instance into the 879first. 880 881=item $options->include_from(@CLASSES) 882 883This lets you include options from multiple classes that have options defined. 884 885=item $options->include_option($opt) 886 887This lets you include a single already defined option instance. 888 889=item $options->pre_docs($format, @args) 890 891Get documentation for pre-command options. $format may be 'cli' or 'pod'. 892 893=item $options->cmd_docs($format, @args) 894 895Get documentation for command options. $format may be 'cli' or 'pod'. 896 897=back 898 899=head1 SOURCE 900 901The source code repository for Test2-Harness can be found at 902F<http://github.com/Test-More/Test2-Harness/>. 903 904=head1 MAINTAINERS 905 906=over 4 907 908=item Chad Granum E<lt>exodist@cpan.orgE<gt> 909 910=back 911 912=head1 AUTHORS 913 914=over 4 915 916=item Chad Granum E<lt>exodist@cpan.orgE<gt> 917 918=back 919 920=head1 COPYRIGHT 921 922Copyright 2020 Chad Granum E<lt>exodist7@gmail.comE<gt>. 923 924This program is free software; you can redistribute it and/or 925modify it under the same terms as Perl itself. 926 927See F<http://dev.perl.org/licenses/> 928 929=cut 930