| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | #!/usr/bin/perl | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | =head1 NAME | 
| 4 |  |  |  |  |  |  |  | 
| 5 |  |  |  |  |  |  | App::Getconf - singleton-like config store for command-line applications | 
| 6 |  |  |  |  |  |  |  | 
| 7 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | # main.pl | 
| 10 |  |  |  |  |  |  |  | 
| 11 |  |  |  |  |  |  | use App::Getconf qw{ :schema }; | 
| 12 |  |  |  |  |  |  | use YAML qw{ LoadFile }; | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | App::Getconf->option_schema( | 
| 15 |  |  |  |  |  |  | help    => opt { type => 'flag', | 
| 16 |  |  |  |  |  |  | help => "this message" }, | 
| 17 |  |  |  |  |  |  | version => opt { type => 'flag', | 
| 18 |  |  |  |  |  |  | help => "print version information" }, | 
| 19 |  |  |  |  |  |  | verbose => opt { type => 'bool', | 
| 20 |  |  |  |  |  |  | help => "be verbose" }, | 
| 21 |  |  |  |  |  |  | session => schema( | 
| 22 |  |  |  |  |  |  | timeout => opt { type => 'int',    value => 50 }, | 
| 23 |  |  |  |  |  |  | path    => opt { type => 'string', value => '/' }, | 
| 24 |  |  |  |  |  |  | ), | 
| 25 |  |  |  |  |  |  | # ... | 
| 26 |  |  |  |  |  |  | ); | 
| 27 |  |  |  |  |  |  |  | 
| 28 |  |  |  |  |  |  | App::Getconf->cmdline(\@ARGV); | 
| 29 |  |  |  |  |  |  | App::Getconf->options(LoadFile('/etc/myapp.yaml')); | 
| 30 |  |  |  |  |  |  |  | 
| 31 |  |  |  |  |  |  | if (App::Getconf->getopt->help) { | 
| 32 |  |  |  |  |  |  | print App::Getconf->help_message(); | 
| 33 |  |  |  |  |  |  | exit 0; | 
| 34 |  |  |  |  |  |  | } | 
| 35 |  |  |  |  |  |  |  | 
| 36 |  |  |  |  |  |  | # real code... | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  | #------------------------------------------------- | 
| 39 |  |  |  |  |  |  | # My/Module.pm | 
| 40 |  |  |  |  |  |  |  | 
| 41 |  |  |  |  |  |  | package My::Module; | 
| 42 |  |  |  |  |  |  |  | 
| 43 |  |  |  |  |  |  | use App::Getconf; | 
| 44 |  |  |  |  |  |  |  | 
| 45 |  |  |  |  |  |  | sub do_something { | 
| 46 |  |  |  |  |  |  | my ($self, %args) = @_; | 
| 47 |  |  |  |  |  |  |  | 
| 48 |  |  |  |  |  |  | my $opts = App::Getconf->getopt; | 
| 49 |  |  |  |  |  |  |  | 
| 50 |  |  |  |  |  |  | if ($opts->verbose) { | 
| 51 |  |  |  |  |  |  | print "Entering function do_something()\n"; | 
| 52 |  |  |  |  |  |  | } | 
| 53 |  |  |  |  |  |  |  | 
| 54 |  |  |  |  |  |  | # ... | 
| 55 |  |  |  |  |  |  | } | 
| 56 |  |  |  |  |  |  |  | 
| 57 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | This module is yet another command line options parser. But not only. | 
| 60 |  |  |  |  |  |  | Actually, it's an option container. It's a response to a question: after | 
| 61 |  |  |  |  |  |  | parsing options (from command line and from config file), how do I pass them | 
| 62 |  |  |  |  |  |  | down the function call stack? | 
| 63 |  |  |  |  |  |  |  | 
| 64 |  |  |  |  |  |  | There are two classic approaches. One utilizes global variables. This is not | 
| 65 |  |  |  |  |  |  | that convenient, because introduces some names treated in special way (not | 
| 66 |  |  |  |  |  |  | defined inside the current function). The other requires passing option | 
| 67 |  |  |  |  |  |  | container as an argument to each and every function (you can't always tell in | 
| 68 |  |  |  |  |  |  | advance that the function will never use the options on one hand, and API | 
| 69 |  |  |  |  |  |  | changes are tedious on the other). | 
| 70 |  |  |  |  |  |  |  | 
| 71 |  |  |  |  |  |  | App::Getconf tries a different way, which is not entirely new: the inspiration | 
| 72 |  |  |  |  |  |  | for this module was L, which is Perl port of log4j Java | 
| 73 |  |  |  |  |  |  | library. The idea is simple: you need a value accessible similarly to a global | 
| 74 |  |  |  |  |  |  | variable, but declared locally. | 
| 75 |  |  |  |  |  |  |  | 
| 76 |  |  |  |  |  |  | =head1 ARCHITECTURE | 
| 77 |  |  |  |  |  |  |  | 
| 78 |  |  |  |  |  |  | App::Getconf consists of three different types of objects: option | 
| 79 |  |  |  |  |  |  | containers, option views and option schema nodes. | 
| 80 |  |  |  |  |  |  |  | 
| 81 |  |  |  |  |  |  | Option container (App::Getconf instance) stores all the options that were set, | 
| 82 |  |  |  |  |  |  | either from command line or from multi-level hash (e.g. loaded config file). | 
| 83 |  |  |  |  |  |  |  | 
| 84 |  |  |  |  |  |  | Option container needs to be initialized with option schema: list of allowed | 
| 85 |  |  |  |  |  |  | options, along with their types (int, float, string, flag and so on). Such | 
| 86 |  |  |  |  |  |  | schema is composed of nodes created with C function or derivatives. | 
| 87 |  |  |  |  |  |  |  | 
| 88 |  |  |  |  |  |  | Option view (L instance) is an interface to options | 
| 89 |  |  |  |  |  |  | list. When option is requested, view does a "lookup" to find appropriate | 
| 90 |  |  |  |  |  |  | option. For example, view C<$v> for I subsystem was created. | 
| 91 |  |  |  |  |  |  | When C<< $v->get('timeout') >> was issued, the view will return value of the | 
| 92 |  |  |  |  |  |  | first existing option: I, I or | 
| 93 |  |  |  |  |  |  | I. Of course there's also a possibility to omit this lookup. | 
| 94 |  |  |  |  |  |  |  | 
| 95 |  |  |  |  |  |  | App::Getconf creates a default option container. This default container is | 
| 96 |  |  |  |  |  |  | used every time when semi-static method (see L"Semi-Static Methods"> | 
| 97 |  |  |  |  |  |  | section) is called as static one. This is how App::Getconf provides a way of | 
| 98 |  |  |  |  |  |  | accessing options globally. However, you are not limited to this default | 
| 99 |  |  |  |  |  |  | container. You may create your own containers with their own option schema. Of | 
| 100 |  |  |  |  |  |  | course you will need to pass them down the call stack. | 
| 101 |  |  |  |  |  |  |  | 
| 102 |  |  |  |  |  |  | =head2 Options Lifecycle | 
| 103 |  |  |  |  |  |  |  | 
| 104 |  |  |  |  |  |  | Option container needs a schema to tell which options are legal and which are | 
| 105 |  |  |  |  |  |  | not. Defining schema is basically the first thing to do. Schema can also | 
| 106 |  |  |  |  |  |  | contain initial values for some options. | 
| 107 |  |  |  |  |  |  |  | 
| 108 |  |  |  |  |  |  | Next go options defined in command line and in config file. Option container | 
| 109 |  |  |  |  |  |  | can parse command line on its own, it just needs an array of arguments. | 
| 110 |  |  |  |  |  |  |  | 
| 111 |  |  |  |  |  |  | Two above steps are only to be done once, at the application start, possibly | 
| 112 |  |  |  |  |  |  | as early as possible. Changing option values, however, is planned in the | 
| 113 |  |  |  |  |  |  | future to be supported after initialization process, at run-time. | 
| 114 |  |  |  |  |  |  |  | 
| 115 |  |  |  |  |  |  | From now on, C method may be used in any part of application. | 
| 116 |  |  |  |  |  |  |  | 
| 117 |  |  |  |  |  |  | =head2 Schema Definition | 
| 118 |  |  |  |  |  |  |  | 
| 119 |  |  |  |  |  |  | Schema is simply a hashref that contains options. Each value is a node (actual | 
| 120 |  |  |  |  |  |  | option or alias) or a sub-schema. | 
| 121 |  |  |  |  |  |  |  | 
| 122 |  |  |  |  |  |  | Full name of an option from sub-schema is I<$schema.$option>, where | 
| 123 |  |  |  |  |  |  | C<${schema}> is the key, under which sub-schema was stored. Command line | 
| 124 |  |  |  |  |  |  | option that sets such option is I<--$schema-$option>. | 
| 125 |  |  |  |  |  |  |  | 
| 126 |  |  |  |  |  |  | Schemas stored under greater depth are analogous. | 
| 127 |  |  |  |  |  |  |  | 
| 128 |  |  |  |  |  |  | Example of schema: | 
| 129 |  |  |  |  |  |  |  | 
| 130 |  |  |  |  |  |  | help    => opt { type => 'flag', ... }, | 
| 131 |  |  |  |  |  |  | version => opt { type => 'flag', ... }, | 
| 132 |  |  |  |  |  |  | verbose => opt { type => 'bool', ... }, | 
| 133 |  |  |  |  |  |  | session => { | 
| 134 |  |  |  |  |  |  | timeout => opt { type => 'int',    ... }, | 
| 135 |  |  |  |  |  |  | path    => opt { type => 'string', ... }, | 
| 136 |  |  |  |  |  |  | ''      => opt { type => 'string', ... }, | 
| 137 |  |  |  |  |  |  | }, | 
| 138 |  |  |  |  |  |  | # ... | 
| 139 |  |  |  |  |  |  |  | 
| 140 |  |  |  |  |  |  | This schema defines options I, I, I, | 
| 141 |  |  |  |  |  |  | I, I and just plain I. The last one is | 
| 142 |  |  |  |  |  |  | example of how to define option of the same name as sub-schema. | 
| 143 |  |  |  |  |  |  |  | 
| 144 |  |  |  |  |  |  | End-user can set these options using command line options, accordingly: | 
| 145 |  |  |  |  |  |  | I<--help>, I<--version>, I<--verbose>/I<--no-verbose>, | 
| 146 |  |  |  |  |  |  | I<--session-timeout=###>, I<--session-path=XXX> and I<--session=XXX>. | 
| 147 |  |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  | Basic way of creating node is using C function, but there are few | 
| 149 |  |  |  |  |  |  | shorthands, like C, C and others. See | 
| 150 |  |  |  |  |  |  | L"Functions Defining Schema"> section for details. | 
| 151 |  |  |  |  |  |  |  | 
| 152 |  |  |  |  |  |  | Schema is also used, beside validating option correctness, for generating | 
| 153 |  |  |  |  |  |  | message printed typically after issuing I<--help> option. Only options having | 
| 154 |  |  |  |  |  |  | C field are included in this message. Other options still may be set in | 
| 155 |  |  |  |  |  |  | command line, but are not exposed to the user. They are meant mainly to be | 
| 156 |  |  |  |  |  |  | specified with configuration file or with other means. | 
| 157 |  |  |  |  |  |  |  | 
| 158 |  |  |  |  |  |  | Order of options in autogenerated help message is lexicographic order. You may | 
| 159 |  |  |  |  |  |  | provide the order by changing Perl's built-in anonymous hashref C<{}> to call | 
| 160 |  |  |  |  |  |  | to function C. Example: | 
| 161 |  |  |  |  |  |  |  | 
| 162 |  |  |  |  |  |  | # ... | 
| 163 |  |  |  |  |  |  | session => schema( | 
| 164 |  |  |  |  |  |  | timeout => opt { type => 'int',    ... }, | 
| 165 |  |  |  |  |  |  | path    => opt { type => 'string', ... }, | 
| 166 |  |  |  |  |  |  | ''      => opt { type => 'string', ... }, | 
| 167 |  |  |  |  |  |  | ), | 
| 168 |  |  |  |  |  |  | # ... | 
| 169 |  |  |  |  |  |  |  | 
| 170 |  |  |  |  |  |  | You may freely mix hashrefs and C calls, at the same or different | 
| 171 |  |  |  |  |  |  | nesting levels. | 
| 172 |  |  |  |  |  |  |  | 
| 173 |  |  |  |  |  |  | =cut | 
| 174 |  |  |  |  |  |  |  | 
| 175 |  |  |  |  |  |  | package App::Getconf; | 
| 176 |  |  |  |  |  |  |  | 
| 177 |  |  |  |  |  |  | #----------------------------------------------------------------------------- | 
| 178 |  |  |  |  |  |  |  | 
| 179 | 10 |  |  | 10 |  | 244108 | use warnings; | 
|  | 10 |  |  |  |  | 29 |  | 
|  | 10 |  |  |  |  | 447 |  | 
| 180 | 10 |  |  | 10 |  | 62 | use strict; | 
|  | 10 |  |  |  |  | 24 |  | 
|  | 10 |  |  |  |  | 460 |  | 
| 181 |  |  |  |  |  |  |  | 
| 182 | 10 |  |  | 10 |  | 58 | use base qw{Exporter}; | 
|  | 10 |  |  |  |  | 22 |  | 
|  | 10 |  |  |  |  | 1154 |  | 
| 183 | 10 |  |  | 10 |  | 62 | use Carp; | 
|  | 10 |  |  |  |  | 22 |  | 
|  | 10 |  |  |  |  | 847 |  | 
| 184 | 10 |  |  | 10 |  | 6458 | use App::Getconf::View; | 
|  | 10 |  |  |  |  | 28 |  | 
|  | 10 |  |  |  |  | 400 |  | 
| 185 | 10 |  |  | 10 |  | 6726 | use App::Getconf::Node; | 
|  | 10 |  |  |  |  | 43 |  | 
|  | 10 |  |  |  |  | 325 |  | 
| 186 | 10 |  |  | 10 |  | 10100 | use Tie::IxHash; | 
|  | 10 |  |  |  |  | 62319 |  | 
|  | 10 |  |  |  |  | 64003 |  | 
| 187 |  |  |  |  |  |  |  | 
| 188 |  |  |  |  |  |  | our $VERSION = '0.20.04'; | 
| 189 |  |  |  |  |  |  |  | 
| 190 |  |  |  |  |  |  | our @EXPORT_OK = qw( | 
| 191 |  |  |  |  |  |  | schema | 
| 192 |  |  |  |  |  |  | opt        opt_alias | 
| 193 |  |  |  |  |  |  | opt_flag   opt_bool | 
| 194 |  |  |  |  |  |  | opt_int    opt_float | 
| 195 |  |  |  |  |  |  | opt_string opt_path   opt_hostname | 
| 196 |  |  |  |  |  |  | opt_re     opt_sub    opt_enum | 
| 197 |  |  |  |  |  |  | ); | 
| 198 |  |  |  |  |  |  |  | 
| 199 |  |  |  |  |  |  | our %EXPORT_TAGS = ( | 
| 200 |  |  |  |  |  |  | schema => [ 'schema', grep { /^opt/ } @EXPORT_OK ], | 
| 201 |  |  |  |  |  |  | ); | 
| 202 |  |  |  |  |  |  |  | 
| 203 |  |  |  |  |  |  | #----------------------------------------------------------------------------- | 
| 204 |  |  |  |  |  |  |  | 
| 205 |  |  |  |  |  |  | my $static = new App::Getconf(); | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | #----------------------------------------------------------------------------- | 
| 208 |  |  |  |  |  |  |  | 
| 209 |  |  |  |  |  |  | =head1 MODULE API | 
| 210 |  |  |  |  |  |  |  | 
| 211 |  |  |  |  |  |  | Following methods are available: | 
| 212 |  |  |  |  |  |  |  | 
| 213 |  |  |  |  |  |  | =over | 
| 214 |  |  |  |  |  |  |  | 
| 215 |  |  |  |  |  |  | =cut | 
| 216 |  |  |  |  |  |  |  | 
| 217 |  |  |  |  |  |  | #----------------------------------------------------------------------------- | 
| 218 |  |  |  |  |  |  |  | 
| 219 |  |  |  |  |  |  | =item C | 
| 220 |  |  |  |  |  |  |  | 
| 221 |  |  |  |  |  |  | Constructor. | 
| 222 |  |  |  |  |  |  |  | 
| 223 |  |  |  |  |  |  | No options are used at the moment. | 
| 224 |  |  |  |  |  |  |  | 
| 225 |  |  |  |  |  |  | B: You don't need to use the constructor. You may (and typically would) | 
| 226 |  |  |  |  |  |  | want to use App::Getconf's default container. | 
| 227 |  |  |  |  |  |  |  | 
| 228 |  |  |  |  |  |  | =cut | 
| 229 |  |  |  |  |  |  |  | 
| 230 |  |  |  |  |  |  | sub new { | 
| 231 | 89 |  |  | 89 | 1 | 4542 | my ($class, %opts) = @_; | 
| 232 |  |  |  |  |  |  |  | 
| 233 | 89 |  |  |  |  | 746 | my $self = bless { | 
| 234 |  |  |  |  |  |  | aliases => undef, | 
| 235 |  |  |  |  |  |  | options => undef, | 
| 236 |  |  |  |  |  |  | args    => undef, | 
| 237 |  |  |  |  |  |  | help    => { | 
| 238 |  |  |  |  |  |  | message => undef, | 
| 239 |  |  |  |  |  |  | order   => undef, | 
| 240 |  |  |  |  |  |  | }, | 
| 241 |  |  |  |  |  |  | # each getopt() will return | 
| 242 |  |  |  |  |  |  | getopt_cache  => {}, | 
| 243 |  |  |  |  |  |  | }, $class; | 
| 244 |  |  |  |  |  |  |  | 
| 245 | 89 |  |  |  |  | 307 | return $self; | 
| 246 |  |  |  |  |  |  | } | 
| 247 |  |  |  |  |  |  |  | 
| 248 |  |  |  |  |  |  | #----------------------------------------------------------------------------- | 
| 249 |  |  |  |  |  |  |  | 
| 250 |  |  |  |  |  |  | =back | 
| 251 |  |  |  |  |  |  |  | 
| 252 |  |  |  |  |  |  | =head2 Semi-Static Methods | 
| 253 |  |  |  |  |  |  |  | 
| 254 |  |  |  |  |  |  | Methods from this section can be called as instance methods, when you have | 
| 255 |  |  |  |  |  |  | created own instance of C, or as static methods, when they | 
| 256 |  |  |  |  |  |  | operate on default instance of C. Typically you would use the | 
| 257 |  |  |  |  |  |  | latter strategy, as passing option container down the function call stack is | 
| 258 |  |  |  |  |  |  | somewhat troublesome. | 
| 259 |  |  |  |  |  |  |  | 
| 260 |  |  |  |  |  |  | =over | 
| 261 |  |  |  |  |  |  |  | 
| 262 |  |  |  |  |  |  | =cut | 
| 263 |  |  |  |  |  |  |  | 
| 264 |  |  |  |  |  |  | #----------------------------------------------------------------------------- | 
| 265 |  |  |  |  |  |  |  | 
| 266 |  |  |  |  |  |  | =item C | 
| 267 |  |  |  |  |  |  |  | 
| 268 |  |  |  |  |  |  | =item C<< option_schema(key => value, key => value, ...) >> | 
| 269 |  |  |  |  |  |  |  | 
| 270 |  |  |  |  |  |  | Set expected schema for the options. Schema may be either a hashref (Perl's | 
| 271 |  |  |  |  |  |  | ordinary or created using C function) or a list of key/value pairs. | 
| 272 |  |  |  |  |  |  | The latter form has the same result as passing the list to C first, | 
| 273 |  |  |  |  |  |  | i.e., the options order will be preserved. | 
| 274 |  |  |  |  |  |  |  | 
| 275 |  |  |  |  |  |  | =cut | 
| 276 |  |  |  |  |  |  |  | 
| 277 |  |  |  |  |  |  | sub option_schema { | 
| 278 | 78 |  |  | 78 | 1 | 265 | my ($self, @args) = @_; | 
| 279 |  |  |  |  |  |  |  | 
| 280 | 78 | 50 |  |  |  | 325 | my $schema = (@args == 1) ? $args[0] : schema(@args);; | 
| 281 |  |  |  |  |  |  |  | 
| 282 | 78 | 50 |  |  |  | 366 | $self = $static unless ref $self; # static call or non-static? | 
| 283 |  |  |  |  |  |  |  | 
| 284 | 78 |  |  |  |  | 209 | my @schema = _flatten($schema, ""); | 
| 285 | 78 |  |  |  |  | 232 | $self->{options} = {}; | 
| 286 | 78 |  |  |  |  | 168 | $self->{aliases} = {}; | 
| 287 | 78 |  |  |  |  | 186 | $self->{help}{order} = []; | 
| 288 | 78 |  |  |  |  | 250 | for my $opt (@schema) { | 
| 289 | 364 | 100 |  |  |  | 1307 | if ($opt->{opt}->alias) { | 
| 290 |  |  |  |  |  |  | # alias option | 
| 291 |  |  |  |  |  |  |  | 
| 292 | 43 |  |  |  |  | 177 | $self->{aliases}{ $opt->{name} } = $opt->{opt}; | 
| 293 |  |  |  |  |  |  |  | 
| 294 |  |  |  |  |  |  | } else { | 
| 295 |  |  |  |  |  |  | # normal (non-alias) option | 
| 296 |  |  |  |  |  |  |  | 
| 297 | 321 |  |  |  |  | 999 | $self->{options}{ $opt->{name} } = $opt->{opt}; | 
| 298 |  |  |  |  |  |  | # remember the order of messages | 
| 299 | 321 | 50 |  |  |  | 1002 | if ($opt->{opt}->help) { | 
| 300 | 0 |  |  |  |  | 0 | push @{ $self->{help}{order} }, $opt->{name}; | 
|  | 0 |  |  |  |  | 0 |  | 
| 301 |  |  |  |  |  |  | } | 
| 302 |  |  |  |  |  |  | } | 
| 303 |  |  |  |  |  |  | } | 
| 304 |  |  |  |  |  |  |  | 
| 305 |  |  |  |  |  |  | # NOTE: this can't be moved to inside the previous loop, because there could | 
| 306 |  |  |  |  |  |  | # be an alias processed earlier than the option it points to | 
| 307 | 78 |  |  |  |  | 149 | for my $name (sort keys %{ $self->{aliases} }) { | 
|  | 78 |  |  |  |  | 920 |  | 
| 308 | 43 |  |  |  |  | 151 | my $dest = $self->{aliases}{$name}->alias; | 
| 309 |  |  |  |  |  |  |  | 
| 310 |  |  |  |  |  |  | # option can't be an alias and non-alias at the same time | 
| 311 | 43 | 50 |  |  |  | 520 | if ($self->{aliases}{$dest}) { | 
|  |  | 50 |  |  |  |  |  | 
| 312 | 0 |  |  |  |  | 0 | croak "Alias \"$name\" points to another alias called \"$dest\""; | 
| 313 |  |  |  |  |  |  | } elsif (not $self->{options}{$dest}) { | 
| 314 | 0 |  |  |  |  | 0 | croak "Alias \"$name\" points to a non-existent option \"$dest\""; | 
| 315 |  |  |  |  |  |  | } | 
| 316 |  |  |  |  |  |  | } | 
| 317 |  |  |  |  |  |  | } | 
| 318 |  |  |  |  |  |  |  | 
| 319 |  |  |  |  |  |  | =begin Internal | 
| 320 |  |  |  |  |  |  |  | 
| 321 |  |  |  |  |  |  | =pod _flatten() {{{ | 
| 322 |  |  |  |  |  |  |  | 
| 323 |  |  |  |  |  |  | =item C<_flatten($root, $path)> | 
| 324 |  |  |  |  |  |  |  | 
| 325 |  |  |  |  |  |  | Function flattens schema hashref tree to a flat hash, where option names are | 
| 326 |  |  |  |  |  |  | separated by C<.>. | 
| 327 |  |  |  |  |  |  |  | 
| 328 |  |  |  |  |  |  | C<$root> is a root of schema hashref tree to convert (recursively). | 
| 329 |  |  |  |  |  |  | C<$path> is used to keep path so far in recursive call. It should be an empty string initially. | 
| 330 |  |  |  |  |  |  |  | 
| 331 |  |  |  |  |  |  | Returned value is a hash with two fields: I contains full option path, | 
| 332 |  |  |  |  |  |  | and I is actual L object. | 
| 333 |  |  |  |  |  |  |  | 
| 334 |  |  |  |  |  |  | =cut | 
| 335 |  |  |  |  |  |  |  | 
| 336 |  |  |  |  |  |  | sub _flatten { | 
| 337 | 128 |  |  | 128 |  | 287 | my ($root, $path) = @_; | 
| 338 |  |  |  |  |  |  |  | 
| 339 | 128 | 100 |  |  |  | 454 | my @opts = eval { tied(%$root)->isa("Tie::IxHash") } ? | 
|  | 128 |  |  |  |  | 1306 |  | 
| 340 |  |  |  |  |  |  | keys %$root : | 
| 341 |  |  |  |  |  |  | sort keys %$root; | 
| 342 | 128 |  |  |  |  | 2706 | my @result; | 
| 343 | 128 |  |  |  |  | 251 | for my $o (@opts) { | 
| 344 | 414 | 100 |  |  |  | 3537 | if (eval { $root->{$o}->isa("App::Getconf::Node") }) { | 
|  | 414 | 50 |  |  |  | 5248 |  | 
| 345 | 364 |  |  |  |  | 4053 | my $name = "$path.$o"; | 
| 346 | 364 |  |  |  |  | 2513 | $name =~ s/^\.|\.$//g; | 
| 347 | 364 |  |  |  |  | 2096 | push @result, { name => $name, opt => $root->{$o} }; | 
| 348 |  |  |  |  |  |  | } elsif (ref $root->{$o} eq 'HASH') { | 
| 349 |  |  |  |  |  |  | # XXX: don't try $root->{$o}{""}, it will be collected in the recursive | 
| 350 |  |  |  |  |  |  | # _flatten() call (note that this may leave trailing period for this | 
| 351 |  |  |  |  |  |  | # option) | 
| 352 | 50 |  |  |  |  | 1345 | push @result, _flatten($root->{$o}, "$path.$o"); | 
| 353 |  |  |  |  |  |  | } | 
| 354 |  |  |  |  |  |  | } | 
| 355 | 128 |  |  |  |  | 2435 | return @result; | 
| 356 |  |  |  |  |  |  | } | 
| 357 |  |  |  |  |  |  |  | 
| 358 |  |  |  |  |  |  | =end Internal | 
| 359 |  |  |  |  |  |  |  | 
| 360 |  |  |  |  |  |  | =pod }}} | 
| 361 |  |  |  |  |  |  |  | 
| 362 |  |  |  |  |  |  | =cut | 
| 363 |  |  |  |  |  |  |  | 
| 364 |  |  |  |  |  |  | #----------------------------------------------------------------------------- | 
| 365 |  |  |  |  |  |  |  | 
| 366 |  |  |  |  |  |  | =item C | 
| 367 |  |  |  |  |  |  |  | 
| 368 |  |  |  |  |  |  | Return message printed when I<--help> (or similar) option was passed. Message | 
| 369 |  |  |  |  |  |  | will be C<\n>-terminated. | 
| 370 |  |  |  |  |  |  |  | 
| 371 |  |  |  |  |  |  | Typical usage: | 
| 372 |  |  |  |  |  |  |  | 
| 373 |  |  |  |  |  |  | if (App::Getconf->getopt->help) { | 
| 374 |  |  |  |  |  |  | print App::Getconf->help_message( | 
| 375 |  |  |  |  |  |  | screen   => 130, | 
| 376 |  |  |  |  |  |  | synopsis => "%0 [ options ] file ...", | 
| 377 |  |  |  |  |  |  | ); | 
| 378 |  |  |  |  |  |  | exit 0; | 
| 379 |  |  |  |  |  |  | } | 
| 380 |  |  |  |  |  |  |  | 
| 381 |  |  |  |  |  |  | Supported options: | 
| 382 |  |  |  |  |  |  |  | 
| 383 |  |  |  |  |  |  | =over | 
| 384 |  |  |  |  |  |  |  | 
| 385 |  |  |  |  |  |  | =item C (default: 80) | 
| 386 |  |  |  |  |  |  |  | 
| 387 |  |  |  |  |  |  | Screen width, in columns. | 
| 388 |  |  |  |  |  |  |  | 
| 389 |  |  |  |  |  |  | =item C (default: C<$0> with path stripped) | 
| 390 |  |  |  |  |  |  |  | 
| 391 |  |  |  |  |  |  | Name of the program. Usually C<$0> or a derivative. | 
| 392 |  |  |  |  |  |  |  | 
| 393 |  |  |  |  |  |  | =item C (default: C<%0 [ options ... ]>) | 
| 394 |  |  |  |  |  |  |  | 
| 395 |  |  |  |  |  |  | Short call summary. Any occurrence of C<%0> will be replaced with content of | 
| 396 |  |  |  |  |  |  | C option. | 
| 397 |  |  |  |  |  |  |  | 
| 398 |  |  |  |  |  |  | Synopsis may be also a multiline string or an array of single-line strings. | 
| 399 |  |  |  |  |  |  |  | 
| 400 |  |  |  |  |  |  | =item C | 
| 401 |  |  |  |  |  |  |  | 
| 402 |  |  |  |  |  |  | =item C | 
| 403 |  |  |  |  |  |  |  | 
| 404 |  |  |  |  |  |  | =item C | 
| 405 |  |  |  |  |  |  |  | 
| 406 |  |  |  |  |  |  | Three additional text fields: before synopsis, after synopsis but before | 
| 407 |  |  |  |  |  |  | options list, after options list. | 
| 408 |  |  |  |  |  |  |  | 
| 409 |  |  |  |  |  |  | Text will be re-wrapped to fit on a terminal of C width. Empty lines | 
| 410 |  |  |  |  |  |  | will be treated as paragraph separators, but single newline characters will | 
| 411 |  |  |  |  |  |  | not be preserved. | 
| 412 |  |  |  |  |  |  |  | 
| 413 |  |  |  |  |  |  | Any occurrence of C<%0> will be replaced with content of C option. | 
| 414 |  |  |  |  |  |  |  | 
| 415 |  |  |  |  |  |  | =item C (default: 2) | 
| 416 |  |  |  |  |  |  |  | 
| 417 |  |  |  |  |  |  | =item C (default: 6) | 
| 418 |  |  |  |  |  |  |  | 
| 419 |  |  |  |  |  |  | Indenting for option header ("--option" with parameter specification, if any) | 
| 420 |  |  |  |  |  |  | and for option description. | 
| 421 |  |  |  |  |  |  |  | 
| 422 |  |  |  |  |  |  | =back | 
| 423 |  |  |  |  |  |  |  | 
| 424 |  |  |  |  |  |  | =cut | 
| 425 |  |  |  |  |  |  |  | 
| 426 |  |  |  |  |  |  | sub help_message { | 
| 427 | 0 |  |  | 0 | 1 | 0 | my ($self, %opts) = @_; | 
| 428 |  |  |  |  |  |  |  | 
| 429 | 0 | 0 |  |  |  | 0 | $self = $static unless ref $self; # static call or non-static? | 
| 430 |  |  |  |  |  |  |  | 
| 431 | 0 |  | 0 |  |  | 0 | $opts{screen}   ||= 80; | 
| 432 | 0 |  | 0 |  |  | 0 | $opts{arg0}     ||= (split m[/], $0)[-1]; | 
| 433 | 0 |  | 0 |  |  | 0 | $opts{synopsis} ||= "%0 [ options ... ]"; | 
| 434 |  |  |  |  |  |  |  | 
| 435 | 0 |  | 0 |  |  | 0 | $opts{option_indent}      ||= 2; | 
| 436 | 0 |  | 0 |  |  | 0 | $opts{description_indent} ||= 6; | 
| 437 |  |  |  |  |  |  |  | 
| 438 |  |  |  |  |  |  | # $opts{header}      ||= undef; | 
| 439 |  |  |  |  |  |  | # $opts{description} ||= undef; | 
| 440 |  |  |  |  |  |  | # $opts{footer}      ||= undef; | 
| 441 |  |  |  |  |  |  |  | 
| 442 | 0 |  |  |  |  | 0 | my $help = ""; | 
| 443 | 0 |  |  |  |  | 0 | my $line; | 
| 444 |  |  |  |  |  |  | my %format_markers; | 
| 445 |  |  |  |  |  |  |  | 
| 446 |  |  |  |  |  |  | #--------------------------------------------------------- | 
| 447 |  |  |  |  |  |  | # header {{{ | 
| 448 |  |  |  |  |  |  |  | 
| 449 | 0 | 0 |  |  |  | 0 | if ($opts{header}) { | 
| 450 | 0 |  |  |  |  | 0 | $line = _reformat($opts{header}, $opts{screen}); | 
| 451 | 0 |  |  |  |  | 0 | $line =~ s/%0/$opts{arg0}/g; | 
| 452 |  |  |  |  |  |  |  | 
| 453 | 0 |  |  |  |  | 0 | $help .= $line; | 
| 454 | 0 |  |  |  |  | 0 | $help .= "\n"; # additional empty line | 
| 455 |  |  |  |  |  |  | } | 
| 456 |  |  |  |  |  |  |  | 
| 457 |  |  |  |  |  |  | # }}} | 
| 458 |  |  |  |  |  |  | #--------------------------------------------------------- | 
| 459 |  |  |  |  |  |  | # synopsis {{{ | 
| 460 |  |  |  |  |  |  |  | 
| 461 | 0 | 0 |  |  |  | 0 | if (ref $opts{synopsis} eq 'ARRAY') { | 
| 462 | 0 |  |  |  |  | 0 | $line = join "\n", @{ $opts{synopsis} }; | 
|  | 0 |  |  |  |  | 0 |  | 
| 463 |  |  |  |  |  |  | } else { | 
| 464 | 0 |  |  |  |  | 0 | $line = $opts{synopsis}; | 
| 465 |  |  |  |  |  |  | } | 
| 466 | 0 |  |  |  |  | 0 | $line =~ s/%0/$opts{arg0}/g; | 
| 467 |  |  |  |  |  |  |  | 
| 468 | 0 |  |  |  |  | 0 | $line =~ s/\s+$//; # strip leading spaces | 
| 469 |  |  |  |  |  |  |  | 
| 470 | 0 | 0 |  |  |  | 0 | if ($line =~ /\n./) { | 
| 471 |  |  |  |  |  |  | # multiline synopsis | 
| 472 | 0 |  |  |  |  | 0 | $format_markers{multiline_synopsis} = 1; | 
| 473 |  |  |  |  |  |  |  | 
| 474 | 0 |  |  |  |  | 0 | $line =~ s/^[ \t]*/  /mg; # uniform indentation | 
| 475 | 0 |  |  |  |  | 0 | $help .= sprintf "Usage:\n%s\n", $line; | 
| 476 |  |  |  |  |  |  |  | 
| 477 |  |  |  |  |  |  | } else { | 
| 478 |  |  |  |  |  |  | # single line synopsis | 
| 479 |  |  |  |  |  |  |  | 
| 480 | 0 |  |  |  |  | 0 | $line =~ s/^\s+//; # strip leading spaces | 
| 481 | 0 | 0 |  |  |  | 0 | if (length($line) < $opts{screen} - 1 - length("Usage: ")) { | 
| 482 | 0 |  |  |  |  | 0 | $help .= sprintf "Usage: %s\n", $line; | 
| 483 |  |  |  |  |  |  | } else { | 
| 484 | 0 |  |  |  |  | 0 | $format_markers{multiline_synopsis} = 1; | 
| 485 | 0 |  |  |  |  | 0 | $help .= sprintf "Usage:\n%s\n", $line; | 
| 486 |  |  |  |  |  |  | } | 
| 487 |  |  |  |  |  |  |  | 
| 488 |  |  |  |  |  |  | } | 
| 489 |  |  |  |  |  |  |  | 
| 490 |  |  |  |  |  |  | # }}} | 
| 491 |  |  |  |  |  |  | #--------------------------------------------------------- | 
| 492 |  |  |  |  |  |  | # description (below synopsis) {{{ | 
| 493 |  |  |  |  |  |  |  | 
| 494 | 0 | 0 |  |  |  | 0 | if ($opts{description}) { | 
| 495 | 0 |  |  |  |  | 0 | $line = _reformat($opts{description}, $opts{screen}); | 
| 496 | 0 |  |  |  |  | 0 | $line =~ s/%0/$opts{arg0}/g; | 
| 497 |  |  |  |  |  |  |  | 
| 498 | 0 |  |  |  |  | 0 | $help .= "\n"; | 
| 499 | 0 |  |  |  |  | 0 | $help .= $line; | 
| 500 |  |  |  |  |  |  |  | 
| 501 | 0 |  |  |  |  | 0 | $format_markers{multiline_synopsis} = 1; | 
| 502 |  |  |  |  |  |  | } | 
| 503 |  |  |  |  |  |  |  | 
| 504 |  |  |  |  |  |  | # }}} | 
| 505 |  |  |  |  |  |  | #--------------------------------------------------------- | 
| 506 |  |  |  |  |  |  | # options {{{ | 
| 507 |  |  |  |  |  |  |  | 
| 508 | 0 | 0 | 0 |  |  | 0 | if ($self->{help}{order} && @{ $self->{help}{order} }) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 509 | 0 |  |  |  |  | 0 | $line = "Options available:\n"; | 
| 510 |  |  |  |  |  |  |  | 
| 511 | 0 |  |  |  |  | 0 | for my $opt (@{ $self->{help}{order} }) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 512 | 0 | 0 |  |  |  | 0 | my $dash_opt = (length $opt > 1) ? "--$opt" : "-$opt"; | 
| 513 | 0 |  |  |  |  | 0 | $dash_opt =~ tr/./-/; | 
| 514 |  |  |  |  |  |  |  | 
| 515 | 0 |  |  |  |  | 0 | my $node = $self->option_node($opt); | 
| 516 |  |  |  |  |  |  |  | 
| 517 | 0 |  |  |  |  | 0 | my $init_val = ""; | 
| 518 | 0 | 0 |  |  |  | 0 | if ($node->has_value) { | 
| 519 | 0 |  |  |  |  | 0 | $init_val = $node->get; | 
| 520 | 0 | 0 |  |  |  | 0 | $init_val = "" if not defined $init_val; | 
| 521 | 0 |  |  |  |  | 0 | $init_val = " (initially: $init_val)"; | 
| 522 |  |  |  |  |  |  | } | 
| 523 |  |  |  |  |  |  |  | 
| 524 |  |  |  |  |  |  | # option header (indented "--option") {{{ | 
| 525 |  |  |  |  |  |  | # TODO: aliases | 
| 526 | 0 | 0 |  |  |  | 0 | if ($node->type eq 'flag') { | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 527 | 0 |  |  |  |  | 0 | $line .= sprintf "%*s%s\n", $opts{option_indent}, "", $dash_opt; | 
| 528 |  |  |  |  |  |  | } elsif ($node->type eq 'bool') { | 
| 529 | 0 |  |  |  |  | 0 | my $neg_dash_opt = "--no-$opt"; | 
| 530 | 0 |  |  |  |  | 0 | $neg_dash_opt =~ tr/./-/; | 
| 531 | 0 | 0 |  |  |  | 0 | $line .= sprintf "%*s%s, %s\n", | 
| 532 |  |  |  |  |  |  | $opts{option_indent}, "", | 
| 533 |  |  |  |  |  |  | ($node->get ? | 
| 534 |  |  |  |  |  |  | ($neg_dash_opt, $dash_opt) : | 
| 535 |  |  |  |  |  |  | ($dash_opt, $neg_dash_opt)); | 
| 536 |  |  |  |  |  |  | } elsif ($node->has_default) { | 
| 537 | 0 |  |  |  |  | 0 | my $type = $node->type; | 
| 538 | 0 | 0 |  |  |  | 0 | if ($node->enum) { | 
| 539 | 0 |  |  |  |  | 0 | $type = join "|", @{ $node->enum }; | 
|  | 0 |  |  |  |  | 0 |  | 
| 540 |  |  |  |  |  |  | } | 
| 541 | 0 |  |  |  |  | 0 | $line .= sprintf "%*s%s, %s=%s%s\n", | 
| 542 |  |  |  |  |  |  | $opts{option_indent}, "", | 
| 543 |  |  |  |  |  |  | $dash_opt, | 
| 544 |  |  |  |  |  |  | $dash_opt, $type, | 
| 545 |  |  |  |  |  |  | $init_val; | 
| 546 |  |  |  |  |  |  | } else { | 
| 547 | 0 |  |  |  |  | 0 | my $type = $node->type; | 
| 548 | 0 | 0 |  |  |  | 0 | if ($node->enum) { | 
| 549 | 0 |  |  |  |  | 0 | $type = join "|", @{ $node->enum }; | 
|  | 0 |  |  |  |  | 0 |  | 
| 550 |  |  |  |  |  |  | } | 
| 551 |  |  |  |  |  |  |  | 
| 552 | 0 |  |  |  |  | 0 | $line .= sprintf "%*s%s=%s%s\n", | 
| 553 |  |  |  |  |  |  | $opts{option_indent}, "", | 
| 554 |  |  |  |  |  |  | $dash_opt, $type, | 
| 555 |  |  |  |  |  |  | $init_val; | 
| 556 |  |  |  |  |  |  | } | 
| 557 |  |  |  |  |  |  | # }}} | 
| 558 |  |  |  |  |  |  |  | 
| 559 |  |  |  |  |  |  | # option description (reformatted help message) # {{{ | 
| 560 | 0 |  |  |  |  | 0 | $line .= _reformat( | 
| 561 |  |  |  |  |  |  | $node->help, | 
| 562 |  |  |  |  |  |  | $opts{screen}, $opts{description_indent} | 
| 563 |  |  |  |  |  |  | ); | 
| 564 |  |  |  |  |  |  | # }}} | 
| 565 |  |  |  |  |  |  | } | 
| 566 |  |  |  |  |  |  |  | 
| 567 | 0 | 0 | 0 |  |  | 0 | if (_nlines($line) > 16 || $format_markers{multiline_synopsis} || | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 568 |  |  |  |  |  |  | $opts{header} || $opts{description}) { | 
| 569 |  |  |  |  |  |  | # additional empty line between synopsis and options description | 
| 570 | 0 |  |  |  |  | 0 | $help .= "\n"; | 
| 571 |  |  |  |  |  |  | } | 
| 572 |  |  |  |  |  |  |  | 
| 573 | 0 |  |  |  |  | 0 | $help .= $line; | 
| 574 | 0 |  |  |  |  | 0 | $format_markers{has_options} = 1; | 
| 575 |  |  |  |  |  |  | } | 
| 576 |  |  |  |  |  |  |  | 
| 577 |  |  |  |  |  |  | # }}} | 
| 578 |  |  |  |  |  |  | #--------------------------------------------------------- | 
| 579 |  |  |  |  |  |  | # footer {{{ | 
| 580 |  |  |  |  |  |  |  | 
| 581 | 0 | 0 |  |  |  | 0 | if ($opts{footer}) { | 
| 582 | 0 |  |  |  |  | 0 | $line = _reformat($opts{footer}, $opts{screen}); | 
| 583 | 0 |  |  |  |  | 0 | $line =~ s/%0/$opts{arg0}/g; | 
| 584 |  |  |  |  |  |  |  | 
| 585 | 0 |  |  |  |  | 0 | $help .= "\n"; | 
| 586 | 0 |  |  |  |  | 0 | $help .= $line; | 
| 587 |  |  |  |  |  |  | } | 
| 588 |  |  |  |  |  |  |  | 
| 589 |  |  |  |  |  |  | # }}} | 
| 590 |  |  |  |  |  |  | #--------------------------------------------------------- | 
| 591 |  |  |  |  |  |  |  | 
| 592 | 0 |  |  |  |  | 0 | return $help; | 
| 593 |  |  |  |  |  |  | } | 
| 594 |  |  |  |  |  |  |  | 
| 595 |  |  |  |  |  |  | =begin Internal | 
| 596 |  |  |  |  |  |  |  | 
| 597 |  |  |  |  |  |  | =pod _nlines(), _reformat() {{{ | 
| 598 |  |  |  |  |  |  |  | 
| 599 |  |  |  |  |  |  | =item C<_nlines($string)> | 
| 600 |  |  |  |  |  |  |  | 
| 601 |  |  |  |  |  |  | Calculate number of lines in C<$string>. | 
| 602 |  |  |  |  |  |  |  | 
| 603 |  |  |  |  |  |  | =cut | 
| 604 |  |  |  |  |  |  |  | 
| 605 |  |  |  |  |  |  | sub _nlines { | 
| 606 | 0 |  |  | 0 |  | 0 | my ($str) = @_; | 
| 607 |  |  |  |  |  |  |  | 
| 608 | 0 |  |  |  |  | 0 | my $nlines =()= ($str =~ /\n/g); | 
| 609 |  |  |  |  |  |  |  | 
| 610 | 0 |  |  |  |  | 0 | return $nlines; | 
| 611 |  |  |  |  |  |  | } | 
| 612 |  |  |  |  |  |  |  | 
| 613 |  |  |  |  |  |  | =item C<_reformat($string, $max_width, $indent)> | 
| 614 |  |  |  |  |  |  |  | 
| 615 |  |  |  |  |  |  | Reformat a multiparagraph string to include maximum of C<$width-1> characters | 
| 616 |  |  |  |  |  |  | per line, including indentation. | 
| 617 |  |  |  |  |  |  |  | 
| 618 |  |  |  |  |  |  | =cut | 
| 619 |  |  |  |  |  |  |  | 
| 620 |  |  |  |  |  |  | sub _reformat { | 
| 621 | 0 |  |  | 0 |  | 0 | my ($str, $width, $indent) = @_; | 
| 622 |  |  |  |  |  |  |  | 
| 623 | 0 |  | 0 |  |  | 0 | $indent ||= 0; | 
| 624 |  |  |  |  |  |  |  | 
| 625 | 0 |  |  |  |  | 0 | my @result; | 
| 626 |  |  |  |  |  |  |  | 
| 627 | 0 |  |  |  |  | 0 | $str =~ s/^\s+//; | 
| 628 | 0 |  |  |  |  | 0 | for my $para (split /\n\s*\n[ \t]*/, $str) { | 
| 629 | 0 |  |  |  |  | 0 | my $r = ""; | 
| 630 | 0 |  |  |  |  | 0 | my $line = ""; | 
| 631 | 0 |  |  |  |  | 0 | for my $w (split /\s+/, $para) { | 
| 632 | 0 | 0 |  |  |  | 0 | if ($line eq "") { | 
|  |  | 0 |  |  |  |  |  | 
| 633 | 0 |  |  |  |  | 0 | $line = (" " x $indent) . $w; | 
| 634 |  |  |  |  |  |  | } elsif (length($line) + 1 + length($w) < $width) { | 
| 635 | 0 |  |  |  |  | 0 | $line .= " " . $w; | 
| 636 |  |  |  |  |  |  | } else { | 
| 637 | 0 |  |  |  |  | 0 | $r .= $line . "\n"; | 
| 638 | 0 |  |  |  |  | 0 | $line = (" " x $indent) . $w; | 
| 639 |  |  |  |  |  |  | } | 
| 640 |  |  |  |  |  |  | } | 
| 641 | 0 |  |  |  |  | 0 | $r .= $line . "\n"; | 
| 642 | 0 |  |  |  |  | 0 | push @result, $r; | 
| 643 |  |  |  |  |  |  | } | 
| 644 |  |  |  |  |  |  |  | 
| 645 | 0 |  |  |  |  | 0 | return join "\n", @result; | 
| 646 |  |  |  |  |  |  | } | 
| 647 |  |  |  |  |  |  |  | 
| 648 |  |  |  |  |  |  | =end Internal | 
| 649 |  |  |  |  |  |  |  | 
| 650 |  |  |  |  |  |  | =pod }}} | 
| 651 |  |  |  |  |  |  |  | 
| 652 |  |  |  |  |  |  | =cut | 
| 653 |  |  |  |  |  |  |  | 
| 654 |  |  |  |  |  |  | #----------------------------------------------------------------------------- | 
| 655 |  |  |  |  |  |  |  | 
| 656 |  |  |  |  |  |  | =item C | 
| 657 |  |  |  |  |  |  |  | 
| 658 |  |  |  |  |  |  | Set options read from configuration file (hashref). | 
| 659 |  |  |  |  |  |  |  | 
| 660 |  |  |  |  |  |  | Example usage: | 
| 661 |  |  |  |  |  |  |  | 
| 662 |  |  |  |  |  |  | App::Getconf->options(YAML::LoadFile("/etc/myapp.yaml")); | 
| 663 |  |  |  |  |  |  |  | 
| 664 |  |  |  |  |  |  | =cut | 
| 665 |  |  |  |  |  |  |  | 
| 666 |  |  |  |  |  |  | sub options { | 
| 667 | 31 |  |  | 31 | 1 | 61 | my ($self, $options) = @_; | 
| 668 |  |  |  |  |  |  |  | 
| 669 | 31 | 50 |  |  |  | 89 | $self = $static unless ref $self; # static call or non-static? | 
| 670 |  |  |  |  |  |  |  | 
| 671 | 31 |  |  |  |  | 94 | $self->set_verify($options); | 
| 672 |  |  |  |  |  |  | } | 
| 673 |  |  |  |  |  |  |  | 
| 674 |  |  |  |  |  |  | #----------------------------------------------------------------------------- | 
| 675 |  |  |  |  |  |  |  | 
| 676 |  |  |  |  |  |  | =item C | 
| 677 |  |  |  |  |  |  |  | 
| 678 |  |  |  |  |  |  | Set options based on command line arguments (arrayref). If C<$arguments> was | 
| 679 |  |  |  |  |  |  | not specified, C<@ARGV> is used. | 
| 680 |  |  |  |  |  |  |  | 
| 681 |  |  |  |  |  |  | Method returns list of messages (single line, no C<\n> at end) for errors that | 
| 682 |  |  |  |  |  |  | were found, naturally empty if nothing was found. | 
| 683 |  |  |  |  |  |  |  | 
| 684 |  |  |  |  |  |  | Arguments that were not options can be retrieved using C method. | 
| 685 |  |  |  |  |  |  |  | 
| 686 |  |  |  |  |  |  | Example usage: | 
| 687 |  |  |  |  |  |  |  | 
| 688 |  |  |  |  |  |  | App::Getconf->cmdline(\@ARGV); | 
| 689 |  |  |  |  |  |  | # the same: App::Getconf->cmdline(); | 
| 690 |  |  |  |  |  |  | for my $arg (App::Getconf->args()) { | 
| 691 |  |  |  |  |  |  | # ... | 
| 692 |  |  |  |  |  |  | } | 
| 693 |  |  |  |  |  |  |  | 
| 694 |  |  |  |  |  |  | =cut | 
| 695 |  |  |  |  |  |  |  | 
| 696 |  |  |  |  |  |  | sub cmdline { | 
| 697 | 41 |  |  | 41 | 1 | 82 | my ($self, $arguments) = @_; | 
| 698 |  |  |  |  |  |  |  | 
| 699 | 41 | 50 |  |  |  | 138 | $self = $static unless ref $self; # static call or non-static? | 
| 700 |  |  |  |  |  |  |  | 
| 701 | 41 | 50 |  |  |  | 66 | my @args = @{ $arguments || \@ARGV }; | 
|  | 41 |  |  |  |  | 167 |  | 
| 702 | 41 |  |  |  |  | 75 | my @left; | 
| 703 |  |  |  |  |  |  | my @errors; | 
| 704 |  |  |  |  |  |  |  | 
| 705 |  |  |  |  |  |  | OPTION: | 
| 706 | 41 |  |  |  |  | 238 | for (my $i = 0; $i < @args; ++$i) { | 
| 707 | 59 |  |  |  |  | 85 | my $option; | 
| 708 |  |  |  |  |  |  | my $option_name; | 
| 709 | 0 |  |  |  |  | 0 | my $option_arg; # undef only when no argument, with argument at least "" | 
| 710 |  |  |  |  |  |  |  | 
| 711 | 59 | 100 |  |  |  | 458 | if ($args[$i] =~ /^--([a-zA-Z0-9-]+)=(.*)$/) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 712 |  |  |  |  |  |  | # long option with parameter {{{ | 
| 713 |  |  |  |  |  |  |  | 
| 714 | 16 |  |  |  |  | 50 | $option_name = $1; | 
| 715 | 16 |  |  |  |  | 42 | $option_arg  = $2; | 
| 716 | 16 |  |  |  |  | 30 | $option = "--$option_name"; | 
| 717 |  |  |  |  |  |  |  | 
| 718 | 16 |  |  |  |  | 50 | push @errors, $self->_try_set($option, $option_name, $option_arg); | 
| 719 |  |  |  |  |  |  |  | 
| 720 |  |  |  |  |  |  | # }}} | 
| 721 |  |  |  |  |  |  | } elsif ($args[$i] =~ /^--([a-zA-Z0-9-]+)$/) { | 
| 722 |  |  |  |  |  |  | # long option, possible parameter in next argument {{{ | 
| 723 |  |  |  |  |  |  |  | 
| 724 | 34 |  |  |  |  | 97 | $option_name = $1; | 
| 725 | 34 |  |  |  |  | 65 | $option = $args[$i]; | 
| 726 |  |  |  |  |  |  |  | 
| 727 |  |  |  |  |  |  | # there's no option of exactly the same name, but the --option looks | 
| 728 |  |  |  |  |  |  | # like a negation of Boolean | 
| 729 | 34 | 100 | 100 |  |  | 133 | if (!$self->has_option($option_name) && $option_name =~ /^no-/) { | 
| 730 | 1 |  |  |  |  | 4 | my $negated_name = substr $option_name, 3; | 
| 731 |  |  |  |  |  |  |  | 
| 732 |  |  |  |  |  |  | # there is an option without "--no-" prefix and that option is | 
| 733 |  |  |  |  |  |  | # a Boolean, so it might be actually negated | 
| 734 | 1 | 50 | 33 |  |  | 4 | if ($self->has_option($negated_name) && | 
| 735 |  |  |  |  |  |  | $self->option_node($negated_name)->type() eq 'bool') { | 
| 736 | 1 |  |  |  |  | 2 | $option_name = $negated_name; | 
| 737 | 1 |  |  |  |  | 2 | $option = "--$negated_name"; | 
| 738 | 1 |  |  |  |  | 3 | $option_arg = 0; | 
| 739 |  |  |  |  |  |  | } | 
| 740 |  |  |  |  |  |  | } | 
| 741 |  |  |  |  |  |  |  | 
| 742 | 34 | 100 | 100 |  |  | 99 | if ($self->has_option($option_name) && | 
| 743 |  |  |  |  |  |  | $self->option_node($option_name)->requires_arg()) { | 
| 744 |  |  |  |  |  |  | # consume the next argument, if this is possible; if not, report an | 
| 745 |  |  |  |  |  |  | # error | 
| 746 | 19 | 100 |  |  |  | 191 | if ($i < $#args) { | 
| 747 |  |  |  |  |  |  | # TODO: if $args[++$i] =~ /^-/, don't consume it (require people to | 
| 748 |  |  |  |  |  |  | # use "--foo=-arg" form) | 
| 749 | 18 |  |  |  |  | 45 | $option_arg = $args[++$i]; | 
| 750 |  |  |  |  |  |  | } else { | 
| 751 | 1 |  |  |  |  | 6 | push @errors, { | 
| 752 |  |  |  |  |  |  | option => $option, | 
| 753 |  |  |  |  |  |  | cause => "missing argument", | 
| 754 |  |  |  |  |  |  | }; | 
| 755 |  |  |  |  |  |  | } | 
| 756 |  |  |  |  |  |  | } | 
| 757 |  |  |  |  |  |  |  | 
| 758 | 34 |  |  |  |  | 138 | push @errors, $self->_try_set($option, $option_name, $option_arg); | 
| 759 |  |  |  |  |  |  |  | 
| 760 |  |  |  |  |  |  | # }}} | 
| 761 |  |  |  |  |  |  | } elsif ($args[$i] =~ /^-([a-zA-Z0-9]+)$/) { | 
| 762 |  |  |  |  |  |  | # set of short options {{{ | 
| 763 |  |  |  |  |  |  |  | 
| 764 | 0 |  |  |  |  | 0 | my @short_opts = split //, $1; | 
| 765 |  |  |  |  |  |  |  | 
| 766 | 0 |  |  |  |  | 0 | for my $sopt (@short_opts) { | 
| 767 |  |  |  |  |  |  | # XXX: short options can't have arguments specified | 
| 768 | 0 |  |  |  |  | 0 | push @errors, $self->_try_set("-$sopt", $sopt); | 
| 769 |  |  |  |  |  |  | } | 
| 770 |  |  |  |  |  |  |  | 
| 771 | 0 |  |  |  |  | 0 | next OPTION; | 
| 772 |  |  |  |  |  |  |  | 
| 773 |  |  |  |  |  |  | # }}} | 
| 774 |  |  |  |  |  |  | } elsif ($args[$i] eq "--") { | 
| 775 |  |  |  |  |  |  | # end-of-options marker {{{ | 
| 776 |  |  |  |  |  |  |  | 
| 777 |  |  |  |  |  |  | # mark all the rest of arguments as non-options | 
| 778 | 2 |  |  |  |  | 9 | push @left, @args[$i + 1 .. $#args]; | 
| 779 | 2 |  |  |  |  | 6 | last OPTION; | 
| 780 |  |  |  |  |  |  |  | 
| 781 |  |  |  |  |  |  | # }}} | 
| 782 |  |  |  |  |  |  | } elsif ($args[$i] =~ /^-/) { | 
| 783 |  |  |  |  |  |  | # anything beginning with dash (e.g. "-@", "--()&*^&^") {{{ | 
| 784 |  |  |  |  |  |  |  | 
| 785 | 0 |  |  |  |  | 0 | push @errors, { | 
| 786 |  |  |  |  |  |  | option => $args[$i], | 
| 787 |  |  |  |  |  |  | cause => "unknown option", | 
| 788 |  |  |  |  |  |  | }; | 
| 789 |  |  |  |  |  |  |  | 
| 790 |  |  |  |  |  |  | # }}} | 
| 791 |  |  |  |  |  |  | } else { | 
| 792 |  |  |  |  |  |  | # non-option {{{ | 
| 793 |  |  |  |  |  |  |  | 
| 794 | 7 |  |  |  |  | 13 | push @left, $args[$i]; | 
| 795 | 7 |  |  |  |  | 24 | next OPTION; | 
| 796 |  |  |  |  |  |  |  | 
| 797 |  |  |  |  |  |  | # }}} | 
| 798 |  |  |  |  |  |  | } | 
| 799 |  |  |  |  |  |  | } | 
| 800 |  |  |  |  |  |  |  | 
| 801 | 41 |  |  |  |  | 97 | $self->{args} = \@left; | 
| 802 |  |  |  |  |  |  |  | 
| 803 | 41 | 100 |  |  |  | 108 | if (@errors) { | 
| 804 |  |  |  |  |  |  | # TODO: use $_->{"eval"} | 
| 805 | 5 |  |  |  |  | 13 | return map { "$_->{option}: $_->{cause}" } @errors; | 
|  | 6 |  |  |  |  | 45 |  | 
| 806 |  |  |  |  |  |  | } else { | 
| 807 | 36 |  |  |  |  | 137 | return; | 
| 808 |  |  |  |  |  |  | } | 
| 809 |  |  |  |  |  |  | } | 
| 810 |  |  |  |  |  |  |  | 
| 811 |  |  |  |  |  |  | #----------------------------------------------------------------------------- | 
| 812 |  |  |  |  |  |  |  | 
| 813 |  |  |  |  |  |  | =item C | 
| 814 |  |  |  |  |  |  |  | 
| 815 |  |  |  |  |  |  | Check if the schema contains a command line option called C<$name> (aliases | 
| 816 |  |  |  |  |  |  | are resolved). | 
| 817 |  |  |  |  |  |  |  | 
| 818 |  |  |  |  |  |  | B: This is a semi-internal API. | 
| 819 |  |  |  |  |  |  |  | 
| 820 |  |  |  |  |  |  | =cut | 
| 821 |  |  |  |  |  |  |  | 
| 822 |  |  |  |  |  |  | sub has_option { | 
| 823 | 194 |  |  | 194 | 1 | 392 | my ($self, $name) = @_; | 
| 824 |  |  |  |  |  |  |  | 
| 825 | 194 | 50 |  |  |  | 487 | $self = $static unless ref $self; # static call or non-static? | 
| 826 |  |  |  |  |  |  |  | 
| 827 | 194 |  |  |  |  | 346 | $name =~ tr/-/./; | 
| 828 |  |  |  |  |  |  |  | 
| 829 | 194 |  | 100 |  |  | 1442 | return defined $self->{options}{$name} || defined $self->{aliases}{$name}; | 
| 830 |  |  |  |  |  |  | } | 
| 831 |  |  |  |  |  |  |  | 
| 832 |  |  |  |  |  |  | =item C | 
| 833 |  |  |  |  |  |  |  | 
| 834 |  |  |  |  |  |  | Retrieve an option node (L) corresponding to C<$name>. | 
| 835 |  |  |  |  |  |  |  | 
| 836 |  |  |  |  |  |  | Method Cs when no such option is defined in schema. | 
| 837 |  |  |  |  |  |  |  | 
| 838 |  |  |  |  |  |  | B: This is a semi-internal API. | 
| 839 |  |  |  |  |  |  |  | 
| 840 |  |  |  |  |  |  | =cut | 
| 841 |  |  |  |  |  |  |  | 
| 842 |  |  |  |  |  |  | sub option_node { | 
| 843 | 127 |  |  | 127 | 1 | 205 | my ($self, $name) = @_; | 
| 844 |  |  |  |  |  |  |  | 
| 845 | 127 | 50 |  |  |  | 375 | $self = $static unless ref $self; # static call or non-static? | 
| 846 |  |  |  |  |  |  |  | 
| 847 | 127 |  |  |  |  | 167 | $name =~ tr/-/./; | 
| 848 |  |  |  |  |  |  |  | 
| 849 | 127 | 100 |  |  |  | 404 | if ($self->{options}{$name}) { | 
| 850 | 120 |  |  |  |  | 575 | return $self->{options}{$name}; | 
| 851 |  |  |  |  |  |  | } | 
| 852 |  |  |  |  |  |  |  | 
| 853 | 7 | 50 |  |  |  | 21 | if ($self->{aliases}{$name}) { | 
| 854 | 7 |  |  |  |  | 27 | my $target = $self->{aliases}{$name}->alias; | 
| 855 | 7 |  |  |  |  | 29 | return $self->{options}{$target}; | 
| 856 |  |  |  |  |  |  | } | 
| 857 |  |  |  |  |  |  |  | 
| 858 | 0 |  |  |  |  | 0 | croak "No option called $name in schema"; | 
| 859 |  |  |  |  |  |  | } | 
| 860 |  |  |  |  |  |  |  | 
| 861 |  |  |  |  |  |  | =begin Internal | 
| 862 |  |  |  |  |  |  |  | 
| 863 |  |  |  |  |  |  | =pod _try_set() {{{ | 
| 864 |  |  |  |  |  |  |  | 
| 865 |  |  |  |  |  |  | =item C<_try_set($option, $option_name, $option_argument)> | 
| 866 |  |  |  |  |  |  |  | 
| 867 |  |  |  |  |  |  | Try setting option C<$option_name> (C<$option> was the actual name, under | 
| 868 |  |  |  |  |  |  | which it was specified -- mainly I<-X> or I<--long-X>). If the option was | 
| 869 |  |  |  |  |  |  | given a parameter (empty string counts here, too), it should be specified as | 
| 870 |  |  |  |  |  |  | C<$option_argument>, otherwise C<$option_argument> should be left C. | 
| 871 |  |  |  |  |  |  |  | 
| 872 |  |  |  |  |  |  | In case of success, returned value is empty list. In case of failure, | 
| 873 |  |  |  |  |  |  | returned value is a hashref with two keys: I | 
| 874 |  |  |  |  |  |  | I containing an error message. There could be third key I, | 
| 875 |  |  |  |  |  |  | containing C<$@>. Method is suitable for | 
| 876 |  |  |  |  |  |  | C<< push @errors, $o->_try_set(...) >>. | 
| 877 |  |  |  |  |  |  |  | 
| 878 |  |  |  |  |  |  | =cut | 
| 879 |  |  |  |  |  |  |  | 
| 880 |  |  |  |  |  |  | sub _try_set { | 
| 881 | 50 |  |  | 50 |  | 115 | my ($self, $option, $opt_name, $opt_arg) = @_; | 
| 882 |  |  |  |  |  |  |  | 
| 883 | 50 | 100 |  |  |  | 115 | if (not $self->has_option($opt_name)) { | 
| 884 |  |  |  |  |  |  | return { | 
| 885 | 1 |  |  |  |  | 7 | option => $option, | 
| 886 |  |  |  |  |  |  | cause => "unknown option", | 
| 887 |  |  |  |  |  |  | }; | 
| 888 |  |  |  |  |  |  | } | 
| 889 |  |  |  |  |  |  |  | 
| 890 | 49 |  |  |  |  | 136 | my $node = $self->option_node($opt_name); | 
| 891 |  |  |  |  |  |  |  | 
| 892 | 49 | 100 |  |  |  | 129 | if (defined $opt_arg) { | 
| 893 | 35 | 100 |  |  |  | 54 | if (not eval { $node->set($opt_arg); "OK" }) { | 
|  | 35 |  |  |  |  | 173 |  | 
|  | 32 |  |  |  |  | 123 |  | 
| 894 | 3 |  |  |  |  | 197 | chomp $@; | 
| 895 |  |  |  |  |  |  | return { | 
| 896 | 3 |  |  |  |  | 32 | option => $option, | 
| 897 |  |  |  |  |  |  | cause => "invalid option argument: $opt_arg", | 
| 898 |  |  |  |  |  |  | eval => $@, | 
| 899 |  |  |  |  |  |  | }; | 
| 900 |  |  |  |  |  |  | } | 
| 901 |  |  |  |  |  |  | } else { # not defined $opt_arg | 
| 902 |  |  |  |  |  |  | # XXX: this is important not to pass an argument to $node->set() here, as | 
| 903 |  |  |  |  |  |  | # it would try to set undef | 
| 904 | 14 | 100 |  |  |  | 26 | if (not eval { $node->set(); "OK" }) { | 
|  | 14 |  |  |  |  | 201 |  | 
|  | 13 |  |  |  |  | 45 |  | 
| 905 | 1 |  |  |  |  | 151 | chomp $@; | 
| 906 |  |  |  |  |  |  | return { | 
| 907 | 1 |  |  |  |  | 15 | option => $option, | 
| 908 |  |  |  |  |  |  | cause => "invalid option argument: ", | 
| 909 |  |  |  |  |  |  | eval => $@, | 
| 910 |  |  |  |  |  |  | }; | 
| 911 |  |  |  |  |  |  | } | 
| 912 |  |  |  |  |  |  | } | 
| 913 |  |  |  |  |  |  |  | 
| 914 | 45 |  |  |  |  | 306 | return (); | 
| 915 |  |  |  |  |  |  | } | 
| 916 |  |  |  |  |  |  |  | 
| 917 |  |  |  |  |  |  | =end Internal | 
| 918 |  |  |  |  |  |  |  | 
| 919 |  |  |  |  |  |  | =pod }}} | 
| 920 |  |  |  |  |  |  |  | 
| 921 |  |  |  |  |  |  | =cut | 
| 922 |  |  |  |  |  |  |  | 
| 923 |  |  |  |  |  |  | #----------------------------------------------------------------------------- | 
| 924 |  |  |  |  |  |  |  | 
| 925 |  |  |  |  |  |  | =item C | 
| 926 |  |  |  |  |  |  |  | 
| 927 |  |  |  |  |  |  | =item C | 
| 928 |  |  |  |  |  |  |  | 
| 929 |  |  |  |  |  |  | Set value(s) with verification against schema. If C<$path> was specified, | 
| 930 |  |  |  |  |  |  | options start with this prefix. If values were verified successfully, they are | 
| 931 |  |  |  |  |  |  | saved in internal storage. | 
| 932 |  |  |  |  |  |  |  | 
| 933 |  |  |  |  |  |  | B: This is a semi-internal API. | 
| 934 |  |  |  |  |  |  |  | 
| 935 |  |  |  |  |  |  | =cut | 
| 936 |  |  |  |  |  |  |  | 
| 937 |  |  |  |  |  |  | sub set_verify { | 
| 938 | 75 |  |  | 75 | 1 | 130 | my ($self, $data, $path) = @_; | 
| 939 |  |  |  |  |  |  |  | 
| 940 | 75 | 50 |  |  |  | 300 | $self = $static unless ref $self; # static call or non-static? | 
| 941 |  |  |  |  |  |  |  | 
| 942 | 75 |  | 100 |  |  | 259 | $path ||= ""; | 
| 943 |  |  |  |  |  |  |  | 
| 944 | 75 |  | 100 |  |  | 276 | my $datum_type = lc(ref $data) || "scalar"; | 
| 945 |  |  |  |  |  |  |  | 
| 946 | 75 | 100 |  |  |  | 263 | if ($datum_type ne 'hash') { | 
| 947 |  |  |  |  |  |  | # this is an option, but there's no corresponding schema node | 
| 948 | 34 | 50 |  |  |  | 72 | if (not $self->has_option($path)) { | 
| 949 |  |  |  |  |  |  | # $path: unknown option ($datum_type) | 
| 950 | 0 |  |  |  |  | 0 | croak "Unexpected $datum_type option ($path)"; | 
| 951 |  |  |  |  |  |  | } | 
| 952 |  |  |  |  |  |  |  | 
| 953 | 34 |  |  |  |  | 107 | $self->option_node($path)->set($data); | 
| 954 |  |  |  |  |  |  |  | 
| 955 | 30 |  |  |  |  | 115 | return; | 
| 956 |  |  |  |  |  |  | } | 
| 957 |  |  |  |  |  |  |  | 
| 958 |  |  |  |  |  |  | # more complex case: data is a hash | 
| 959 |  |  |  |  |  |  |  | 
| 960 |  |  |  |  |  |  | # if no corresponding node in schema, just go deeper | 
| 961 |  |  |  |  |  |  | # if there is corresponding node, but it's not a hash, just go deeper, too | 
| 962 | 41 | 100 | 66 |  |  | 109 | if (!$self->has_option($path) || | 
| 963 |  |  |  |  |  |  | $self->option_node($path)->storage() ne 'hash') { | 
| 964 | 36 |  |  |  |  | 123 | for my $o (keys %$data) { | 
| 965 | 44 |  |  |  |  | 97 | my $new_path = "$path.$o"; | 
| 966 | 44 |  |  |  |  | 267 | $new_path =~ s/^\.|\.$//g; | 
| 967 |  |  |  |  |  |  |  | 
| 968 | 44 |  |  |  |  | 154 | $self->set_verify($data->{$o}, $new_path); | 
| 969 |  |  |  |  |  |  | } | 
| 970 |  |  |  |  |  |  |  | 
| 971 | 32 |  |  |  |  | 109 | return; | 
| 972 |  |  |  |  |  |  | } | 
| 973 |  |  |  |  |  |  |  | 
| 974 |  |  |  |  |  |  | # it's sure that option called $path exists and it's storage type is "hash" | 
| 975 |  |  |  |  |  |  | # also, this option's type is hash | 
| 976 |  |  |  |  |  |  |  | 
| 977 | 5 |  |  |  |  | 15 | my $node = $self->option_node($path); | 
| 978 | 5 |  |  |  |  | 14 | for my $k (keys %$data) { | 
| 979 | 7 |  |  |  |  | 23 | $node->set($k, $data->{$k}); | 
| 980 |  |  |  |  |  |  | } | 
| 981 |  |  |  |  |  |  | } | 
| 982 |  |  |  |  |  |  |  | 
| 983 |  |  |  |  |  |  | #----------------------------------------------------------------------------- | 
| 984 |  |  |  |  |  |  |  | 
| 985 |  |  |  |  |  |  | =item C | 
| 986 |  |  |  |  |  |  |  | 
| 987 |  |  |  |  |  |  | Retrieve non-option arguments (e.g. everything after "--") passed from command | 
| 988 |  |  |  |  |  |  | line. | 
| 989 |  |  |  |  |  |  |  | 
| 990 |  |  |  |  |  |  | Values returned by this method are set by C method. | 
| 991 |  |  |  |  |  |  |  | 
| 992 |  |  |  |  |  |  | =cut | 
| 993 |  |  |  |  |  |  |  | 
| 994 |  |  |  |  |  |  | sub args { | 
| 995 | 6 |  |  | 6 | 1 | 33 | my ($self) = @_; | 
| 996 |  |  |  |  |  |  |  | 
| 997 | 6 | 50 |  |  |  | 18 | $self = $static unless ref $self; # static call or non-static? | 
| 998 |  |  |  |  |  |  |  | 
| 999 | 6 |  |  |  |  | 9 | return @{ $self->{args} }; | 
|  | 6 |  |  |  |  | 51 |  | 
| 1000 |  |  |  |  |  |  | } | 
| 1001 |  |  |  |  |  |  |  | 
| 1002 |  |  |  |  |  |  | #----------------------------------------------------------------------------- | 
| 1003 |  |  |  |  |  |  |  | 
| 1004 |  |  |  |  |  |  | =item C | 
| 1005 |  |  |  |  |  |  |  | 
| 1006 |  |  |  |  |  |  | Retrieve a view of options (L) appropriate for | 
| 1007 |  |  |  |  |  |  | package or subsystem called C<$package>. | 
| 1008 |  |  |  |  |  |  |  | 
| 1009 |  |  |  |  |  |  | If C<$package> was not provided, caller's package name is used. | 
| 1010 |  |  |  |  |  |  |  | 
| 1011 |  |  |  |  |  |  | C<$package> sets option search path. See C, C option | 
| 1012 |  |  |  |  |  |  | description in L for details. | 
| 1013 |  |  |  |  |  |  |  | 
| 1014 |  |  |  |  |  |  | Typical usage: | 
| 1015 |  |  |  |  |  |  |  | 
| 1016 |  |  |  |  |  |  | sub foo { | 
| 1017 |  |  |  |  |  |  | my (@args) = @_; | 
| 1018 |  |  |  |  |  |  |  | 
| 1019 |  |  |  |  |  |  | my $opts = App::Getconf->getopt(__PACKAGE__); | 
| 1020 |  |  |  |  |  |  |  | 
| 1021 |  |  |  |  |  |  | if ($opts->ssl) { | 
| 1022 |  |  |  |  |  |  | # ... | 
| 1023 |  |  |  |  |  |  |  | 
| 1024 |  |  |  |  |  |  | =cut | 
| 1025 |  |  |  |  |  |  |  | 
| 1026 |  |  |  |  |  |  | sub getopt { | 
| 1027 | 5 |  |  | 5 | 1 | 1034 | my ($self, $package) = @_; | 
| 1028 |  |  |  |  |  |  |  | 
| 1029 | 5 | 50 |  |  |  | 24 | $self = $static unless ref $self; # static call or non-static? | 
| 1030 | 5 | 100 |  |  |  | 20 | if (not defined $package) { | 
| 1031 | 1 |  |  |  |  | 3 | $package = caller; | 
| 1032 | 1 | 50 | 33 |  |  | 13 | if (!defined $package || $package eq 'main') { | 
| 1033 | 1 |  |  |  |  | 22 | $package = ''; | 
| 1034 |  |  |  |  |  |  | } | 
| 1035 |  |  |  |  |  |  | } | 
| 1036 |  |  |  |  |  |  |  | 
| 1037 | 5 |  |  |  |  | 17 | $package =~ s{/|::}{.}g; | 
| 1038 | 5 |  |  |  |  | 24 | $package = lc $package; | 
| 1039 |  |  |  |  |  |  |  | 
| 1040 | 5 | 50 |  |  |  | 31 | if (not $self->{getopt_cache}{$package}) { | 
| 1041 | 5 |  |  |  |  | 34 | $self->{getopt_cache}{$package} = new App::Getconf::View( | 
| 1042 |  |  |  |  |  |  | prefix  => $package, | 
| 1043 |  |  |  |  |  |  | options => $self->{options}, | 
| 1044 |  |  |  |  |  |  | ); | 
| 1045 |  |  |  |  |  |  | } | 
| 1046 |  |  |  |  |  |  |  | 
| 1047 | 5 |  |  |  |  | 20 | return $self->{getopt_cache}{$package}; | 
| 1048 |  |  |  |  |  |  | } | 
| 1049 |  |  |  |  |  |  |  | 
| 1050 |  |  |  |  |  |  | #----------------------------------------------------------------------------- | 
| 1051 |  |  |  |  |  |  |  | 
| 1052 |  |  |  |  |  |  | =back | 
| 1053 |  |  |  |  |  |  |  | 
| 1054 |  |  |  |  |  |  | =cut | 
| 1055 |  |  |  |  |  |  |  | 
| 1056 |  |  |  |  |  |  | #----------------------------------------------------------------------------- | 
| 1057 |  |  |  |  |  |  |  | 
| 1058 |  |  |  |  |  |  | =head2 Functions Defining Schema | 
| 1059 |  |  |  |  |  |  |  | 
| 1060 |  |  |  |  |  |  | =over | 
| 1061 |  |  |  |  |  |  |  | 
| 1062 |  |  |  |  |  |  | =cut | 
| 1063 |  |  |  |  |  |  |  | 
| 1064 |  |  |  |  |  |  | #----------------------------------------------------------------------------- | 
| 1065 |  |  |  |  |  |  |  | 
| 1066 |  |  |  |  |  |  | =item C<< schema(key => value, key => value, ...) >> | 
| 1067 |  |  |  |  |  |  |  | 
| 1068 |  |  |  |  |  |  | Create a hashref from key/value pairs. The resulting hash is tied to | 
| 1069 |  |  |  |  |  |  | L, so the order of keys is preserved. | 
| 1070 |  |  |  |  |  |  |  | 
| 1071 |  |  |  |  |  |  | Main use is for defining order of options in I<--help> message, otherwise it | 
| 1072 |  |  |  |  |  |  | acts just like anonymous hashref creation (C<< { key => value, ... } >>). | 
| 1073 |  |  |  |  |  |  |  | 
| 1074 |  |  |  |  |  |  | =cut | 
| 1075 |  |  |  |  |  |  |  | 
| 1076 |  |  |  |  |  |  | sub schema { | 
| 1077 | 81 |  |  | 81 | 1 | 678 | my (@args) = @_; | 
| 1078 |  |  |  |  |  |  |  | 
| 1079 | 81 |  |  |  |  | 550 | tie my %h, 'Tie::IxHash'; | 
| 1080 | 81 |  |  |  |  | 1532 | %h = @args; | 
| 1081 |  |  |  |  |  |  |  | 
| 1082 | 81 |  |  |  |  | 6264 | return \%h; | 
| 1083 |  |  |  |  |  |  | } | 
| 1084 |  |  |  |  |  |  |  | 
| 1085 |  |  |  |  |  |  | #----------------------------------------------------------------------------- | 
| 1086 |  |  |  |  |  |  |  | 
| 1087 |  |  |  |  |  |  | =item C | 
| 1088 |  |  |  |  |  |  |  | 
| 1089 |  |  |  |  |  |  | Generic option specification. | 
| 1090 |  |  |  |  |  |  |  | 
| 1091 |  |  |  |  |  |  | Possible data: | 
| 1092 |  |  |  |  |  |  |  | 
| 1093 |  |  |  |  |  |  | opt { | 
| 1094 |  |  |  |  |  |  | type    => 'flag' | 'bool' | 'int' | 'float' | 'string', | 
| 1095 |  |  |  |  |  |  | check   => qr// | sub {} | ["enum", "value", ...], | 
| 1096 |  |  |  |  |  |  | storage => undef | \$foo | [] | {}, | 
| 1097 |  |  |  |  |  |  | help    => "message displayed on --help", | 
| 1098 |  |  |  |  |  |  | value   => "initial value", | 
| 1099 |  |  |  |  |  |  | default => "default value", | 
| 1100 |  |  |  |  |  |  | } | 
| 1101 |  |  |  |  |  |  |  | 
| 1102 |  |  |  |  |  |  | If type is not specified, the option is treated as a string. | 
| 1103 |  |  |  |  |  |  |  | 
| 1104 |  |  |  |  |  |  | Check is for verifying correctness of specified option. It may be a regexp, | 
| 1105 |  |  |  |  |  |  | callback function (it gets the value to check as a first argument and in C<$_> | 
| 1106 |  |  |  |  |  |  | variable) or list of possible string values. | 
| 1107 |  |  |  |  |  |  |  | 
| 1108 |  |  |  |  |  |  | Types of options: | 
| 1109 |  |  |  |  |  |  |  | 
| 1110 |  |  |  |  |  |  | =over | 
| 1111 |  |  |  |  |  |  |  | 
| 1112 |  |  |  |  |  |  | =item C | 
| 1113 |  |  |  |  |  |  |  | 
| 1114 |  |  |  |  |  |  | Simple option, like I<--help> or I<--version>. Flag's value tells how many | 
| 1115 |  |  |  |  |  |  | times it was encountered. | 
| 1116 |  |  |  |  |  |  |  | 
| 1117 |  |  |  |  |  |  | =item C | 
| 1118 |  |  |  |  |  |  |  | 
| 1119 |  |  |  |  |  |  | ON/OFF option. May be turned on (I<--verbose>) or off (I<--no-verbose>). | 
| 1120 |  |  |  |  |  |  |  | 
| 1121 |  |  |  |  |  |  | =item C | 
| 1122 |  |  |  |  |  |  |  | 
| 1123 |  |  |  |  |  |  | Option containing an integer. | 
| 1124 |  |  |  |  |  |  |  | 
| 1125 |  |  |  |  |  |  | =item C | 
| 1126 |  |  |  |  |  |  |  | 
| 1127 |  |  |  |  |  |  | Option containing a floating point number. | 
| 1128 |  |  |  |  |  |  |  | 
| 1129 |  |  |  |  |  |  | =item C | 
| 1130 |  |  |  |  |  |  |  | 
| 1131 |  |  |  |  |  |  | Option containing a string. This is the default. | 
| 1132 |  |  |  |  |  |  |  | 
| 1133 |  |  |  |  |  |  | =back | 
| 1134 |  |  |  |  |  |  |  | 
| 1135 |  |  |  |  |  |  | Storage tells if the option is a single-value (default), multi-value | 
| 1136 |  |  |  |  |  |  | accumulator (e.g. may be specified in command line multiple times, and the | 
| 1137 |  |  |  |  |  |  | option arguments will be stored in an array) or multi-value hash accumulator | 
| 1138 |  |  |  |  |  |  | (similar, but option argument is specified as C, and the value part | 
| 1139 |  |  |  |  |  |  | is validated). Note that this specify only type of storage, not the actual | 
| 1140 |  |  |  |  |  |  | container. | 
| 1141 |  |  |  |  |  |  |  | 
| 1142 |  |  |  |  |  |  | B: Don't specify option with a hash storage and that has sub-options | 
| 1143 |  |  |  |  |  |  | (see L"Schema Definition">). Verification can't tell whether the value is | 
| 1144 |  |  |  |  |  |  | meant for the hash under this option or for one of its sub-options. | 
| 1145 |  |  |  |  |  |  |  | 
| 1146 |  |  |  |  |  |  | Presence of C key indicates that this option should be exposed to | 
| 1147 |  |  |  |  |  |  | end-users in I<--help> message. Options lacking this key will be skipped (but | 
| 1148 |  |  |  |  |  |  | stil honoured by App::Getconf). | 
| 1149 |  |  |  |  |  |  |  | 
| 1150 |  |  |  |  |  |  | Except for flags (I<--help>) and bool (I<--no-verbose>) options, the rest of | 
| 1151 |  |  |  |  |  |  | types require an argument. It may be specified as I<--timeout=120> or as | 
| 1152 |  |  |  |  |  |  | I<--timeout 120>. This requirement may be loosened by providing | 
| 1153 |  |  |  |  |  |  | C value. This way end-user may just provide I<--timeout> option, and | 
| 1154 |  |  |  |  |  |  | the argument to the option is taken from default. (Of course, only | 
| 1155 |  |  |  |  |  |  | I<--timeout=120> form is supported if the argument needs to be provided.) | 
| 1156 |  |  |  |  |  |  |  | 
| 1157 |  |  |  |  |  |  | Initial value (C key) is the value set for the option just after | 
| 1158 |  |  |  |  |  |  | defining schema. It may or may not be changed with command line options (which | 
| 1159 |  |  |  |  |  |  | is different from C, for which the option still needs to be | 
| 1160 |  |  |  |  |  |  | specified). | 
| 1161 |  |  |  |  |  |  |  | 
| 1162 |  |  |  |  |  |  | Initial and default values are both subject to check that was specified, if | 
| 1163 |  |  |  |  |  |  | any. | 
| 1164 |  |  |  |  |  |  |  | 
| 1165 |  |  |  |  |  |  | Help message will not retain any formatting, all whitespaces are converted to | 
| 1166 |  |  |  |  |  |  | single space (empty lines are squeezed to single empty line). On the other | 
| 1167 |  |  |  |  |  |  | hand, the message will be pretty wrapped and indented, while you don't need to | 
| 1168 |  |  |  |  |  |  | worry about formatting the string if it is longer and broken to separate lines | 
| 1169 |  |  |  |  |  |  | in your source code, so I think it's a good trade-off. | 
| 1170 |  |  |  |  |  |  |  | 
| 1171 |  |  |  |  |  |  | =cut | 
| 1172 |  |  |  |  |  |  |  | 
| 1173 |  |  |  |  |  |  | sub opt($) { | 
| 1174 | 322 |  |  | 322 | 1 | 1559 | my ($data) = @_; | 
| 1175 |  |  |  |  |  |  |  | 
| 1176 | 322 |  | 100 |  |  | 1285 | my $type    = $data->{type} || "string"; | 
| 1177 | 322 |  |  |  |  | 515 | my $check   = $data->{check}; | 
| 1178 | 322 |  |  |  |  | 576 | my $storage = $data->{storage}; | 
| 1179 | 322 |  |  |  |  | 483 | my $help    = $data->{help}; | 
| 1180 | 322 |  |  |  |  | 550 | my $value   = $data->{value};   # not necessary, but kept for convention | 
| 1181 | 322 |  |  |  |  | 470 | my $default = $data->{default}; # not necessary, but kept for convention | 
| 1182 |  |  |  |  |  |  |  | 
| 1183 | 322 | 100 |  |  |  | 717 | if (ref $storage) { | 
| 1184 |  |  |  |  |  |  | # make sure the store is not a reference to something outside of this | 
| 1185 |  |  |  |  |  |  | # function | 
| 1186 | 30 | 100 |  |  |  | 170 | if (ref $storage eq 'ARRAY') { | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 1187 | 15 |  |  |  |  | 31 | $storage = 'array'; | 
| 1188 |  |  |  |  |  |  | } elsif (ref $storage eq 'HASH') { | 
| 1189 | 15 |  |  |  |  | 26 | $storage = 'hash'; | 
| 1190 |  |  |  |  |  |  | } elsif (ref $storage eq 'SCALAR') { | 
| 1191 | 0 |  |  |  |  | 0 | $storage = 'scalar'; | 
| 1192 |  |  |  |  |  |  | } # TODO: else die? | 
| 1193 |  |  |  |  |  |  | } else { | 
| 1194 | 292 |  |  |  |  | 460 | $storage = 'scalar'; | 
| 1195 |  |  |  |  |  |  | } | 
| 1196 |  |  |  |  |  |  |  | 
| 1197 | 322 | 100 |  |  |  | 2350 | return new App::Getconf::Node( | 
|  |  | 100 |  |  |  |  |  | 
| 1198 |  |  |  |  |  |  | type    => $type, | 
| 1199 |  |  |  |  |  |  | check   => $check, | 
| 1200 |  |  |  |  |  |  | storage => $storage, | 
| 1201 |  |  |  |  |  |  | help    => $help, | 
| 1202 |  |  |  |  |  |  | # XXX: this way undefs are possible to represent as undefs | 
| 1203 |  |  |  |  |  |  | (exists $data->{value}   ? (value   => $value  ) : ()), | 
| 1204 |  |  |  |  |  |  | (exists $data->{default} ? (default => $default) : ()), | 
| 1205 |  |  |  |  |  |  | ); | 
| 1206 |  |  |  |  |  |  | } | 
| 1207 |  |  |  |  |  |  |  | 
| 1208 |  |  |  |  |  |  | =item C | 
| 1209 |  |  |  |  |  |  |  | 
| 1210 |  |  |  |  |  |  | Create an alias for C<$option>. Note that aliases are purely for command line. | 
| 1211 |  |  |  |  |  |  | L and C method don't honour them. | 
| 1212 |  |  |  |  |  |  |  | 
| 1213 |  |  |  |  |  |  | Aliases may only point to non-alias options. | 
| 1214 |  |  |  |  |  |  |  | 
| 1215 |  |  |  |  |  |  | =cut | 
| 1216 |  |  |  |  |  |  |  | 
| 1217 |  |  |  |  |  |  | sub opt_alias($) { | 
| 1218 | 43 |  |  | 43 | 1 | 70 | my ($dest_option) = @_; | 
| 1219 |  |  |  |  |  |  |  | 
| 1220 | 43 |  |  |  |  | 200 | return new App::Getconf::Node(alias => $dest_option); | 
| 1221 |  |  |  |  |  |  | } | 
| 1222 |  |  |  |  |  |  |  | 
| 1223 |  |  |  |  |  |  | =item C | 
| 1224 |  |  |  |  |  |  |  | 
| 1225 |  |  |  |  |  |  | Flag option (like I<--help>, I<--verbose> or I<--debug>). | 
| 1226 |  |  |  |  |  |  |  | 
| 1227 |  |  |  |  |  |  | =cut | 
| 1228 |  |  |  |  |  |  |  | 
| 1229 |  |  |  |  |  |  | sub opt_flag() { | 
| 1230 | 18 |  |  | 18 | 1 | 113 | return opt { type => 'flag' }; | 
| 1231 |  |  |  |  |  |  | } | 
| 1232 |  |  |  |  |  |  |  | 
| 1233 |  |  |  |  |  |  | =item C | 
| 1234 |  |  |  |  |  |  |  | 
| 1235 |  |  |  |  |  |  | Boolean option (like I<--recursive>). Such option gets its counterpart | 
| 1236 |  |  |  |  |  |  | called I<--no-${option}> (mentioned I<--recursive> gets I<--no-recursive>). | 
| 1237 |  |  |  |  |  |  |  | 
| 1238 |  |  |  |  |  |  | =cut | 
| 1239 |  |  |  |  |  |  |  | 
| 1240 |  |  |  |  |  |  | sub opt_bool() { | 
| 1241 | 1 |  |  | 1 | 1 | 4 | return opt { type => 'bool' }; | 
| 1242 |  |  |  |  |  |  | } | 
| 1243 |  |  |  |  |  |  |  | 
| 1244 |  |  |  |  |  |  | =item C | 
| 1245 |  |  |  |  |  |  |  | 
| 1246 |  |  |  |  |  |  | Integer option (I<--retries=3>). | 
| 1247 |  |  |  |  |  |  |  | 
| 1248 |  |  |  |  |  |  | =cut | 
| 1249 |  |  |  |  |  |  |  | 
| 1250 |  |  |  |  |  |  | sub opt_int() { | 
| 1251 | 8 |  |  | 8 | 1 | 29 | return opt { type => 'int' }; | 
| 1252 |  |  |  |  |  |  | } | 
| 1253 |  |  |  |  |  |  |  | 
| 1254 |  |  |  |  |  |  | =item C | 
| 1255 |  |  |  |  |  |  |  | 
| 1256 |  |  |  |  |  |  | Option specifying a floating point number. | 
| 1257 |  |  |  |  |  |  |  | 
| 1258 |  |  |  |  |  |  | =cut | 
| 1259 |  |  |  |  |  |  |  | 
| 1260 |  |  |  |  |  |  | sub opt_float() { | 
| 1261 | 0 |  |  | 0 | 1 | 0 | return opt { type => 'float' }; | 
| 1262 |  |  |  |  |  |  | } | 
| 1263 |  |  |  |  |  |  |  | 
| 1264 |  |  |  |  |  |  | =item C | 
| 1265 |  |  |  |  |  |  |  | 
| 1266 |  |  |  |  |  |  | Option specifying a string. | 
| 1267 |  |  |  |  |  |  |  | 
| 1268 |  |  |  |  |  |  | =cut | 
| 1269 |  |  |  |  |  |  |  | 
| 1270 |  |  |  |  |  |  | sub opt_string() { | 
| 1271 | 20 |  |  | 20 | 1 | 83 | return opt { type => 'string' }; | 
| 1272 |  |  |  |  |  |  | } | 
| 1273 |  |  |  |  |  |  |  | 
| 1274 |  |  |  |  |  |  | =item C | 
| 1275 |  |  |  |  |  |  |  | 
| 1276 |  |  |  |  |  |  | Option specifying a path in local filesystem. | 
| 1277 |  |  |  |  |  |  |  | 
| 1278 |  |  |  |  |  |  | =cut | 
| 1279 |  |  |  |  |  |  |  | 
| 1280 |  |  |  |  |  |  | sub opt_path() { | 
| 1281 |  |  |  |  |  |  | # TODO: some checks on how this looks like | 
| 1282 |  |  |  |  |  |  | #   * existing file | 
| 1283 |  |  |  |  |  |  | #   * existing directory | 
| 1284 |  |  |  |  |  |  | #   * non-existing file (directory exists) | 
| 1285 |  |  |  |  |  |  | #   * Maasai? | 
| 1286 | 0 |  |  | 0 | 1 |  | return opt { type => 'string' }; | 
| 1287 |  |  |  |  |  |  | } | 
| 1288 |  |  |  |  |  |  |  | 
| 1289 |  |  |  |  |  |  | =item C | 
| 1290 |  |  |  |  |  |  |  | 
| 1291 |  |  |  |  |  |  | Option specifying a hostname. | 
| 1292 |  |  |  |  |  |  |  | 
| 1293 |  |  |  |  |  |  | B: This doesn't check DNS for the hostname to exist. This only checks | 
| 1294 |  |  |  |  |  |  | hostname's syntactic correctness (and only to some degree). | 
| 1295 |  |  |  |  |  |  |  | 
| 1296 |  |  |  |  |  |  | =cut | 
| 1297 |  |  |  |  |  |  |  | 
| 1298 |  |  |  |  |  |  | sub opt_hostname() { | 
| 1299 | 0 |  |  | 0 | 1 |  | return opt { check => qr/^[a-z0-9-]+(\.[a-z0-9-]+)*$/i }; | 
| 1300 |  |  |  |  |  |  | } | 
| 1301 |  |  |  |  |  |  |  | 
| 1302 |  |  |  |  |  |  | =item C | 
| 1303 |  |  |  |  |  |  |  | 
| 1304 |  |  |  |  |  |  | Option specifying a string, with check specified as regexp. | 
| 1305 |  |  |  |  |  |  |  | 
| 1306 |  |  |  |  |  |  | =cut | 
| 1307 |  |  |  |  |  |  |  | 
| 1308 |  |  |  |  |  |  | sub opt_re($) { | 
| 1309 | 0 |  |  | 0 | 1 |  | my ($re) = @_; | 
| 1310 |  |  |  |  |  |  |  | 
| 1311 | 0 |  |  |  |  |  | return opt { check => $re }; | 
| 1312 |  |  |  |  |  |  | } | 
| 1313 |  |  |  |  |  |  |  | 
| 1314 |  |  |  |  |  |  | =item C | 
| 1315 |  |  |  |  |  |  |  | 
| 1316 |  |  |  |  |  |  | =item C | 
| 1317 |  |  |  |  |  |  |  | 
| 1318 |  |  |  |  |  |  | Option specifying a string, with check specified as function (code ref). | 
| 1319 |  |  |  |  |  |  |  | 
| 1320 |  |  |  |  |  |  | Subroutine will have C<$_> set to value to check, and the value will be the | 
| 1321 |  |  |  |  |  |  | only argument (C<@_>) passed. | 
| 1322 |  |  |  |  |  |  |  | 
| 1323 |  |  |  |  |  |  | Subroutine should return C when option value should be accepted, | 
| 1324 |  |  |  |  |  |  | C otherwise. | 
| 1325 |  |  |  |  |  |  |  | 
| 1326 |  |  |  |  |  |  | =cut | 
| 1327 |  |  |  |  |  |  |  | 
| 1328 |  |  |  |  |  |  | sub opt_sub(&) { | 
| 1329 | 0 |  |  | 0 | 1 |  | my ($sub) = @_; | 
| 1330 |  |  |  |  |  |  |  | 
| 1331 | 0 |  |  |  |  |  | return opt { check => $sub }; | 
| 1332 |  |  |  |  |  |  | } | 
| 1333 |  |  |  |  |  |  |  | 
| 1334 |  |  |  |  |  |  | =item C | 
| 1335 |  |  |  |  |  |  |  | 
| 1336 |  |  |  |  |  |  | Option specifying a string. The string must be one of the specified in the | 
| 1337 |  |  |  |  |  |  | array. | 
| 1338 |  |  |  |  |  |  |  | 
| 1339 |  |  |  |  |  |  | =cut | 
| 1340 |  |  |  |  |  |  |  | 
| 1341 |  |  |  |  |  |  | sub opt_enum($) { | 
| 1342 | 0 |  |  | 0 | 1 |  | my ($choices) = @_; | 
| 1343 |  |  |  |  |  |  |  | 
| 1344 | 0 |  |  |  |  |  | return opt { check => $choices }; | 
| 1345 |  |  |  |  |  |  | } | 
| 1346 |  |  |  |  |  |  |  | 
| 1347 |  |  |  |  |  |  | #----------------------------------------------------------------------------- | 
| 1348 |  |  |  |  |  |  |  | 
| 1349 |  |  |  |  |  |  | =back | 
| 1350 |  |  |  |  |  |  |  | 
| 1351 |  |  |  |  |  |  | =cut | 
| 1352 |  |  |  |  |  |  |  | 
| 1353 |  |  |  |  |  |  | #----------------------------------------------------------------------------- | 
| 1354 |  |  |  |  |  |  |  | 
| 1355 |  |  |  |  |  |  | =head1 AUTHOR | 
| 1356 |  |  |  |  |  |  |  | 
| 1357 |  |  |  |  |  |  | Stanislaw Klekot, C<<  >> | 
| 1358 |  |  |  |  |  |  |  | 
| 1359 |  |  |  |  |  |  | =head1 LICENSE AND COPYRIGHT | 
| 1360 |  |  |  |  |  |  |  | 
| 1361 |  |  |  |  |  |  | Copyright 2012 Stanislaw Klekot. | 
| 1362 |  |  |  |  |  |  |  | 
| 1363 |  |  |  |  |  |  | This program is free software; you can redistribute it and/or modify it | 
| 1364 |  |  |  |  |  |  | under the terms of either: the GNU General Public License as published | 
| 1365 |  |  |  |  |  |  | by the Free Software Foundation; or the Artistic License. | 
| 1366 |  |  |  |  |  |  |  | 
| 1367 |  |  |  |  |  |  | See http://dev.perl.org/licenses/ for more information. | 
| 1368 |  |  |  |  |  |  |  | 
| 1369 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 1370 |  |  |  |  |  |  |  | 
| 1371 |  |  |  |  |  |  | L, L, L. | 
| 1372 |  |  |  |  |  |  |  | 
| 1373 |  |  |  |  |  |  | =cut | 
| 1374 |  |  |  |  |  |  |  | 
| 1375 |  |  |  |  |  |  | #----------------------------------------------------------------------------- | 
| 1376 |  |  |  |  |  |  | 1; | 
| 1377 |  |  |  |  |  |  | # vim:ft=perl:foldmethod=marker |