File Coverage

lib/MouseX/OO_Modulino/MOP4Import.pm
Criterion Covered Total %
statement 50 105 47.6
branch 7 30 23.3
condition 1 9 11.1
subroutine 16 25 64.0
pod 0 16 0.0
total 74 185 40.0


line stmt bran cond sub pod time code
1             package MouseX::OO_Modulino::MOP4Import;
2 1     1   5 use strict;
  1         2  
  1         50  
3 1     1   5 use warnings;
  1         2  
  1         62  
4              
5 1     1   693 use Mouse ();
  1         25321  
  1         29  
6 1     1   800 use Data::Dumper ();
  1         8728  
  1         47  
7 1     1   10 use Carp ();
  1         2  
  1         42  
8              
9             our $VERSION = '0.03';
10              
11 1     1   5 use constant DEBUG => $ENV{DEBUG_MOP4IMPORT};
  1         1  
  1         117  
12             BEGIN {
13 1     1   1169 print STDERR "\nUsing ".__PACKAGE__. " = (file '"
14             . __FILE__ . "')\n"
15             if DEBUG;
16             }
17              
18             #
19             # init_meta is called if `-as_base` import pragma is specified.
20             #
21             sub init_meta {
22 1     1 0 3 my ($myPack, %options) = @_;
23              
24             my $for_class = $options{for_class}
25 1 50       4 or Carp::croak "for_class is required!";
26              
27 1         3 my $meta = Mouse->init_meta(for_class => $for_class);
28              
29 1         52 $meta->superclasses($myPack, qw(Mouse::Object));
30             }
31              
32             #
33             # Implement minimum MOP4Import::Declare
34             #
35             sub import {
36 2     2   24 my ($myPack, @decls) = @_;
37              
38 2         9 my $caller = [caller];
39              
40 2 100       15 @decls = $myPack->default_exports($caller) unless @decls;
41              
42 2         9 $myPack->dispatch_declare($caller, $myPack->always_exports($caller), @decls);
43             }
44              
45 1     1 0 2 sub default_exports { () }
46              
47 2     2 0 11 sub always_exports { () }
48              
49             sub dispatch_declare {
50 2     2 0 7 my ($myPack, $opts, @decls) = @_;
51              
52 2         3 print STDERR "$myPack->dispatch_declare("
53             .join(", ", $myPack->cli_encode_dump($opts, @decls)).");\n" if DEBUG;
54              
55 2         23 foreach my $declSpec (@decls) {
56 1 50       3 Carp::croak "Undefined pragma!" unless defined $declSpec;
57              
58 1 50       8 if (not ref $declSpec) {
    0          
59              
60 1         4 $myPack->dispatch_import($opts, $declSpec);
61              
62             }
63             elsif (ref $declSpec eq 'ARRAY') {
64              
65 0         0 $myPack->dispatch_declare_pragma($opts, @$declSpec);
66              
67             }
68             else {
69 0         0 Carp::croak "Invalid pragma: ".$myPack->cli_encode_dump($declSpec);
70             }
71             }
72             }
73              
74             sub dispatch_import {
75 1     1 0 2 my ($myPack, $opts, $declSpec) = @_;
76              
77 1         3 my ($name, $exported);
78              
79 1 50 33     14 if (not ref $declSpec and $declSpec =~ /^-([A-Za-z]\w*)$/) {
80              
81 1         9 $myPack->dispatch_declare_pragma($opts, $1);
82              
83             }
84             else {
85              
86 0         0 $myPack->dispatch_import_symbols($opts, $declSpec);
87             }
88             }
89              
90             sub dispatch_declare_pragma {
91 1     1 0 6 my ($myPack, $opts, $pragma, @rest) = @_;
92              
93 1 50       16 my $sub = $myPack->can("declare_$pragma") or do {
94 0         0 Carp::croak "No such pragma: $pragma at $opts->[1] line $opts->[2]";
95             };
96              
97 1         3 $sub->($myPack, $opts, @rest);
98             }
99              
100             sub declare_as_base {
101 1     1 0 2 my ($myPack, $opts, @rest) = @_;
102              
103 1         1 print STDERR "Class $opts->[0] inherits $myPack\n"
104             if DEBUG;
105              
106 1         7 my $caller = $opts->[0];
107              
108 1         11 Mouse->import(+{
109             into => $caller
110             });
111              
112 1         511 $myPack->init_meta(for_class => $caller, @rest);
113             }
114              
115             sub declare_has {
116 0     0 0   my ($myPack, $opts, $nameSpec, @attrs) = @_;
117              
118 0 0         unless (@attrs % 2 == 0) {
119 0           Carp::croak "Usage: [has 'name' => (key => value, ...)],";
120             }
121              
122 0           my $meta = Mouse::Meta::Class->initialize($opts->[0]);
123              
124 0 0         foreach my $name (ref $nameSpec ? @$nameSpec : $nameSpec) {
125 0           $meta->add_attribute($name, @attrs);
126             }
127              
128 0           $meta;
129             }
130              
131             sub declare_field {
132 0     0 0   my ($myPack, $opts, $nameSpec, @attrs) = @_;
133              
134 0           my $meta = $myPack->has($opts, $nameSpec, @attrs);
135              
136 0   0       my $sym = globref(ref $_[0] || $_[0], 'FIELDS');
137 0 0         unless (*{$sym}{HASH}) {
  0            
138 0           *$sym = {};
139             }
140 0           my $fields = *{$sym}{HASH};
  0            
141              
142 0 0         foreach my $name (ref $nameSpec ? @$nameSpec : $nameSpec) {
143 0           $fields->{$name} = $meta;
144             }
145             }
146              
147             our %SIGIL_MAP = qw(
148             * GLOB
149             $ SCALAR
150             % HASH
151             @ ARRAY
152             & CODE
153             );
154              
155             sub dispatch_import_symbols {
156 0     0 0   my ($myPack, $opts, @declSpec) = @_;
157 0           foreach my $declSpec (@declSpec) {
158 0 0         if ($declSpec =~ /^([\*\$\%\@\&])?([A-Za-z]\w*)$/) {
159 0 0         if ($1) {
160 0           my $kind = $SIGIL_MAP{$1};
161 0           $myPack->import_SIGIL($opts, $1, $kind, $2);
162             } else {
163 0           $myPack->import_NAME($opts => $2);
164             }
165             } else {
166 0           Carp::croak "Invalid import spec: $declSpec";
167             }
168             }
169             }
170              
171             sub import_SIGIL {
172 0     0 0   my ($myPack, $opts, $sigil, $kind, $name) = @_;
173              
174 0           my $exported = *{safe_globref($myPack, $name)}{$kind};
  0            
175              
176 0           print STDERR " Declaring $sigil$opts->[0]::$name"
177             . ", import from $sigil${myPack}::$name"
178             . " (=".terse_dump($exported).")\n" if DEBUG;
179              
180 0           *{globref($opts->[0], $name)} = $exported;
  0            
181             }
182              
183             sub import_NAME {
184 0     0 0   my ($myPack, $opts, $name) = @_;
185              
186 0           my $exported = safe_globref($myPack, $name);
187              
188 0           print STDERR " Declaring $name in $opts->[0] as "
189             .terse_dump($exported)."\n" if DEBUG;
190              
191 0           *{globref($opts->[0], $name)} = $exported;
  0            
192             }
193              
194             sub cli_encode_dump {
195 0     0 0   my ($self, @obj) = @_;
196 0           Data::Dumper->new(\@obj)->Terse(1)->Indent(0)->Dump
197             }
198              
199             #
200             # Stolen from MOP4Import::Util
201             #
202             sub globref {
203 0     0 0   my $pack = shift;
204 0 0         unless (defined $pack) {
205 0           Carp::croak "undef is given to globref()";
206             }
207 0           my $symname = join("::", $pack, @_);
208 1     1   8 no strict 'refs';
  1         4  
  1         168  
209 0           \*{$symname};
  0            
210             }
211              
212             sub symtab {
213 0           *{globref(shift, '')}{HASH}
214 0     0 0   }
215              
216             sub safe_globref {
217 0     0 0   my ($pack_or_obj, $name) = @_;
218 0 0         unless (defined symtab($pack_or_obj)->{$name}) {
219 0   0       my $pack = ref $pack_or_obj || $pack_or_obj;
220 0           Carp::croak "No such symbol '$name' in package $pack";
221             }
222 0           globref($pack_or_obj, $name);
223             }
224              
225             1;