File Coverage

web/cgi-bin/yatt.lib/YATT/ArgTypes.pm
Criterion Covered Total %
statement 76 81 93.8
branch 18 26 69.2
condition 2 3 66.6
subroutine 14 15 93.3
pod 0 5 0.0
total 110 130 84.6


line stmt bran cond sub pod time code
1             # -*- mode: perl; coding: utf-8 -*-
2 3     3   2344 package YATT::ArgTypes; use YATT::Inc;
  3         3  
  3         17  
3 3     3   10 use strict;
  3         5  
  3         79  
4 3     3   11 use warnings FATAL => qw(all);
  3         2  
  3         97  
5              
6 3     3   8 use base qw(YATT::Class::Configurable);
  3         5  
  3         421  
7 3         17 use YATT::Fields qw(cf_callpack
8             cf_base cf_type_map cf_type_fmt
9             cf_type_name
10             cf_debug
11 3     3   335 );
  3         4  
12 3     3   11 use YATT::Util;
  3         4  
  3         301  
13 3     3   10 use YATT::Util::Symbol;
  3         5  
  3         168  
14 3     3   14 use Carp;
  3         5  
  3         2059  
15              
16             sub import {
17 3     3   6 my $pack = shift;
18 3         6 my ($callpack) = caller;
19 3         5 my @types;
20 3         11 my $opts = $pack->new(callpack => $callpack
21             , $pack->parse_args(\@_, \@types));
22 3         13 $opts->add_type($_) for @types;
23             }
24              
25             sub parse_args {
26 3     3 0 6 my ($pack, $arglist, $taskqueue) = @_;
27 3         3 my @confs;
28 3         10 while (@$arglist) {
29 33 100       71 if (ref $arglist->[0]) {
    50          
30 21         28 push @$taskqueue, shift @$arglist;
31             } elsif (my ($flag, $key) = $arglist->[0] =~ /^([\-:])(\w+)/) {
32 12         9 shift @$arglist;
33 12 100       21 my $value = $flag eq ':' ? 1 : shift @$arglist;
34 12         28 push @confs, $key, $value;
35             } else {
36 0         0 croak "Invalid option '$arglist->[0]'";
37             }
38             }
39 3         31 @confs;
40             }
41              
42             sub add_type {
43 21     21 0 20 (my MY $self, my ($desc)) = @_;
44 21         24 my $type = shift @$desc;
45 21         59 my $fullclass = sprintf $self->{cf_type_fmt}, $type;
46              
47 21         34 $self->{cf_type_map}{$type} = $fullclass;
48              
49 21 50       64 define_const(globref($fullclass, "type_name"), $type)
50             if $self->{cf_type_name};
51              
52             # t_zzz typealias.
53 21         55 define_const(globref($self->{cf_callpack}, "t_$type"), $fullclass);
54              
55 21         45 my $fields = fields_hash($self);
56              
57 21         23 my (@symbols, @tasks, %config);
58 21         37 while (@$desc) {
59 27 100       110 if (ref $desc->[0] eq 'SCALAR') {
    50          
60 9         17 my ($nameref, $value) = splice @$desc, 0, 2;
61 9         9 my $code = do {
62 9 50       16 unless (ref $value) {
    0          
63 9     0   38 sub () { $value };
  0         0  
64             } elsif (ref $value eq 'CODE') {
65 0         0 $value;
66             } else {
67 0         0 die "Unknown ArgType desc for $$nameref : '$value'";
68             }
69             };
70 9         23 push @symbols, [$$nameref, $code];
71             # *{globref($fullclass, $$nameref)} = $code;
72             } elsif (my ($flag, $key) = $desc->[0] =~ /^([\-:])(\w+)/) {
73 18         18 shift @$desc;
74 18 50       27 my $value = $flag eq ':' ? 1 : shift @$desc;
75 18 100       36 if ($fields->{"cf_$key"}) {
76 3         11 $config{"cf_$key"} = $value;
77             } else {
78 15 50       54 my $sub = $self->can("option_$key")
79             or die "Unknown ArgType option $key";
80 15         41 push @tasks, [$sub, $value];
81             }
82             # $sub->($self, $fullclass, $value);
83             } else {
84 0         0 die "Unknown desc type $desc"
85             }
86             }
87              
88             # base だけは eval を使う。 さもないと %FIELDS が作られない。
89             # *{globref($fullclass, 'ISA')} = [$self->{cf_base}];
90             $self->checked_eval
91 21   66     51 (sprintf qq{package %s; use base qw(%s)}
92             , $fullclass
93             , $self->lookup_in($self->{cf_type_map}, $config{cf_base})
94             || $$self{cf_base});
95              
96 21         34 foreach my $rec (@symbols) {
97 9         12 my ($sym, $code) = @$rec;
98 9         9 *{globref($fullclass, $sym)} = $code;
  9         17  
99             }
100              
101 21         45 foreach my $rec (@tasks) {
102 15         16 my ($sub, $value) = @$rec;
103 15         27 $sub->($self, $fullclass, $value, \%config);
104             }
105             }
106              
107             sub lookup_in {
108 21     21 0 32 my ($self, $hash, $key) = @_;
109 21 100       126 return unless defined $key;
110 3         14 $hash->{$key};
111             }
112              
113             sub option_alias {
114 9     9 0 11 (my MY $self, my ($class, $value)) = @_;
115 9 100       19 foreach my $alias (ref $value ? @$value : $value) {
116 12         42 $self->{cf_type_map}{$alias} = $class;
117             }
118             }
119              
120             sub option_fields {
121 6     6 0 9 (my MY $self, my ($class, $value)) = @_;
122 6         17 my $fields = terse_dump(@$value);
123 6         194 $self->checked_eval(<
124             package $class; use YATT::Fields $fields;
125             END
126             }
127              
128             1;