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 78     78   566 use strict;
  78         174  
  78         2645  
40 78     78   411 use Carp;
  78         159  
  78         5841  
41              
42 78     78   469 use vars qw/$VERSION %EXPORT_TAGS %DEF_SYNS @ISA/;
  78         153  
  78         186565  
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 22 my ($href) = @_;
111 8 100 66     45 return defined $href && ref $href eq 'HASH' ? $href : {};
112             }
113              
114 0     0 1 0 sub parse { return _parse(1,@_) }
115 16     16 1 172 sub iparse { return _parse(0,@_) }
116              
117             sub _parse {
118              
119 16 50   16   48 croak 'Usage: parse( \%defaults, \%user )' if scalar(@_) != 3;
120              
121 16         87 my $casechk = shift;
122 16         28 my $defaults = shift;
123 16 50       51 croak ("First argument is not a hash reference")
124             unless ref($defaults) eq "HASH";
125              
126 16         27 my $user = shift;
127 16 50       44 croak ("Second argument is not a hash reference")
128             unless ref($user) eq "HASH";
129              
130             # Create new object
131 16         84 my $opt = new PDLA::Options ( $defaults );
132              
133             # Set up default behaviour
134 16         58 $opt->minmatch(1);
135 16         66 $opt->casesens($casechk);
136 16         55 $opt->synonyms( \%DEF_SYNS );
137              
138             # Process the options
139 16         54 my $optref = $opt->options( $user );
140              
141 16         163 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 43     43 1 125 my $proto = shift;
172 43   33     369 my $class = ref($proto) || $proto;
173              
174 43         101 my $opt = {};
175              
176             # Set up object structure
177 43         131 $opt->{DEFAULTS} = {}; # Default options
178 43         110 $opt->{CURRENT} = {}; # Current options
179 43         112 $opt->{CurrKeys} = []; # list of selected keys if full_options(0)
180 43         111 $opt->{SYNONYMS} = {}; # List of synonyms
181 43         97 $opt->{INC} = 0; # Flag to decide whether we are incremental on cur
182 43         85 $opt->{CaseSens} = 0; # Are options case sensitive
183 43         92 $opt->{MinMatch} = 1; # Minimum matching on keys
184 43         127 $opt->{Translation} = {};# Translation from eg 'RED' to 1
185 43         93 $opt->{AutoTranslate}= 1;# Automatically translate options when processing
186 43         85 $opt->{MinMatchTrans} = 0; # Min matching during translation
187 43         89 $opt->{CaseSensTrans} = 0; # Case sensitive during translation
188             # Return full options list
189 43         114 $opt->{FullOptions} = $default->{FullOptions};
190             # Whether to warn for options that are invalid or not
191 43         92 $opt->{WarnOnMissing}= $default->{WarnOnMissing};
192 43         96 $opt->{DEBUG} = $default->{DEBUG}; # Turn on debug messages
193              
194             # Bless into class
195 43         94 bless ( $opt, $class);
196              
197             # If we were passed arguments, pass to defaults method
198 43 50       140 if (@_) { $opt->defaults( @_ ); }
  43         157  
199              
200 43         134 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 73     73 1 140 my $self = shift;
276              
277 73 100       184 if (@_) {
278 43         74 my $arg = shift;
279 43 50       182 croak("Argument is not a hash reference") unless ref($arg) eq "HASH";
280 43         266 $self->{DEFAULTS} = $arg;
281              
282             # Reset the current state (making sure that I disconnect the
283             # hashes
284 43         259 my %hash = %$arg;
285 43         186 $self->curr_full(\%hash);
286              
287             }
288              
289             # Decouple the hash to protect it from being modified outside the
290             # object
291 73         164 my %hash = %{$self->{DEFAULTS}};
  73         295  
292 73         173 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 91 my $self = shift;
353              
354 57 100       129 if (@_) {
355 27         41 my $arg = shift;
356 27 50       71 croak("Argument is not a hash reference") unless ref($arg) eq "HASH";
357 27         64 $self->{SYNONYMS} = $arg;
358             }
359              
360             # Decouple the hash to protect it from being modified outside the
361             # object
362 57         79 my %hash = %{$self->{SYNONYMS}};
  57         205  
363 57         160 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 71 my $self = shift;
381              
382 42 50       103 if ($self->full_options) {
383 42         77 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 53 my $self = shift;
417 30 100       73 if (@_) { @{$self->{CurrKeys}} = @_; }
  22         45  
  22         78  
418 30         46 return @{$self->{CurrKeys}};
  30         72  
419             }
420              
421             # Method to set the full state of the object
422             # Not publicising this
423              
424             sub curr_full {
425 175     175 0 269 my $self = shift;
426              
427 175 100       346 if (@_) {
428 103         158 my $arg = shift;
429 103 50       355 croak("Argument is not a hash reference") unless ref($arg) eq "HASH";
430 103         269 $self->{CURRENT} = $arg;
431             }
432              
433             # Decouple the hash
434 175         240 my %hash = %{$self->{CURRENT}};
  175         696  
435 175         557 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 51 my $self = shift;
470              
471 30 50       97 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         46 my %hash = %{$self->{Translation}};
  30         97  
480 30         74 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       85 if (@_) { $self->{INC} = shift; }
  0         0  
499 30         100 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 63 my $self = shift;
520 42 50       104 if (@_) { $self->{FullOptions} = shift; }
  0         0  
521 42         118 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 67 my $self = shift;
536 44 100       96 if (@_) { $self->{CaseSens} = shift; }
  16         32  
537 44         77 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 75 my $self = shift;
558 44 100       94 if (@_) { $self->{MinMatch} = shift; }
  16         32  
559 44         69 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 59 my $self = shift;
575 30 50       77 if (@_) { $self->{AutoTranslate} = shift; }
  0         0  
576 30         114 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 41 my $self = shift;
647 25 50       65 if (ref $self) {
648 25 50       69 if (@_) { $self->{DEBUG} = shift; }
  0         0  
649 25         113 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 53 my $self = shift;
688              
689             # If there is an argument do something clever
690 30 50       83 if (@_) {
691              
692             # check that the arg is a hash
693 30         42 my $arg = shift;
694 30 50       86 croak("Argument is not a hash reference") unless ref($arg) eq "HASH";
695              
696             # Turn the options into a real hash
697 30         89 my %user = %$arg;
698              
699             # Now read in the base options
700 30         52 my $base;
701 30 50       77 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         114 my %base = %$base;
709              
710             # Store a list of all the expanded user keys
711 30         67 my @list = ();
712              
713             # Read in synonyms
714 30         54 my %syn = %{$self->synonyms};
  30         68  
715              
716             # Now go through the keys in the user hash and compare with
717             # the defaults
718 30         144 foreach my $userkey (sort keys %user) {
719              
720             # Check for matches in the default set
721 25         100 my @matched = $self->compare_with_list(0, $userkey, keys %base);
722              
723             # If we had no matches, check the synonyms list
724 25 100       76 if ($#matched == -1) {
725 3         11 @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         10 for (my $i =0; $i <= $#matched; $i++) {
730 3         9 $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       66 if ($#matched == -1) {
737 0 0       0 print "Warning: $userkey is not a valid option\n" if $self->{WarnOnMissing};
738             } else {
739 25 50       83 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         66 $base{$matched[0]} = $user{$userkey};
748 25         51 push(@list, $matched[0]);
749 25 50       70 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         114 $self->curr_keys(@list);
756 30         110 $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       92 $self->translate if $self->autotrans;
766              
767             }
768              
769             # Current state should now be in current.
770             # Simply return it
771 30         99 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 50 my $self = shift;
789              
790 30         44 my %trans = %{$self->translation};
  30         87  
791 30         60 my %opt = %{$self->curr_full}; # Process all options
  30         76  
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         123 foreach my $key ( keys %opt ) {
797 160 50       303 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         87 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 62 my $self = shift;
850              
851 28         53 my $flag = shift;
852 28         42 my $key = shift;
853 28         86 my @list = @_;
854              
855 28         48 my @result = ();
856              
857 28         49 my ($casesens, $minmatch);
858 28 50       70 if ($flag == 0) {
859 28         56 $casesens = $self->casesens;
860 28         64 $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       60 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         46 local $^W = undef; # To silence warnings about uninitialised values
  28         109  
895 28         60 @result = grep { /^$key$/i } @list;
  152         717  
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     117 if ($#result == -1 && $minmatch) {
902              
903 3         5 @result = grep { /^$key/i } @list;
  6         33  
904              
905             }
906             }
907 28         88 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