File Coverage

blib/lib/Hash/AutoHash/Args.pm
Criterion Covered Total %
statement 107 108 99.0
branch 28 32 87.5
condition 13 18 72.2
subroutine 33 33 100.0
pod n/a
total 181 191 94.7


line stmt bran cond sub pod time code
1             package Hash::AutoHash::Args;
2             our $VERSION='1.18';
3             $VERSION=eval $VERSION; # I think this is the accepted idiom..
4              
5             #################################################################################
6             #
7             # Author: Nat Goodman
8             # Created: 09-03-05
9             # $Id:
10             #
11             # Simplifies processing of keyward argument lists.
12             # Replaces Class::AutoClass::Args using Class::AutoClass:Hash and tied hash to
13             # provide cleaner, more powerful interface.
14             # NOT completely compatible with Class::AutoClass::Args.
15             # Use Hash::AutoHash::Args::V0 if compatibility with Class::AutoClass::Args needed
16             #
17             #################################################################################
18 12     12   243919 use strict;
  12         27  
  12         468  
19 12     12   59 use Carp;
  12         21  
  12         727  
20 12     12   7911 use Hash::AutoHash;
  12         66338  
  12         78  
21 12     12   2217 use base qw(Hash::AutoHash);
  12         25  
  12         3264  
22              
23             our @NORMAL_EXPORT_OK=
24             qw(get_args getall_args set_args fix_args fix_keyword fix_keywords is_keyword is_positional
25             autoargs_get autoargs_set);
26             our @RENAME_EXPORT_OK=sub {s/^autohash/autoargs/; $_};
27             # our @EXPORT_OK=Hash::AutoHash::Args::helper->EXPORT_OK;
28             # our @SUBCLASS_EXPORT_OK=Hash::AutoHash::Args::helper->SUBCLASS_EXPORT_OK;
29             my $helper_class=__PACKAGE__.'::helper';
30             our @EXPORT_OK=$helper_class->EXPORT_OK;
31             our @SUBCLASS_EXPORT_OK=$helper_class->SUBCLASS_EXPORT_OK;
32              
33             # sub new {
34             # my $class_or_self=@_>0 && shift;
35             # # send to parent if called as object method. will access hash slot via AUTOLOAD
36             # return $class_or_self->SUPER::new(@_) if ref $class_or_self;
37             # # do regular 'new' via helper class if called as class method.
38             # my $helper_class=$class_or_self.'::helper';
39             # $helper_class->_new($class_or_self,@_);
40             # }
41              
42             #################################################################################
43             # helper package exists to avoid polluting Hash::AutoHash::Args namespace with
44             # subs that would mask accessor/mutator AUTOLOADs
45             # functions herein (except _new) are exportable by Hash::AutoHash::Args
46             #################################################################################
47             package Hash::AutoHash::Args::helper;
48             our $VERSION=$Hash::AutoHash::Args::VERSION;
49 12     12   75 use strict;
  12         18  
  12         341  
50 12     12   106 use Carp;
  12         20  
  12         684  
51 12     12   72 use Scalar::Util qw(reftype);
  12         24  
  12         828  
52             BEGIN {
53 12     12   401 our @ISA=qw(Hash::AutoHash::helper);
54             }
55 12     12   68 use Hash::AutoHash qw(autohash_tie);
  12         30  
  12         74  
56              
57             sub _new {
58 76     76   74747 my($helper_class,$class,@args)=@_;
59 76         292 my $self=autohash_tie Hash::AutoHash::Args::tie,@args;
60 76         645 bless $self,$class;
61             }
62              
63             #################################################################################
64             # functions from Class::AutoClass::Args
65             # get_args, set_args are redundant w/ autoargs_get, autoargs_set
66             # getall_args is trivial wrapper for %$args....
67             #################################################################################
68             sub get_args {
69 17     17   2793 my($self,@args)=@_;
70 17 50 66     91 @args=@{$args[0]} if @args==1 && 'ARRAY' eq ref $args[0];
  0         0  
71 17         36 @args=fix_keyword(@args);
72 17         38 my @results=map {$self->{$_}} @args;
  33         148  
73             # NG 09-03-12: line below is ancient bug. see POD. scary it wasn't caught sooner
74             # wantarray? @results: $results[0];
75 17 100       87 wantarray? @results: \@results;
76             }
77 7     7   8084 sub autoargs_get { get_args(@_); } # do it this way so defined at compile-time
78             # *autoargs_get=\&get_args; # NOT this way!
79              
80             sub getall_args {
81 6     6   4929 my $self = shift;
82 6 100       47 wantarray? %$self: {%$self};
83             }
84             sub set_args {
85 12     12   6814 my $self=shift;
86 12 100 100     103 if (@_==2 && 'ARRAY' eq ref $_[0] && 'ARRAY' eq ref $_[1]) { # separate arrays form
      66        
87 4         10 my($keys,$values)=@_;
88 4         14 my @keys=fix_keywords(@$keys);
89 4         11 my @values=@$values;
90 4         16 for (my $i=0; $i<@keys; $i++) {
91 8         16 my($key,$value)=($keys[$i],$values[$i]);
92 8         34 $self->{$key}=$value;
93             }} else {
94 8         27 my $args=fix_args(@_);
95 8         50 while(my($key,$value)=each %$args) {
96 16         142 $self->$key($value);
97             }}
98 12         32 $self;
99             }
100 5     5   3736 sub autoargs_set { set_args(@_); } # do it this way so defined at compile-time
101             # *autoargs_set=\&set_args; # NOT this way!
102              
103             sub fix_args {
104 12     12   9759 no warnings;
  12         20  
  12         7338  
105 88     88   3496 my(@args)=@_;
106 88 100 100     371 @args=@{$args[0]} if @args==1 && 'ARRAY' eq ref $args[0];
  3         13  
107 88 100 66     329 @args=%{$args[0]} if @args==1 && 'HASH' eq reftype $args[0];
  6         31  
108 88 50       283 confess("Malformed keyword argument list (odd number of elements): @args") if @args%2;
109 88         155 my $args={};
110 88         228 while(@args) {
111 176         522 my($keyword,$value)=(fix_keyword(shift @args),shift @args);
112 176 100       837 $args->{$keyword}=$value,next unless exists $args->{$keyword};
113 43         78 my $old=$args->{$keyword};
114             # NG 09-12-31: breaks if $old is object.
115             # $args->{$keyword}=[$old,$value],next unless ref $old; # grow scalar slot into ARRAY
116 43 100       205 $args->{$keyword}=[$old,$value],next unless 'ARRAY' eq ref $old; # grow scalar slot into ARRAY
117 10         47 push(@$old,$value); # else add new value to ARRAY slot
118             }
119 88         432 $args;
120             }
121             sub fix_keyword {
122 649     649   9755 my @keywords=@_; # copies input, so update-in-place doesn't munge it
123 649         992 for my $keyword (@keywords) {
124 688 50       1401 next unless defined $keyword;
125 688 50       5163 $keyword=~s/^-*(.*)$/\L$1/ unless ref $keyword; # updates in place
126             }
127 649 100       2453 wantarray? @keywords: $keywords[0];
128             }
129 8     8   3899 sub fix_keywords {fix_keyword(@_);}
130 7 100   7   4696 sub is_keyword {!(@_%2) && $_[0]=~/^-/;}
131 7 100   7   425 sub is_positional {@_%2 || $_[0]!~/^-/;}
132              
133             #################################################################################
134             # Tied hash which provides the core capabilities of Hash::AutoHash::Args
135             #################################################################################
136             package Hash::AutoHash::Args::tie;
137             our $VERSION=$Hash::AutoHash::Args::VERSION;
138 12     12   67 use strict;
  12         18  
  12         370  
139 12     12   73 use Carp;
  12         31  
  12         668  
140 12     12   62 use Tie::Hash;
  12         25  
  12         5480  
141             our @ISA=qw(Tie::StdHash);
142             *fix_args=\&Hash::AutoHash::Args::helper::fix_args;
143             *fix_keyword=\&Hash::AutoHash::Args::helper::fix_keyword;
144              
145             sub TIEHASH {
146 76     76   959 my($class,@args)=@_;
147 76   33     389 $class=(ref $class)||$class;
148 76         223 bless Hash::AutoHash::Args::helper::fix_args(@args), $class;
149             }
150             # following code adapted from Tie::StdHash
151             # sub TIEHASH { bless {}, $_[0] }
152             # sub STORE { $_[0]->{fix_keyword($_[1])} = $_[2] }
153             sub STORE {
154 113     113   40411 my $self=shift;
155 113         235 my $keyword=fix_keyword(shift);
156 113 100       291 my $value=@_==1? $_[0]: [@_];
157 113         656 $self->{$keyword}=$value;
158             }
159             sub FETCH {
160 291     291   49301 my $self=shift;
161 291         507 my $keyword=fix_keyword(shift);
162             # non-existent arg should return nothing. not undef! this works when accessing the
163             # object directly or using autoloaded methods from the main class. when accessing
164             # via the tied hash interface, Perl converts the result to undef anyway :(
165 291 100       820 return unless exists $self->{$keyword};
166 273         1171 return $self->{$keyword};
167             }
168 57     57   42162 sub FIRSTKEY { my $a = scalar keys %{$_[0]}; each %{$_[0]} }
  57         127  
  57         64  
  57         292  
169 143     143   540 sub NEXTKEY { each %{$_[0]} }
  143         487  
170 29     29   5439 sub EXISTS { exists $_[0]->{fix_keyword($_[1])} }
171 10     10   71 sub DELETE { delete $_[0]->{fix_keyword($_[1])} }
172 5     5   3050 sub CLEAR { %{$_[0]} = () }
  5         25  
173 11     11   3671 sub SCALAR { scalar %{$_[0]} }
  11         49  
174              
175             1;
176              
177             __END__