File Coverage

blib/lib/Class/Meta/Express.pm
Criterion Covered Total %
statement 107 107 100.0
branch 21 24 87.5
condition 2 2 100.0
subroutine 22 22 100.0
pod 6 6 100.0
total 158 161 98.1


line stmt bran cond sub pod time code
1             package Class::Meta::Express;
2              
3 2     2   74365 use strict;
  2         5  
  2         1199  
4 2     2   15 use vars qw($VERSION);
  2         8  
  2         307  
5 2     2   8736 use Class::Meta '0.60';
  2         42937  
  2         112  
6              
7             $VERSION = '0.13';
8              
9             my %meta_for;
10              
11             sub import {
12 18     18   55966 my $pkg = shift;
13 18         40 my $caller = caller;
14 2     2   22 no strict 'refs';
  2         4  
  2         6507  
15 18 50       23 return shift if defined &{"$caller\::meta"};
  18         129  
16 108         820 *{"$caller\::$_"} = $pkg->can($_)
17 18         151 for qw(class meta ctor has method build);
18 18         2676 return shift;
19             }
20              
21             sub class (&) {
22 14     14 1 26492 my $code = shift;
23             goto sub {
24 14     14   30 $code->();
25 14         979 goto &build;
26 14         58 };
27             }
28              
29             sub meta {
30 25     25 1 34694 _new_meta( scalar caller, @_ );
31             }
32              
33             sub ctor {
34 8     8 1 56 unshift @_, 'constructor';
35 8         33 goto &_meth;
36             }
37              
38             sub has {
39 21     21 1 1047 my $caller = caller;
40 21         45 my $meta = _meta_for( $caller );
41 21         67 unshift @_, $meta, 'name';
42 21 100       60 splice @_, 3, 1, %{ $_[3] } if ref $_[3] eq 'HASH';
  2         8  
43 21         28 goto &{ $meta->can('add_attribute') };
  21         124  
44             }
45              
46             sub method {
47 4     4 1 399 unshift @_, 'method';
48 4         10 goto &_meth;
49             }
50              
51             sub build {
52 26     26 1 1224 my $meta = delete $meta_for{ my $caller = caller };
53             # Remove exported functions.
54 26         71 _unimport($caller);
55              
56             # Build the class.
57 26         56 unshift @_, $meta;
58 26         31 goto &{ $meta->can('build') };
  26         171  
59             }
60              
61             sub _new_meta {
62 26     26   55 my ($caller, $key) = (shift, shift);
63 26 100       112 my $args = ref $_[0] eq 'HASH' ? $_[0] : { @_ };
64 26         58 $args->{key} = $key;
65 26 100       102 _export(delete $args->{reexport}, $caller, $args) if $args->{reexport};
66 26   100     144 my $meta_class = delete $args->{meta_class} || 'Class::Meta';
67 26         33 my $meta = $meta_class->new( package => $caller, %{ $args } );
  26         153  
68 26         7795 $meta_for{$caller} = $meta;
69 26         122 return $meta;
70             }
71              
72             sub _meta_for {
73 33     33   48 my $caller = shift;
74 33 100       118 unless ( $meta_for{ $caller } ) {
75             # Create a key from the last part of the package name.
76 1         5 (my $key = $caller) =~ s/.*:://;
77 1         3 $key = lcfirst $key;
78 1         7 $key =~ s/([[:upper:]]+)/_\L$1/g;
79 1         4 _new_meta( $caller, $key );
80             }
81 33         65 return $meta_for{ $caller };
82             }
83              
84             sub _meth {
85 12     12   28 my $method = 'add_' . shift;
86 12         39 my $meta = _meta_for( scalar caller );
87 12         32 unshift @_, $meta, 'name';
88 12 100       42 if (my $ref = ref $_[3]) {
89 8 100       25 if ($ref eq 'CODE') {
90 4         14 splice @_, 3, 0, 'code';
91             } else {
92 4 50       14 splice @_, 3, 1, %{ $_[3] } if $ref eq 'HASH';
  4         14  
93             }
94             }
95 12         17 goto &{ $meta->can($method) };
  12         91  
96             }
97              
98             sub _unimport {
99 26     26   40 my $caller = shift;
100 26         55 for my $fn (qw(class meta ctor has method build)) {
101 2     2   211 no strict 'refs';
  2         4  
  2         1374  
102 156         287 my $name = "$caller\::$fn";
103             # Copy the current glob contents, excluding CODE.
104 156         167 my %things = map { $_ => *{$name}{$_} }
  156         662  
  780         2182  
105 156         211 grep { defined *{$name}{$_} }
  780         787  
106             qw(SCALAR ARRAY HASH IO FORMAT);
107             # Undefine the glob and reinstall the contents.
108 156         186 undef *{$name};
  156         405  
109 156         340 *{$name} = $things{$_} for keys %things;
  156         633  
110             }
111             }
112              
113             sub _export {
114 8     8   23 my ($export, $pkg, $args) = @_;
115 8         25 my @args = map { $_ => $args->{$_} } grep { exists $args->{$_} }
  8         25  
  56         124  
116             Class::Meta::INHERITABLE, 'meta_class';
117              
118             my $meta = !@args ? \&meta : sub {
119 4     4   4901 splice @_, 1, 0, @args;
120 4         16 goto &Class::Meta::Express::meta;
121 8 100       38 };
122              
123 8 100       27 $export = 0 unless ref $export eq 'CODE';
124              
125 2     2   11 no strict 'refs';
  2         5  
  2         107  
126 8         50 *{"$pkg\::import"} = sub {
127 8     8   3246 my $caller = caller;
128 2     2   9 no strict 'refs';
  2         4  
  2         273  
129 8 50       14 unless (defined &{"$caller\::meta"}) {
  8         58  
130 8         11 *{"$caller\::meta"} = $meta;
  8         37  
131 40         203 *{"$caller\::$_"} = \&{__PACKAGE__ . "::$_"}
  40         128  
132 8         49 for qw(class ctor has method build);
133             }
134 8 100       32 goto $export if $export;
135 4         692 return shift;
136 8         51 };
137             }
138              
139             1;
140             __END__