File Coverage

blib/lib/PDLA/Options.pm
Criterion Covered Total %
statement 159 252 63.1
branch 42 102 41.1
condition 5 12 41.6
subroutine 22 30 73.3
pod 23 26 88.4
total 251 422 59.4


line stmt bran cond sub pod time code
1              
2             package PDLA::Options;
3              
4             =head1 NAME
5              
6             PDLA::Options - simplifies option passing by hash in PerlDL
7              
8             =head1 SYNOPSIS
9              
10             use PDLA::Options;
11              
12             %hash = parse( \%defaults, \%user_options);
13              
14             use PDLA::Options ();
15              
16             $opt = new PDLA::Options;
17             $opt = new PDLA::Options ( \%defaults );
18              
19             $opt->defaults ( \%defaults );
20             $opt->synonyms ( { 'COLOR' => 'COLOUR' } );
21              
22             $hashref = $opt->defaults;
23              
24             $opt->options ( \%user_options );
25              
26             $hashref = $opt->options;
27              
28             $opt->incremental(1);
29             $opt->full_options(0);
30              
31             =head1 DESCRIPTION
32              
33             Object to simplify option passing for PerlDL subroutines.
34             Allows you to merge a user defined options with defaults.
35             A simplified (non-OO) interface is provided.
36              
37             =cut
38              
39 77     77   537 use strict;
  77         162  
  77         2433  
40 77     77   405 use Carp;
  77         152  
  77         5249  
41              
42 77     77   469 use vars qw/$VERSION %EXPORT_TAGS %DEF_SYNS @ISA/;
  77         176  
  77         177886  
43              
44             require Exporter;
45              
46             # difference to 0.91 is that added CENTRE/CENTER as default
47             # synonymns (patch by Diab Jerius [ #469110 ])
48             our $VERSION = '0.92';
49             $VERSION = eval $VERSION;
50              
51             @ISA = qw(Exporter);
52              
53             %EXPORT_TAGS = (
54             'Func' => [qw/
55             parse iparse ifhref
56             /]
57             );
58              
59             Exporter::export_tags('Func');
60              
61             # List of default synonyms
62             %DEF_SYNS = (
63             COLOR => 'COLOUR',
64             COLOUR => 'COLOR',
65             CENTER => 'CENTRE',
66             CENTRE => 'CENTER',
67             );
68              
69             my $default = {
70             WarnOnMissing => 1,
71             FullOptions => 1,
72             DEBUG => 0,
73             };
74              
75             =head1 Utility functions
76              
77             =head2 ifhref
78              
79             parse({Ext => 'TIF', ifhref($opt)});
80              
81             just return the argument if it is a hashref otherwise return
82             an empty hashref. Useful in conjunction with parse to return
83             just the default values if argument is not a hash ref
84              
85             =head1 NON-OO INTERFACE
86              
87             A simplified non-object oriented interface is provided.
88             These routines are exported into the callers namespace by default.
89              
90             =over 4
91              
92             =item parse( \%defaults, \%user_options)
93              
94             This will parse user options by using the defaults. The following
95             settings are used for parsing: The options are case-sensitive, a
96             default synonym table is consulted (see L),
97             minimum-matching is turned on, and translation of values is not performed.
98              
99             A hash (not hash reference) containing the processed options is returned.
100              
101             %options = parse( { LINE => 1, COLOUR => 'red'}, { COLOR => 'blue'});
102              
103             =item iparse( \%defaults, \%user_options)
104              
105             Same as C but matching is case insensitive
106              
107             =cut
108              
109             sub ifhref {
110 8     8 1 20 my ($href) = @_;
111 8 100 66     42 return defined $href && ref $href eq 'HASH' ? $href : {};
112             }
113              
114 0     0 1 0 sub parse { return _parse(1,@_) }
115 16     16 1 136 sub iparse { return _parse(0,@_) }
116              
117             sub _parse {
118              
119 16 50   16   42 croak 'Usage: parse( \%defaults, \%user )' if scalar(@_) != 3;
120              
121 16         75 my $casechk = shift;
122 16         25 my $defaults = shift;
123 16 50       45 croak ("First argument is not a hash reference")
124             unless ref($defaults) eq "HASH";
125              
126 16         25 my $user = shift;
127 16 50       40 croak ("Second argument is not a hash reference")
128             unless ref($user) eq "HASH";
129              
130             # Create new object
131 16         79 my $opt = new PDLA::Options ( $defaults );
132              
133             # Set up default behaviour
134 16         50 $opt->minmatch(1);
135 16         41 $opt->casesens($casechk);
136 16         50 $opt->synonyms( \%DEF_SYNS );
137              
138             # Process the options
139 16         55 my $optref = $opt->options( $user );
140              
141 16         153 return %$optref;
142             }
143              
144              
145             =back
146              
147             =head2 Default Synonyms
148              
149             The following default synonyms are available in the non-OO interface:
150              
151             COLOR => COLOUR
152             COLOUR => COLOR
153             CENTER => CENTRE
154             CENTRE => CENTER
155              
156             =head1 METHODS
157              
158             The following methods are available to PDLA::Options objects.
159              
160             =over 4
161              
162             =item new()
163              
164             Constructor. Creates the object. With an optional argument can also
165             set the default options.
166              
167             =cut
168              
169             sub new {
170              
171 42     42 1 105 my $proto = shift;
172 42   33     331 my $class = ref($proto) || $proto;
173              
174 42         89 my $opt = {};
175              
176             # Set up object structure
177 42         120 $opt->{DEFAULTS} = {}; # Default options
178 42         101 $opt->{CURRENT} = {}; # Current options
179 42         105 $opt->{CurrKeys} = []; # list of selected keys if full_options(0)
180 42         90 $opt->{SYNONYMS} = {}; # List of synonyms
181 42         86 $opt->{INC} = 0; # Flag to decide whether we are incremental on cur
182 42         87 $opt->{CaseSens} = 0; # Are options case sensitive
183 42         76 $opt->{MinMatch} = 1; # Minimum matching on keys
184 42         132 $opt->{Translation} = {};# Translation from eg 'RED' to 1
185 42         88 $opt->{AutoTranslate}= 1;# Automatically translate options when processing
186 42         78 $opt->{MinMatchTrans} = 0; # Min matching during translation
187 42         79 $opt->{CaseSensTrans} = 0; # Case sensitive during translation
188             # Return full options list
189 42         97 $opt->{FullOptions} = $default->{FullOptions};
190             # Whether to warn for options that are invalid or not
191 42         77 $opt->{WarnOnMissing}= $default->{WarnOnMissing};
192 42         94 $opt->{DEBUG} = $default->{DEBUG}; # Turn on debug messages
193              
194             # Bless into class
195 42         86 bless ( $opt, $class);
196              
197             # If we were passed arguments, pass to defaults method
198 42 50       136 if (@_) { $opt->defaults( @_ ); }
  42         139  
199              
200 42         124 return $opt;
201             }
202              
203             =item extend (\%options)
204              
205             This will copy the existing options object and extend it with the
206             requested extra options.
207              
208             =cut
209              
210             sub extend {
211              
212 0     0 1 0 my ($self, $opt)=@_;
213              
214 0         0 my $class = ref($self);
215 0         0 my $h = {%{$self}};
  0         0  
216 0 0       0 croak ("Argument is not reference to hash!\n") unless ref($opt) eq 'HASH';
217             #
218             # The next step is to perform a deep copy of the hash
219             # references since we might want to change these without
220             # changing the originals.
221             #
222 0         0 $h->{SYNONYMS}={%{$self->{SYNONYMS}}};
  0         0  
223 0         0 $h->{Translation}={%{$self->{Translation}}};
  0         0  
224 0         0 $h->{CurrKeys}=[@{$self->{CurrKeys}}];
  0         0  
225             #
226             # Create the extended option list.
227             #
228 0         0 my %all_options = (%{$opt}, %{$self->{DEFAULTS}});
  0         0  
  0         0  
229              
230             # Bless it
231 0         0 bless ($h, $class);
232              
233             # And parse the default options
234 0         0 $h->defaults(\%all_options);
235              
236 0         0 return $h;
237              
238             }
239              
240             # =item change_defaults (\%options)
241              
242             # This will merge the options given with the defaults hash and hence change
243             # the default hash. This is not normally a good idea, but in certain dynamic
244             # situations you might want to adjust a default parameter for future calls
245             # to the routine.
246              
247             # =cut
248              
249             # sub change_defaults {
250              
251             # my $self=shift;
252              
253             # my $arg = shift;
254             # croak("Argument is not a hash reference!\n") unless ref($arg) eq 'HASH';
255              
256             # my $defs = $self->defaults($arg);
257              
258             # $self->defaults($)
259              
260              
261             # }
262              
263              
264             =item defaults( \%defaults )
265              
266             Method to set or return the current defaults. The argument should be
267             a reference to a hash. The hash reference is returned if no arguments
268             are supplied.
269              
270             The current values are reset whenever the defaults are changed.
271              
272             =cut
273              
274             sub defaults {
275 72     72 1 126 my $self = shift;
276              
277 72 100       165 if (@_) {
278 42         75 my $arg = shift;
279 42 50       140 croak("Argument is not a hash reference") unless ref($arg) eq "HASH";
280 42         244 $self->{DEFAULTS} = $arg;
281              
282             # Reset the current state (making sure that I disconnect the
283             # hashes
284 42         260 my %hash = %$arg;
285 42         175 $self->curr_full(\%hash);
286              
287             }
288              
289             # Decouple the hash to protect it from being modified outside the
290             # object
291 72         146 my %hash = %{$self->{DEFAULTS}};
  72         269  
292 72         162 return \%hash;
293              
294             }
295              
296             =item add_synonym (\%synonyms)
297              
298             Method to add another synonym to an option set
299             The argument should be a reference to a hash.
300              
301             =cut
302              
303             sub add_synonym {
304 0     0 1 0 my $self=shift;
305 0 0       0 return unless @_;
306 0         0 my $arg = shift;
307 0 0       0 croak("Synonym argument is not a hash reference") unless ref($arg) eq "HASH";
308              
309 0         0 foreach (keys %$arg) {
310 0         0 $self->{SYNONYMS}{$_}=$arg->{$_};
311             }
312 0         0 my %hash = %{$self->{SYNONYMS}};
  0         0  
313 0         0 return \%hash;
314              
315             }
316              
317             =item add_translation (\%translation)
318              
319             Method to add another translation rule to an option set.
320             The argument should be a reference to a hash.
321              
322             =cut
323              
324              
325             sub add_translation {
326 0     0 1 0 my $self = shift;
327 0 0       0 return unless @_;
328 0         0 my $arg = shift;
329 0 0       0 croak("Translation argument is not a hash reference") unless ref($arg) eq 'HASH';
330              
331 0         0 foreach (keys %$arg) {
332 0         0 $self->{Translation}{$_}=$arg->{$_};
333             }
334 0         0 my %hash = %{$self->{Translation}};
  0         0  
335              
336 0         0 return \%hash;
337              
338             }
339              
340             =item synonyms( \%synonyms )
341              
342             Method to set or return the current synonyms. The argument should be
343             a reference to a hash. The hash reference is returned if no arguments
344             are supplied.
345              
346             This allows you to provide alternate keywords (such as allowing
347             'COLOR' as an option when your defaults uses 'COLOUR').
348              
349             =cut
350              
351             sub synonyms {
352 57     57 1 86 my $self = shift;
353              
354 57 100       116 if (@_) {
355 27         38 my $arg = shift;
356 27 50       65 croak("Argument is not a hash reference") unless ref($arg) eq "HASH";
357 27         54 $self->{SYNONYMS} = $arg;
358             }
359              
360             # Decouple the hash to protect it from being modified outside the
361             # object
362 57         77 my %hash = %{$self->{SYNONYMS}};
  57         177  
363 57         148 return \%hash;
364              
365             }
366              
367              
368             =item current
369              
370             Returns the current state of the options. This is returned
371             as a hash reference (although it is not a reference to the
372             actual hash stored in the object). If full_options() is true
373             the full options hash is returned, if full_options() is false
374             only the modified options are returned (as set by the last call
375             to options()).
376              
377             =cut
378              
379             sub current {
380 42     42 1 66 my $self = shift;
381              
382 42 50       89 if ($self->full_options) {
383 42         83 return $self->curr_full;
384             } else {
385 0         0 my @keys = $self->curr_keys;
386 0         0 my %hash = ();
387 0         0 my $curr = $self->curr_full;
388              
389 0         0 foreach my $key (@keys) {
390 0 0       0 $hash{$key} = $$curr{$key} if exists $$curr{$key};
391             }
392 0         0 return \%hash;
393             }
394             }
395              
396             =item clear_current
397              
398             This routine clears the 'state' of the C object so that
399             the next call to current will return an empty list
400              
401             =cut
402              
403             sub clear_current {
404 0     0 1 0 my $self = shift;
405 0         0 @{$self->{CurrKeys}}=();
  0         0  
406             }
407              
408              
409             # Method to set the 'mini' state of the object
410             # This is just a list of the keys in %defaults that were selected
411             # by the user. current() returns the hash with these keys if
412             # called with full_options(0).
413             # Not publicising this
414              
415             sub curr_keys {
416 30     30 0 56 my $self = shift;
417 30 100       74 if (@_) { @{$self->{CurrKeys}} = @_; }
  22         46  
  22         52  
418 30         48 return @{$self->{CurrKeys}};
  30         53  
419             }
420              
421             # Method to set the full state of the object
422             # Not publicising this
423              
424             sub curr_full {
425 174     174 0 231 my $self = shift;
426              
427 174 100       326 if (@_) {
428 102         145 my $arg = shift;
429 102 50       241 croak("Argument is not a hash reference") unless ref($arg) eq "HASH";
430 102         224 $self->{CURRENT} = $arg;
431             }
432              
433             # Decouple the hash
434 174         235 my %hash = %{$self->{CURRENT}};
  174         641  
435 174         526 return \%hash;
436              
437             }
438              
439              
440             =item translation
441              
442             Provide translation of options to more specific values that are
443             recognised by the program. This allows, for example, the automatic
444             translation of the string 'red' to '#ff0000'.
445              
446             This method can be used to setup the dictionary and is hash reference
447             with the following structure:
448              
449             OPTIONA => {
450             'string1' => decode1,
451             'string2' => decode2
452             },
453             OPTIONB => {
454             's4' => decodeb1,
455             }
456             etc....
457              
458             Where OPTION? corresponds to the top level option name as stored in
459             the defaults array (eg LINECOLOR) and the anonymous hashes provide
460             the translation from string1 ('red') to decode1 ('#ff0000').
461              
462             An options string will be translated automatically during the main options()
463             processing if autotrans() is set to true. Else translation can be
464             initiated by the user using the translate() method.
465              
466             =cut
467              
468             sub translation {
469 30     30 1 49 my $self = shift;
470              
471 30 50       82 if (@_) {
472 0         0 my $arg = shift;
473 0 0       0 croak("Argument is not a hash reference") unless ref($arg) eq "HASH";
474 0         0 $self->{Translation} = $arg;
475             }
476              
477             # Decouple the hash to protect it from being modified outside the
478             # object
479 30         50 my %hash = %{$self->{Translation}};
  30         70  
480 30         73 return \%hash;
481              
482             }
483              
484              
485             =item incremental
486              
487             Specifies whether the user defined options will be treated as additions
488             to the current state of the object (1) or modifications to the default
489             values only (0).
490              
491             Can be used to set or return this value.
492             Default is false.
493              
494             =cut
495              
496             sub incremental {
497 30     30 1 55 my $self = shift;
498 30 50       73 if (@_) { $self->{INC} = shift; }
  0         0  
499 30         94 return $self->{INC};
500             }
501              
502             =item full_options
503              
504             Governs whether a complete set of options is returned (ie defaults
505             + expanded user options), true, or if just the expanded user
506             options are returned, false (ie the values specified by the user).
507              
508             This can be useful when you are only interested in the changes to
509             the options rather than knowing the full state. (For example, if
510             defaults contains keys for COLOUR and LINESTYLE and the user supplied
511             a key of COL, you may simply be interested in the modification to
512             COLOUR rather than the state of LINESTYLE and COLOUR.)
513              
514             Default is true.
515              
516             =cut
517              
518             sub full_options {
519 42     42 1 62 my $self = shift;
520 42 50       91 if (@_) { $self->{FullOptions} = shift; }
  0         0  
521 42         101 return $self->{FullOptions};
522              
523             }
524              
525             =item casesens
526              
527             Specifies whether the user defined options will be processed independent
528             of case (0) or not (1). Default is to be case insensitive.
529              
530             Can be used to set or return this value.
531              
532             =cut
533              
534             sub casesens {
535 44     44 1 64 my $self = shift;
536 44 100       85 if (@_) { $self->{CaseSens} = shift; }
  16         27  
537 44         72 return $self->{CaseSens};
538             }
539              
540             =item minmatch
541              
542             Specifies whether the user defined options will be minimum matched
543             with the defaults (1) or whether the user defined options should match
544             the default keys exactly. Defaults is true (1).
545              
546             If a particular key matches exactly (within the constraints imposed
547             bby case sensitivity) this key will always be taken as correct even
548             if others are similar. For example COL would match COL and COLOUR but
549             this implementation will always return COL in this case (note that
550             for CO it will return both COL and COLOUR and pick one at random.
551              
552             Can be used to set or return this value.
553              
554             =cut
555              
556             sub minmatch {
557 44     44 1 58 my $self = shift;
558 44 100       81 if (@_) { $self->{MinMatch} = shift; }
  16         26  
559 44         73 return $self->{MinMatch};
560             }
561              
562              
563             =item autotrans
564              
565             Specifies whether the user defined options will be processed via
566             the translate() method immediately following the main options
567             parsing. Default is to autotranslate (1).
568              
569             Can be used to set or return this value.
570              
571             =cut
572              
573             sub autotrans {
574 30     30 1 49 my $self = shift;
575 30 50       70 if (@_) { $self->{AutoTranslate} = shift; }
  0         0  
576 30         111 return $self->{AutoTranslate};
577             }
578              
579              
580             =item casesenstrans
581              
582             Specifies whether the keys in the options hash will be matched insensitive
583             of case (0) during translation() or not (1). Default is to be case insensitive.
584              
585             Can be used to set or return this value.
586              
587             =cut
588              
589             sub casesenstrans {
590 0     0 1 0 my $self = shift;
591 0 0       0 if (@_) { $self->{CaseSensTrans} = shift; }
  0         0  
592 0         0 return $self->{CaseSensTrans};
593             }
594              
595             =item minmatchtrans
596              
597             Specifies whether the keys in the options hash will be minimum matched
598             during translation(). Default is false (0).
599              
600             If a particular key matches exactly (within the constraints imposed
601             bby case sensitivity) this key will always be taken as correct even
602             if others are similar. For example COL would match COL and COLOUR but
603             this implementation will always return COL in this case (note that
604             for CO it will return both COL and COLOUR and pick one at random.
605              
606             Can be used to set or return this value.
607              
608             =cut
609              
610             sub minmatchtrans {
611 0     0 1 0 my $self = shift;
612 0 0       0 if (@_) { $self->{MinMatchTrans} = shift; }
  0         0  
613 0         0 return $self->{MinMatchTrans};
614             }
615              
616              
617             =item warnonmissing
618              
619             Turn on or off the warning message printed when an options is not in
620             the options hash. This can be convenient when a user passes a set of
621             options that has to be parsed by several different option objects down
622             the line.
623              
624             =cut
625              
626             sub warnonmissing {
627 0     0 1 0 my $self = shift;
628 0 0       0 if (ref $self) {
629 0 0       0 if (@_) { $self->{WarnOnMissing}=shift;}
  0         0  
630 0         0 return $self->{WarnOnMissing};
631             } else {
632 0 0       0 $default->{WarnOnMissing} = shift if @_;
633 0         0 return $default->{WarnOnMissing};
634             }
635             }
636              
637              
638             =item debug
639              
640             Turn on or off debug messages. Default is off (0).
641             Can be used to set or return this value.
642              
643             =cut
644              
645             sub debug {
646 25     25 1 45 my $self = shift;
647 25 50       58 if (ref $self) {
648 25 50       62 if (@_) { $self->{DEBUG} = shift; }
  0         0  
649 25         85 return $self->{DEBUG};
650             } else {
651 0 0       0 $default->{DEBUG} = shift if @_;
652 0         0 return $default->{DEBUG};
653             }
654             }
655              
656              
657             =item options
658              
659             Takes a set of user-defined options (as a reference to a hash)
660             and merges them with the current state (or the defaults; depends
661             on the state of incremental()).
662              
663             The user-supplied keys will be compared with the defaults.
664             Case sensitivity and minimum matching can be configured using
665             the mimatch() and casesens() methods.
666              
667             A warning is raised if keys present in the user options are not
668             present in the defaults unless warnonmissing is set.
669              
670             A reference to a hash containing the merged options is returned.
671              
672             $merged = $opt->options( { COL => 'red', Width => 1});
673              
674             The state of the object can be retrieved after this by using the
675             current() method or by using the options() method with no arguments.
676             If full_options() is true, all options are returned (options plus
677             overrides), if full_options() is false then only the modified
678             options are returned.
679              
680             Synonyms are supported if they have been configured via the synonyms()
681             method.
682              
683             =cut
684              
685             sub options {
686              
687 30     30 1 50 my $self = shift;
688              
689             # If there is an argument do something clever
690 30 50       71 if (@_) {
691              
692             # check that the arg is a hash
693 30         43 my $arg = shift;
694 30 50       88 croak("Argument is not a hash reference") unless ref($arg) eq "HASH";
695              
696             # Turn the options into a real hash
697 30         86 my %user = %$arg;
698              
699             # Now read in the base options
700 30         57 my $base;
701 30 50       72 if ($self->incremental) {
702 0         0 $base = $self->curr_full;
703             } else {
704 30         76 $base = $self->defaults;
705             }
706              
707             # Turn into a real hash for convenience
708 30         116 my %base = %$base;
709              
710             # Store a list of all the expanded user keys
711 30         69 my @list = ();
712              
713             # Read in synonyms
714 30         39 my %syn = %{$self->synonyms};
  30         65  
715              
716             # Now go through the keys in the user hash and compare with
717             # the defaults
718 30         137 foreach my $userkey (sort keys %user) {
719              
720             # Check for matches in the default set
721 25         89 my @matched = $self->compare_with_list(0, $userkey, keys %base);
722              
723             # If we had no matches, check the synonyms list
724 25 100       67 if ($#matched == -1) {
725 3         8 @matched = $self->compare_with_list(0, $userkey, keys %syn);
726              
727             # If we have matched then convert the key to the actual
728             # value stored in the object
729 3         8 for (my $i =0; $i <= $#matched; $i++) {
730 3         8 $matched[$i] = $syn{$matched[$i]};
731             }
732             }
733              
734             # At this point we have matched the userkey to a key in the
735             # defaults list (or if not say so)
736 25 50       71 if ($#matched == -1) {
737 0 0       0 print "Warning: $userkey is not a valid option\n" if $self->{WarnOnMissing};
738             } else {
739 25 50       62 if ( $#matched > 0 ) {
740 0         0 print "Warning: Multiple matches for option $userkey\n";
741 0         0 print "Warning: Could be any of the following:\n";
742 0         0 print join("\n",@matched) . "\n";
743 0         0 print "Accepting the first match ($matched[0])\n";
744             }
745             # Modify the value in %base and keep track of a separate
746             # array containing only the matched keys
747 25         54 $base{$matched[0]} = $user{$userkey};
748 25         50 push(@list, $matched[0]);
749 25 50       61 print "Matched: $userkey for $matched[0]\n" if $self->debug;
750             }
751             }
752              
753             # Finished matching so set this as the current state of the
754             # object
755 30         93 $self->curr_keys(@list);
756 30         111 $self->curr_full(\%base);
757              
758             # Now process the values via the provided translation
759             # if required. Note that the current design means that
760             # We have to run this after we have set the current state.
761             # Otherwise the translation() method would not work directly
762             # and we would have to provide a public version and a private one.
763             # Note that translate updates the current state of the object
764             # So we don't need to catch the return value
765 30 50       99 $self->translate if $self->autotrans;
766              
767             }
768              
769             # Current state should now be in current.
770             # Simply return it
771 30         96 return $self->current;
772              
773             }
774              
775             =item translate
776              
777             Translate the current option values (eg those set via the options()
778             method) using the provided translation().
779              
780             This method updates the current state of the object and returns the
781             updated options hash as a reference.
782              
783             $ref = $opt->translate;
784              
785             =cut
786              
787             sub translate {
788 30     30 1 49 my $self = shift;
789              
790 30         48 my %trans = %{$self->translation};
  30         67  
791 30         68 my %opt = %{$self->curr_full}; # Process all options
  30         61  
792              
793             # Now need to go through each of the keys
794             # and if the corresponding key exists in the translation
795             # hash we need to check that a valid translation exists
796 30         127 foreach my $key ( keys %opt ) {
797 160 50       295 if (exists $trans{$key}) {
798             # Okay so a translation might exist
799             # Now compare keys in the hash in the hash
800 0         0 my %subhash = %{$trans{$key}};
  0         0  
801              
802             my @matched =
803 0         0 $self->compare_with_list(1, $opt{$key}, keys %subhash);
804              
805             # At this point we have matched the userkey to a key in the
806             # dictionary. If there is no translation dont say anything
807             # since it may be a 'REAL' answer (ie 1 instead of 'red')
808              
809 0 0       0 if ($#matched > -1) {
810 0 0       0 if ( $#matched > 0 ) {
811 0         0 print "Warning: Multiple matches for $opt{$key} in option $key\n";
812 0         0 print "Warning: Could be any of the following:\n";
813 0         0 print join("\n",@matched) . "\n";
814 0         0 print "Accepting the first match ($matched[0])\n";
815              
816             }
817             # Modify the value in the options set
818 0 0       0 print "Translation: $opt{$key} translated to $subhash{$matched[0]}\n"
819             if $self->debug;
820 0         0 $opt{$key} = $subhash{$matched[0]};
821              
822             }
823              
824             }
825              
826             }
827              
828             # Update the current state
829 30         82 return $self->curr_full( \%opt );
830              
831             }
832              
833             # Private method to compare a key with a list of keys.
834             # The object controls whether case-sensitivity of minimum matching
835             # are required
836             # Arguments: flag to determine whether I am matchin options or translations
837             # this is needed since both methods are configurable with
838             # regards to minimum matching and case sensitivity.
839             # 0 - use $self->minmatch and $self->casesens
840             # 1 - use $self->minmatchtrans and $self->casesenstrans
841             # $key: Key to be compared
842             # @keys: List of keys
843             # Returns: Array of all keys that match $key taking into account the
844             # object state.
845             #
846             # There must be a more compact way of doing this
847              
848             sub compare_with_list {
849 28     28 0 42 my $self = shift;
850              
851 28         42 my $flag = shift;
852 28         36 my $key = shift;
853 28         70 my @list = @_;
854              
855 28         45 my @result = ();
856              
857 28         43 my ($casesens, $minmatch);
858 28 50       97 if ($flag == 0) {
859 28         56 $casesens = $self->casesens;
860 28         54 $minmatch = $self->minmatch;
861             } else {
862 0         0 $casesens = $self->casesenstrans;
863 0         0 $minmatch = $self->minmatchtrans;
864             }
865              
866             # Do matches
867              
868             # Case Sensitive
869 28 50       74 if ($casesens) {
870              
871             # Always start with the exact match before proceding to minimum
872             # match.
873             # We want to make sure that we will always match on the
874             # exact match even if alternatives exist (eg COL will always
875             # match just COL if the keys are COL and COLOUR)
876             # Case insensitive
877 0         0 @result = grep { /^$key$/ } @list;
  0         0  
878              
879             # Proceed to minimum match if we detected nothing
880             # Minumum match/ Case sensitive
881 0 0 0     0 if ($#result == -1 && $minmatch) {
882              
883 0         0 @result = grep { /^$key/ } @list;
  0         0  
884              
885             }
886              
887             } else {
888              
889             # We want to make sure that we will always match on the
890             # exact match even if alternatives exist (eg COL will always
891             # match just COL if the keys are COL and COLOUR)
892             # First do the exact match (case insensitive)
893             {
894 28         40 local $^W = undef; # To silence warnings about uninitialised values
  28         100  
895 28         62 @result = grep { /^$key$/i } @list;
  152         681  
896             }
897             # If this match came up with something then we will use it
898             # Else we will try a minimum match (assuming flag is true)
899              
900             # Minumum match/ Case insensitive
901 28 100 66     94 if ($#result == -1 && $minmatch) {
902              
903 3         4 @result = grep { /^$key/i } @list;
  6         25  
904              
905             }
906             }
907 28         83 return @result;
908             }
909              
910              
911              
912              
913             =back
914              
915             =head1 EXAMPLE
916              
917             Two examples are shown. The first uses the simplified interface and
918             the second uses the object-oriented interface.
919              
920             =head1 Non-OO
921              
922             use PDLA::Options (':Func');
923              
924             %options = parse( {
925             LINE => 1,
926             COLOUR => 'red',
927             },
928             {
929             COLOR => 'blue'
930             }
931             );
932              
933             This will return a hash containing
934              
935             %options = (
936             LINE => 1,
937             COLOUR => 'blue'
938             )
939              
940              
941             =head1 Object oriented
942              
943             The following example will try to show the main points:
944              
945             use PDLA::Options ();
946              
947             # Create new object and supply defaults
948             $opt = new PDLA::Options( { Colour => 'red',
949             LineStyle => 'dashed',
950             LineWidth => 1
951             }
952             );
953              
954             # Create synonyms
955             $opt->synonyms( { Color => 'Colour' } );
956              
957             # Create translation dictionary
958             $opt->translation( { Colour => {
959             'blue' => '#0000ff',
960             'red' => '#ff0000',
961             'green'=> '#00ff00'
962             },
963             LineStyle => {
964             'solid' => 1,
965             'dashed' => 2,
966             'dotted' => 3
967             }
968             }
969             );
970              
971             # Generate and parse test hash
972             $options = $opt->options( { Color => 'green',
973             lines => 'solid',
974             }
975             );
976              
977             When this code is run, $options will be the reference to a hash
978             containing the following:
979              
980             Colour => '#00ff00',
981             LineStyle => 1,
982             LineWidth => 1
983              
984             If full_options() was set to false (0), $options would be a reference
985             to a hash containing:
986              
987             Colour => '#00ff00',
988             LineStyle => 1
989              
990             Minimum matching and case insensitivity can be configured for both
991             the initial parsing and for the subsequent translating. The translation
992             can be turned off if not desired.
993              
994             Currently synonyms are not available for the translation although this
995             could be added quite simply.
996              
997             =head1 AUTHOR
998              
999             Copyright (C) Tim Jenness 1998 (t.jenness@jach.hawaii.edu). All
1000             rights reserved. There is no warranty. You are allowed to redistribute
1001             this software / documentation under certain conditions. For details,
1002             see the file COPYING in the PDLA distribution. If this file is
1003             separated from the PDLA distribution, the copyright notice should be
1004             included in the file.
1005              
1006             =cut
1007              
1008              
1009             1;
1010