File Coverage

blib/lib/Net/OAuth2/Scheme/Option/Builder.pm
Criterion Covered Total %
statement 135 146 92.4
branch 46 62 74.1
condition 12 25 48.0
subroutine 24 24 100.0
pod 6 12 50.0
total 223 269 82.9


line stmt bran cond sub pod time code
1 3     3   21527 use strict;
  3         3  
  3         71  
2 3     3   11 use warnings;
  3         3  
  3         119  
3              
4             package Net::OAuth2::Scheme::Option::Builder;
5             BEGIN {
6 3     3   48 $Net::OAuth2::Scheme::Option::Builder::VERSION = '0.020002_099';
7             }
8             # ABSTRACT: poor man's mixin/role closure builder
9              
10 3     3   1046 use Net::OAuth2::Scheme::Option::Defines qw(All_Classes);
  3         5  
  3         259  
11              
12              
13             # use machinery from Net::OAuth2::TokenType::Scheme::Defines
14             # to gather all default values and group definitions
15             sub _all_defaults {
16 3     3   2 my $class = shift;
17 3     3   13 no strict 'refs';
  3         4  
  3         167  
18 3         7 map {%{"${_}::Default"}} All_Classes($class);
  3         4  
  3         11  
19             }
20              
21             sub _all_groups {
22 4     4   5 my $class = shift;
23 3     3   10 no strict 'refs';
  3         3  
  3         549  
24 4         12 map {%{"${_}::Group"}} All_Classes($class);
  4         3  
  4         18  
25             }
26              
27             # group finder, in case we need it
28             our %find_group;
29             sub _find_group {
30 8     8   7 my $class = shift;
31 8 100       15 unless ($find_group{$class}) {
32 1         3 my %group = $class->_all_groups;
33 1         2 my %fg = ();
34 1         3 for my $g (keys %group) {
35 2         2 $fg{$_} = $g for @{$group{$g}->{keys}};
  2         8  
36             }
37 1         3 $find_group{$class} = \%fg;
38             }
39 8         19 return $find_group{$class};
40             }
41              
42             # if we need to see whether we are leaving behind
43             # any closures with links to self
44             our $Visible_Destroy = 0;
45             sub DESTROY {
46 3 50   3   53 print STDERR "Boom!\n" if $Visible_Destroy;
47             }
48              
49              
50 3     3   1002 use fields qw(value alias default pkg export);
  3         2416  
  3         13  
51              
52             # alias: name -> name2 (where named option actually lives)
53             # default: name -> default value to use if value not specified
54             # pkg: name -> [pkg, args...] to invoke if value not specified
55             # value: name -> value (value for named option or undef)
56             # export: list of exported names
57              
58             sub new {
59 3     3 0 393 my $class = shift;
60 3         6 my %opts = @_;
61 3 50       9 $class = ref($class) if ref($class);
62 3         11 my __PACKAGE__ $self = fields::new($class);
63              
64 3         2868 my %group = $class->_all_groups;
65 3         8 for my $i (values %group) {
66 6 50       14 if (defined $i->{default}) {
67             $self->{pkg}->{$_} = $i->{default}
68 0         0 for @{$i->{keys}};
  0         0  
69             }
70             }
71 3         6 for my $o (keys %opts) {
72 4 100       8 if (my $i = $group{$o}) {
73 2         3 my $impl = $opts{$o};
74 2 100       7 my @ispec = ref($impl) ? @{$impl} : ($impl);
  1         3  
75 2         4 $ispec[0] = "pkg_${o}_$ispec[0]";
76             $self->{pkg}->{$_} = \@ispec
77 2         2 for @{$i->{keys}};
  2         10  
78             }
79             else {
80 2         5 $self->{value}->{$o} = $opts{$o};
81             }
82             }
83              
84             $self->{default} =
85             $self->{value}->{defaults_all}
86             ||
87             { _all_defaults(ref($self)),
88 3   50     16 %{$self->{value}->{defaults} || {}},
89             };
90 3         13 return $self;
91             }
92              
93             # define our own croak so that there are reasonable error messages when options get set incorrectly
94             our @load = ();
95             our $Show_Uses_Stack = 1; #for now
96              
97             sub croak {
98 6     6 1 6 my __PACKAGE__ $self = shift;
99 6         7 my $msg = shift;
100 6         5 my $c = 0;
101 6         11 for my $key (@load) {
102 4   50     7 my $from = ref($self)->_find_group->{$key} || '';
103 4 50       6 if ($from) {
104 0 0       0 my $pkg_foo = $self->{pkg}->{$key} ? $self->{pkg}->{$key}->[0] : '?';
105 0         0 $from = " (group $from ($pkg_foo))";
106             }
107 4         4 ++$c;
108 4   33     9 while (defined(caller($c)) && (caller($c))[3] !~ '::uses$') { ++$c; }
  0         0  
109 4         198 while ((caller($c))[0] eq __PACKAGE__) { ++$c; }
  2         40  
110 4 50       98 if ($Show_Uses_Stack) {
111 0         0 my ($file,$line) = (caller($c))[1,2];
112 0         0 print STDERR "... option '$key'$from needed at $file, line $line'\n";
113             }
114             }
115             {
116 3     3   1226 no strict 'refs';
  3         4  
  3         2309  
  6         4  
117             # make Carp trust everyone between here and first caller to uses()
118             # which is usually going to be Scheme->new().
119 12         127 push @{(caller($_))[0] . '::CARP_NOT'}, __PACKAGE__
120 6         14 for (0..$c);
121             }
122 6         190 Carp::croak($msg);
123             }
124              
125             # actual('key')
126             # where to lookup pkg,default,value for 'key'
127             sub actual {
128 68     68 0 51 my __PACKAGE__ $self = shift;
129 68         58 my ($key) = @_;
130 68         135 while (defined(my $nkey = $self->{alias}->{$key})) {
131 14         27 $key = $nkey;
132             }
133 68         103 return $key;
134             }
135              
136             # alias('key','key2')
137             # causes options 'key' and 'key2' to become synonyms
138             sub make_alias {
139 9     9 0 147 my __PACKAGE__ $self = shift;
140 9         13 my ($okey, $okey2) = @_;
141 9         10 my ( $key, $key2) = map {$self->actual($_)} @_;
  18         23  
142              
143             # only options that have not been claimed by groups
144             # can have {alias} entries; so make sure $key is
145             # the one that is not in a group.
146             ( $key, $key2, $okey, $okey2)
147             = ($key2, $key, $okey2, $okey)
148 9 100       20 if $self->{pkg}->{$key};
149              
150             # if both $key and $key2 are in groups, we die,
151             # because otherwise, there will be ambiguity about
152             # which pkg_ routine is invoked to initialize them
153             Carp::croak("cannot alias group members to each other: '$okey'"
154             .($okey ne $key ? " ('$key')" : "")
155             ." <-> '$okey2'"
156             .($okey2 ne $key2 ? " ('$key2')" :""))
157 9 100       43 if $self->{pkg}->{$key};
    100          
    100          
158              
159             # if there is a value, make sure it lives on $key2
160 7 100       17 if (defined($self->{value}->{$key2})) {
    100          
161             $self->croak("settings of options '$key' and '$key2' conflict")
162             if (defined($self->{value}->{$key})
163 4 100 66     18 && $self->{value}->{$key} ne $self->{value}->{$key2});
164             }
165             elsif (defined($self->{value}->{$key})) {
166 1         2 $self->{value}->{$key2} = $self->{value}->{$key};
167             }
168              
169             # if there is a default value, make sure it lives on $key2
170 6 50       16 if (defined($self->{default}->{$key2})) {
    50          
171             # make conflicting defaults disappear
172             delete $self->{default}->{$key2}
173             if (defined($self->{default}->{$key})
174 0 0 0     0 && $self->{default}->{$key} ne $self->{default}->{$key2});
175             }
176             elsif (defined($self->{default}->{$key})) {
177 0         0 $self->{default}->{$key2} = $self->{default}->{$key};
178             }
179             # remove stuff that does not matter anymore
180 6         8 delete $self->{default}->{$key};
181 6         38 delete $self->{value}->{$key};
182              
183             # we can point $key to $key2 (finally)
184 6         19 $self->{alias}->{$key} = $key2;
185             }
186              
187              
188             # installed('key')
189             # value for 'key' or undef
190             sub installed {
191 2     2 0 8 my __PACKAGE__ $self = shift;
192 2         3 my ($key, $default) = @_;
193              
194 2         8 return $self->{value}->{$self->actual($key)};
195             }
196              
197              
198             # uses(key => [,default_value])
199             # value for 'key'; if not defined yet
200             # either use default_value, {default}->{key}, install package for it, or die
201             sub uses {
202 30     30 1 290 my __PACKAGE__ $self = shift;
203 30         33 my ($okey, $default) = @_;
204 30         44 my $key = $self->actual($okey);
205 30         55 local @load = ($okey, @load);
206              
207 30 100       56 unless (exists($self->{value}->{$key})) {
208 9 100 100     37 if (defined $default
    100          
209             || defined($default = $self->{default}->{$key})) {
210 3         15 $self->install($key, $default);
211             }
212 6 100       31 elsif (my ($pkg,@kvs) = @{$self->{pkg}->{$key} || []}) {
213 2 50       6 ($pkg,@kvs) = @$pkg if ref($pkg);
214 2         15 $self->$pkg(@kvs);
215             Carp::croak("package failed to define value: $pkg -> $key")
216 2 50       6 unless defined($self->{value}->{$key});
217             }
218             }
219 30         33 my $value = $self->{value}->{$key};
220 30 100       40 unless (defined($value)) {
221 4         16 my $g = ref($self)->_find_group->{$key};
222 4   33     21 $self->croak("a setting for '".($g || $key)."' is needed");
223             }
224 26         89 return $value;
225             }
226              
227             # ensure(key => $value, $msg)
228             # == uses(key => $value) and die with $msg if value is not $value
229             sub ensure {
230 4     4 1 32 my __PACKAGE__ $self = shift;
231 4         6 my ($key, $value, $msg) = @_;
232 4 100 33     8 $self->uses($key, $value) eq $value
233             or $self->croak($msg || "option '$key' must be '$value' here.");
234 3         9 return $value;
235             }
236              
237             # uses_all(qw(key1 key2 ...))
238             # == (uses('key1'), uses('key2'),...)
239             sub uses_all {
240 3     3 1 5 my __PACKAGE__ $self = shift;
241 3         5 return map {$self->uses($_)} @_;
  10         10  
242             }
243              
244             sub parameter_prefix {
245 2     2 0 10 my __PACKAGE__ $self = shift;
246 2         4 my $prefix = shift;
247 2 50 66     8 if (@_ && $_[0] eq '_default') {
248 0         0 shift;
249             # discard default parameter name if not needed
250 0 0       0 shift if @_ % 2;
251             }
252 2         4 my (%h) = @_;
253             $self->ensure("${prefix}$_",$h{$_})
254 2         9 for (keys %h);
255             }
256              
257             # install(key => $value) sets option 'key' to $value
258             sub install {
259 13     13 1 105 my __PACKAGE__ $self = shift;
260 13         11 my ($okey, $value) = @_;
261 13         16 my $key = $self->actual($okey);
262              
263 13 100       30 Carp::croak("tried to install undef?: $okey")
264             unless defined $value;
265             Carp::croak("multiple definitions?: $okey")
266 12 100       32 if defined $self->{value}->{$key};
267              
268 10         21 $self->{value}->{$key} = $value;
269             }
270              
271             # export(keys...) == uses_all(keys ...)
272             # marking all keys as being exported.
273             sub export {
274 2     2 1 27 my __PACKAGE__ $self = shift;
275 2         6 my @r = $self->uses_all(@_);
276 1         6 $self->{export}->{$_}++ for (@_);
277 1         7 return @r;
278             }
279              
280             sub all_exports {
281 2     2 0 3 my __PACKAGE__ $self = shift;
282 2         2 return keys %{$self->{export}};
  2         14  
283             }
284              
285              
286             # new( defaults => { additional defaults... } ...)
287             # if you want to keep all of the various default values set
288             # and only make minor changes
289             # new( defaults_all => { defaults ...}
290             # if you want to entirely replace all default values;
291             # in which case this function never gets called
292             # since defaults_all is already set;
293             # Kids, don't try this at home...
294              
295             1;
296              
297              
298             __END__