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_01';
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   303528 use strict;
  12         21  
  12         404  
19 12     12   59 use Carp;
  12         19  
  12         816  
20 12     12   4722 use Hash::AutoHash;
  12         127006  
  12         80  
21 12     12   2656 use base qw(Hash::AutoHash);
  12         51  
  12         4168  
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   82 use strict;
  12         30  
  12         316  
50 12     12   70 use Carp;
  12         23  
  12         783  
51 12     12   70 use Scalar::Util qw(reftype);
  12         22  
  12         828  
52             BEGIN {
53 12     12   417 our @ISA=qw(Hash::AutoHash::helper);
54             }
55 12     12   72 use Hash::AutoHash qw(autohash_tie);
  12         18  
  12         71  
56              
57             sub _new {
58 76     76   47462 my($helper_class,$class,@args)=@_;
59 76         244 my $self=autohash_tie Hash::AutoHash::Args::tie,@args;
60 76         328 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   1944 my($self,@args)=@_;
70 17 50 66     73 @args=@{$args[0]} if @args==1 && 'ARRAY' eq ref $args[0];
  0         0  
71 17         41 @args=fix_keyword(@args);
72 17         36 my @results=map {$self->{$_}} @args;
  33         116  
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       71 wantarray? @results: \@results;
76             }
77 7     7   6208 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   3274 my $self = shift;
82 6 100       49 wantarray? %$self: {%$self};
83             }
84             sub set_args {
85 12     12   4022 my $self=shift;
86 12 100 100     98 if (@_==2 && 'ARRAY' eq ref $_[0] && 'ARRAY' eq ref $_[1]) { # separate arrays form
      66        
87 4         9 my($keys,$values)=@_;
88 4         9 my @keys=fix_keywords(@$keys);
89 4         9 my @values=@$values;
90 4         13 for (my $i=0; $i<@keys; $i++) {
91 8         15 my($key,$value)=($keys[$i],$values[$i]);
92 8         28 $self->{$key}=$value;
93             }} else {
94 8         23 my $args=fix_args(@_);
95 8         61 while(my($key,$value)=each %$args) {
96 16         134 $self->$key($value);
97             }}
98 12         24 $self;
99             }
100 5     5   2402 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   6318 no warnings;
  12         23  
  12         6658  
105 88     88   2684 my(@args)=@_;
106 88 100 100     320 @args=@{$args[0]} if @args==1 && 'ARRAY' eq ref $args[0];
  3         9  
107 88 100 66     281 @args=%{$args[0]} if @args==1 && 'HASH' eq reftype $args[0];
  6         30  
108 88 50       225 confess("Malformed keyword argument list (odd number of elements): @args") if @args%2;
109 88         111 my $args={};
110 88         219 while(@args) {
111 176         262 my($keyword,$value)=(fix_keyword(shift @args),shift @args);
112 176 100       594 $args->{$keyword}=$value,next unless exists $args->{$keyword};
113 43         55 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       159 $args->{$keyword}=[$old,$value],next unless 'ARRAY' eq ref $old; # grow scalar slot into ARRAY
117 10         28 push(@$old,$value); # else add new value to ARRAY slot
118             }
119 88         293 $args;
120             }
121             sub fix_keyword {
122 649     649   7757 my @keywords=@_; # copies input, so update-in-place doesn't munge it
123 649         771 for my $keyword (@keywords) {
124 688 50       1015 next unless defined $keyword;
125 688 50       4089 $keyword=~s/^-*(.*)$/\L$1/ unless ref $keyword; # updates in place
126             }
127 649 100       1749 wantarray? @keywords: $keywords[0];
128             }
129 8     8   3330 sub fix_keywords {fix_keyword(@_);}
130 7 100   7   3782 sub is_keyword {!(@_%2) && $_[0]=~/^-/;}
131 7 100   7   695 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   78 use strict;
  12         17  
  12         374  
139 12     12   60 use Carp;
  12         19  
  12         802  
140 12     12   65 use Tie::Hash;
  12         19  
  12         5608  
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   779 my($class,@args)=@_;
147 76   33     382 $class=(ref $class)||$class;
148 76         168 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   30802 my $self=shift;
155 113         182 my $keyword=fix_keyword(shift);
156 113 100       236 my $value=@_==1? $_[0]: [@_];
157 113         390 $self->{$keyword}=$value;
158             }
159             sub FETCH {
160 291     291   41618 my $self=shift;
161 291         368 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       641 return unless exists $self->{$keyword};
166 273         1287 return $self->{$keyword};
167             }
168 57     57   22839 sub FIRSTKEY { my $a = scalar keys %{$_[0]}; each %{$_[0]} }
  57         106  
  57         49  
  57         218  
169 143     143   212 sub NEXTKEY { each %{$_[0]} }
  143         295  
170 29     29   4510 sub EXISTS { exists $_[0]->{fix_keyword($_[1])} }
171 10     10   69 sub DELETE { delete $_[0]->{fix_keyword($_[1])} }
172 5     5   2013 sub CLEAR { %{$_[0]} = () }
  5         21  
173 11     11   3025 sub SCALAR { scalar %{$_[0]} }
  11         46  
174              
175             1;
176              
177             __END__