File Coverage

blib/lib/Scalar/Random/PP/OO.pm
Criterion Covered Total %
statement 691 2189 31.5
branch 140 902 15.5
condition 40 398 10.0
subroutine 150 430 34.8
pod 0 230 0.0
total 1021 4149 24.6


line stmt bran cond sub pod time code
1             # This file was generated by Scalar::Random::PP::OO::Maker 0.07 from Mouse 0.70.
2             #
3             # ANY CHANGES MADE HERE WILL BE LOST!
4 2     2   10 use strict;
  2         4  
  2         70  
5 2     2   10 use warnings;
  2         3  
  2         436  
6              
7             # tell Perl we already have all of the Scalar::Random::PP::OO files loaded:
8             BEGIN {
9 2     2   11 $INC{'Scalar/Random/PP/OO.pm'} = __FILE__;
10 2         4 $INC{'Scalar/Random/PP/OO/Exporter.pm'} = __FILE__;
11 2         4 $INC{'Scalar/Random/PP/OO/Object.pm'} = __FILE__;
12 2         4 $INC{'Scalar/Random/PP/OO/PurePerl.pm'} = __FILE__;
13 2         4 $INC{'Scalar/Random/PP/OO/Role.pm'} = __FILE__;
14 2         5 $INC{'Scalar/Random/PP/OO/Util.pm'} = __FILE__;
15 2         3 $INC{'Scalar/Random/PP/OO/Meta/Attribute.pm'} = __FILE__;
16 2         8 $INC{'Scalar/Random/PP/OO/Meta/Class.pm'} = __FILE__;
17 2         4 $INC{'Scalar/Random/PP/OO/Meta/Method.pm'} = __FILE__;
18 2         2 $INC{'Scalar/Random/PP/OO/Meta/Module.pm'} = __FILE__;
19 2         4 $INC{'Scalar/Random/PP/OO/Meta/Role.pm'} = __FILE__;
20 2         4 $INC{'Scalar/Random/PP/OO/Meta/TypeConstraint.pm'} = __FILE__;
21 2         5 $INC{'Scalar/Random/PP/OO/Meta/Method/Accessor.pm'} = __FILE__;
22 2         4 $INC{'Scalar/Random/PP/OO/Meta/Method/Constructor.pm'} = __FILE__;
23 2         5 $INC{'Scalar/Random/PP/OO/Meta/Method/Delegation.pm'} = __FILE__;
24 2         4 $INC{'Scalar/Random/PP/OO/Meta/Method/Destructor.pm'} = __FILE__;
25 2         3 $INC{'Scalar/Random/PP/OO/Meta/Role/Composite.pm'} = __FILE__;
26 2         4 $INC{'Scalar/Random/PP/OO/Meta/Role/Method.pm'} = __FILE__;
27 2         3 $INC{'Scalar/Random/PP/OO/Util/MetaRole.pm'} = __FILE__;
28 2         160 $INC{'Scalar/Random/PP/OO/Util/TypeConstraints.pm'} = __FILE__;
29             }
30              
31             # and now their contents
32              
33             # Contents of Mouse::PurePerl
34             package Scalar::Random::PP::OO::PurePerl;
35             # The pure Perl backend for Mousse
36             package Scalar::Random::PP::OO::Util;
37 2     2   20 use strict;
  2         3  
  2         72  
38 2     2   10 use warnings;
  2         3  
  2         155  
39 2     2   9 use warnings FATAL => 'redefine'; # to avoid to load Scalar::Random::PP::OO::PurePerl twice
  2         4  
  2         88  
40              
41 2     2   9 use B ();
  2         3  
  2         1658  
42              
43             require Scalar::Random::PP::OO::Util;
44              
45              
46             # taken from Class/MOP.pm
47             sub is_valid_class_name {
48 2     2 0 2 my $class = shift;
49              
50 2 50       7 return 0 if ref($class);
51 2 50       5 return 0 unless defined($class);
52              
53 2 50       40 return 1 if $class =~ /\A \w+ (?: :: \w+ )* \z/xms;
54              
55 0         0 return 0;
56             }
57              
58             sub is_class_loaded {
59 2     2 0 4 my $class = shift;
60              
61 2 50 33     20 return 0 if ref($class) || !defined($class) || !length($class);
      33        
62              
63             # walk the symbol table tree to avoid autovififying
64             # \*{${main::}{"Foo::"}{"Bar::"}} == \*main::Foo::Bar::
65              
66 2         4 my $pack = \%::;
67 2         13 foreach my $part (split('::', $class)) {
68 10         11 $part .= '::';
69 10 50       24 return 0 if !exists $pack->{$part};
70              
71 10         13 my $entry = \$pack->{$part};
72 10 50       29 return 0 if ref($entry) ne 'GLOB';
73 10         10 $pack = *{$entry}{HASH};
  10         23  
74             }
75              
76 2 50       6 return 0 if !%{$pack};
  2         16  
77              
78             # check for $VERSION or @ISA
79 0         0 return 1 if exists $pack->{VERSION}
80 2 0 33     12 && defined *{$pack->{VERSION}}{SCALAR} && defined ${ $pack->{VERSION} };
  0   33     0  
81 0         0 return 1 if exists $pack->{ISA}
82 2 0 33     14 && defined *{$pack->{ISA}}{ARRAY} && @{ $pack->{ISA} } != 0;
  0   33     0  
83              
84             # check for any method
85 2         4 foreach my $name( keys %{$pack} ) {
  2         9  
86 2         4 my $entry = \$pack->{$name};
87 2 50 33     10 return 1 if ref($entry) ne 'GLOB' || defined *{$entry}{CODE};
  2         18  
88             }
89              
90             # fail
91 0         0 return 0;
92             }
93              
94              
95             # taken from Sub::Identify
96             sub get_code_info {
97 14     14 0 22 my ($coderef) = @_;
98 14 50       35 ref($coderef) or return;
99              
100 14         75 my $cv = B::svref_2object($coderef);
101 14 50       82 $cv->isa('B::CV') or return;
102              
103 14         42 my $gv = $cv->GV;
104 14 50       59 $gv->isa('B::GV') or return;
105              
106 14         111 return ($gv->STASH->NAME, $gv->NAME);
107             }
108              
109             sub get_code_package{
110 0     0 0 0 my($coderef) = @_;
111              
112 0         0 my $cv = B::svref_2object($coderef);
113 0 0       0 $cv->isa('B::CV') or return '';
114              
115 0         0 my $gv = $cv->GV;
116 0 0       0 $gv->isa('B::GV') or return '';
117              
118 0         0 return $gv->STASH->NAME;
119             }
120              
121             sub get_code_ref{
122 0     0 0 0 my($package, $name) = @_;
123 2     2   19 no strict 'refs';
  2         3  
  2         69  
124 2     2   10 no warnings 'once';
  2         4  
  2         79  
125 2     2   8 use warnings FATAL => 'uninitialized';
  2         3  
  2         756  
126 0         0 return *{$package . '::' . $name}{CODE};
  0         0  
127             }
128              
129             sub generate_isa_predicate_for {
130 2     2 0 4 my($for_class, $name) = @_;
131              
132 2 0   0   12 my $predicate = sub{ Scalar::Util::blessed($_[0]) && $_[0]->isa($for_class) };
  0         0  
133              
134 2 50       8 if(defined $name){
135 0         0 Scalar::Random::PP::OO::Util::install_subroutines(scalar caller, $name => $predicate);
136 0         0 return;
137             }
138              
139 2         10 return $predicate;
140             }
141              
142             sub generate_can_predicate_for {
143 6     6 0 14 my($methods_ref, $name) = @_;
144              
145 6         5 my @methods = @{$methods_ref};
  6         13  
146              
147             my $predicate = sub{
148 4     4   7 my($instance) = @_;
149 4 50       16 if(Scalar::Util::blessed($instance)){
150 0         0 foreach my $method(@methods){
151 0 0       0 if(!$instance->can($method)){
152 0         0 return 0;
153             }
154             }
155 0         0 return 1;
156             }
157 4         30 return 0;
158 6         24 };
159              
160 6 50       15 if(defined $name){
161 6         15 Scalar::Random::PP::OO::Util::install_subroutines(scalar caller, $name => $predicate);
162 6         11 return;
163             }
164              
165 0         0 return $predicate;
166             }
167              
168             package Scalar::Random::PP::OO::Util::TypeConstraints;
169              
170 2     2   12 use Scalar::Util qw(blessed looks_like_number openhandle);
  2         4  
  2         2402  
171              
172 0     0 0 0 sub Any { 1 }
173 0     0 0 0 sub Item { 1 }
174              
175 0 0   0 0 0 sub Bool { $_[0] ? $_[0] eq '1' : 1 }
176 0     0 0 0 sub Undef { !defined($_[0]) }
177 0     0 0 0 sub Defined { defined($_[0]) }
178 0 0   0 0 0 sub Value { defined($_[0]) && !ref($_[0]) }
179 0     0 0 0 sub Num { looks_like_number($_[0]) }
180             sub Int {
181 0     0 0 0 my($value) = @_;
182 0 0       0 looks_like_number($value) && $value =~ /\A [+-]? [0-9]+ \z/xms;
183             }
184             sub Str {
185 0     0 0 0 my($value) = @_;
186 0   0     0 return defined($value) && ref(\$value) eq 'SCALAR';
187             }
188              
189 0     0 0 0 sub Ref { ref($_[0]) }
190             sub ScalarRef {
191 0     0 0 0 my($value) = @_;
192 0         0 return ref($value) eq 'SCALAR'
193             }
194 0     0 0 0 sub ArrayRef { ref($_[0]) eq 'ARRAY' }
195 0     0 0 0 sub HashRef { ref($_[0]) eq 'HASH' }
196 0     0 0 0 sub CodeRef { ref($_[0]) eq 'CODE' }
197 0     0 0 0 sub RegexpRef { ref($_[0]) eq 'Regexp' }
198 0     0 0 0 sub GlobRef { ref($_[0]) eq 'GLOB' }
199              
200             sub FileHandle {
201 0   0 0 0 0 return openhandle($_[0]) || (blessed($_[0]) && $_[0]->isa("IO::Handle"))
202             }
203              
204 0 0   0 0 0 sub Object { blessed($_[0]) && blessed($_[0]) ne 'Regexp' }
205              
206 0     0 0 0 sub ClassName { Scalar::Random::PP::OO::Util::is_class_loaded($_[0]) }
207 0   0 0 0 0 sub RoleName { (Scalar::Random::PP::OO::Util::class_of($_[0]) || return 0)->isa('Scalar::Random::PP::OO::Meta::Role') }
208              
209             sub _parameterize_ArrayRef_for {
210 0     0   0 my($type_parameter) = @_;
211 0         0 my $check = $type_parameter->_compiled_type_constraint;
212              
213             return sub {
214 0     0   0 foreach my $value (@{$_}) {
  0         0  
215 0 0       0 return undef unless $check->($value);
216             }
217 0         0 return 1;
218             }
219 0         0 }
220              
221             sub _parameterize_HashRef_for {
222 0     0   0 my($type_parameter) = @_;
223 0         0 my $check = $type_parameter->_compiled_type_constraint;
224              
225             return sub {
226 0     0   0 foreach my $value(values %{$_}){
  0         0  
227 0 0       0 return undef unless $check->($value);
228             }
229 0         0 return 1;
230 0         0 };
231             }
232              
233             # 'Maybe' type accepts 'Any', so it requires parameters
234             sub _parameterize_Maybe_for {
235 0     0   0 my($type_parameter) = @_;
236 0         0 my $check = $type_parameter->_compiled_type_constraint;
237              
238             return sub{
239 0   0 0   0 return !defined($_) || $check->($_);
240 0         0 };
241             }
242              
243             package Scalar::Random::PP::OO::Meta::Module;
244              
245 10     10 0 56 sub name { $_[0]->{package} }
246              
247 0     0   0 sub _method_map { $_[0]->{methods} }
248 0     0   0 sub _attribute_map{ $_[0]->{attributes} }
249              
250             sub namespace{
251 0     0 0 0 my $name = $_[0]->{package};
252 2     2   14 no strict 'refs';
  2         3  
  2         347  
253 0         0 return \%{ $name . '::' };
  0         0  
254             }
255              
256             sub add_method {
257 4     4 0 10 my($self, $name, $code) = @_;
258              
259 4 50       10 if(!defined $name){
260 0         0 $self->throw_error('You must pass a defined name');
261             }
262 4 50       10 if(!defined $code){
263 0         0 $self->throw_error('You must pass a defined code');
264             }
265              
266 4 50       13 if(ref($code) ne 'CODE'){
267 0         0 $code = \&{$code}; # coerce
  0         0  
268             }
269              
270 4         12 $self->{methods}->{$name} = $code; # Moose stores meta object here.
271              
272 4         20 Scalar::Random::PP::OO::Util::install_subroutines($self->name,
273             $name => $code,
274             );
275 4         8 return;
276             }
277              
278             package Scalar::Random::PP::OO::Meta::Class;
279              
280 2     2   10 use Scalar::Random::PP::OO::Meta::Method::Constructor;
  2         2  
  2         44  
281 2     2   9 use Scalar::Random::PP::OO::Meta::Method::Destructor;
  2         3  
  2         6958  
282              
283 0 0   0 0 0 sub method_metaclass { $_[0]->{method_metaclass} || 'Scalar::Random::PP::OO::Meta::Method' }
284 2 50   2 0 25 sub attribute_metaclass { $_[0]->{attribute_metaclass} || 'Scalar::Random::PP::OO::Meta::Attribute' }
285              
286 0 0   0 0 0 sub constructor_class { $_[0]->{constructor_class} || 'Scalar::Random::PP::OO::Meta::Method::Constructor' }
287 0 0   0 0 0 sub destructor_class { $_[0]->{destructor_class} || 'Scalar::Random::PP::OO::Meta::Method::Destructor' }
288              
289             sub is_anon_class{
290 4     4 0 35 return exists $_[0]->{anon_serial_id};
291             }
292              
293 0     0 0 0 sub roles { $_[0]->{roles} }
294              
295 4     4 0 8 sub linearized_isa { @{ get_linear_isa($_[0]->{package}) } }
  4         57  
296              
297             sub get_all_attributes {
298 4     4 0 8 my($self) = @_;
299 4         21 my %attrs = map { %{ $self->initialize($_)->{attributes} } } reverse $self->linearized_isa;
  8         12  
  8         19  
300 4         24 return values %attrs;
301             }
302              
303             sub new_object {
304 4     4 0 9 my $meta = shift;
305 4 50       27 my %args = (@_ == 1 ? %{$_[0]} : @_);
  4         26  
306              
307 4         28 my $object = bless {}, $meta->name;
308              
309 4         26 $meta->_initialize_object($object, \%args);
310             # BUILDALL
311 4 50       44 if( $object->can('BUILD') ) {
312 0         0 for my $class (reverse $meta->linearized_isa) {
313 0   0     0 my $build = Scalar::Random::PP::OO::Util::get_code_ref($class, 'BUILD')
314             || next;
315              
316 0         0 $object->$build(\%args);
317             }
318             }
319 4         24 return $object;
320             }
321              
322             sub clone_object {
323 0     0 0 0 my $class = shift;
324 0         0 my $object = shift;
325 0         0 my $args = $object->Scalar::Random::PP::OO::Object::BUILDARGS(@_);
326              
327 0 0 0     0 (blessed($object) && $object->isa($class->name))
328             || $class->throw_error("You must pass an instance of the metaclass (" . $class->name . "), not ($object)");
329              
330 0         0 my $cloned = bless { %$object }, ref $object;
331 0         0 $class->_initialize_object($cloned, $args, 1);
332              
333 0         0 return $cloned;
334             }
335              
336             sub _initialize_object{
337 4     4   9 my($self, $object, $args, $is_cloning) = @_;
338              
339 4         8 my @triggers_queue;
340              
341 4         11 my $used = 0;
342              
343 4         21 foreach my $attribute ($self->get_all_attributes) {
344 4         20 my $init_arg = $attribute->init_arg;
345 4         17 my $slot = $attribute->name;
346              
347 4 50 33     34 if (defined($init_arg) && exists($args->{$init_arg})) {
348 4         24 $object->{$slot} = $attribute->_coerce_and_verify($args->{$init_arg}, $object);
349              
350 4 50 33     23 weaken($object->{$slot})
351             if ref($object->{$slot}) && $attribute->is_weak_ref;
352              
353 4 50       20 if ($attribute->has_trigger) {
354 0         0 push @triggers_queue, [ $attribute->trigger, $object->{$slot} ];
355             }
356 4         15 $used++;
357             }
358             else { # no init arg
359 0 0 0     0 if ($attribute->has_default || $attribute->has_builder) {
    0 0        
360 0 0 0     0 if (!$attribute->is_lazy && !exists $object->{$slot}) {
361 0         0 my $default = $attribute->default;
362 0         0 my $builder = $attribute->builder;
363 0 0       0 my $value = $builder ? $object->$builder()
    0          
364             : ref($default) eq 'CODE' ? $object->$default()
365             : $default;
366              
367 0         0 $object->{$slot} = $attribute->_coerce_and_verify($value, $object);
368              
369 0 0 0     0 weaken($object->{$slot})
370             if ref($object->{$slot}) && $attribute->is_weak_ref;
371             }
372             }
373             elsif(!$is_cloning && $attribute->is_required) {
374 0         0 $self->throw_error("Attribute (".$attribute->name.") is required");
375             }
376             }
377             }
378              
379 4 50 33     12 if($used < keys %{$args} && $self->strict_constructor) {
  4         23  
380 0         0 $self->_report_unknown_args([ $self->get_all_attributes ], $args);
381             }
382              
383 4 50       15 if(@triggers_queue){
384 0         0 foreach my $trigger_and_value(@triggers_queue){
385 0         0 my($trigger, $value) = @{$trigger_and_value};
  0         0  
386 0         0 $trigger->($object, $value);
387             }
388             }
389              
390 4 50       16 if($self->is_anon_class){
391 0         0 $object->{__METACLASS__} = $self;
392             }
393              
394 4         12 return;
395             }
396              
397 0     0 0 0 sub is_immutable { $_[0]->{is_immutable} }
398              
399             sub strict_constructor{
400 0     0 0 0 my $self = shift;
401 0 0       0 if(@_) {
402 0         0 $self->{strict_constructor} = shift;
403             }
404              
405 0         0 foreach my $class($self->linearized_isa) {
406 0 0       0 my $meta = Scalar::Random::PP::OO::Util::get_metaclass_by_name($class)
407             or next;
408              
409 0 0       0 if(exists $meta->{strict_constructor}) {
410 0         0 return $meta->{strict_constructor};
411             }
412             }
413              
414 0         0 return 0; # false
415             }
416              
417             sub _report_unknown_args {
418 0     0   0 my($metaclass, $attrs, $args) = @_;
419              
420 0         0 my @unknowns;
421             my %init_args;
422 0         0 foreach my $attr(@{$attrs}){
  0         0  
423 0         0 my $init_arg = $attr->init_arg;
424 0 0       0 if(defined $init_arg){
425 0         0 $init_args{$init_arg}++;
426             }
427             }
428              
429 0         0 while(my $key = each %{$args}){
  0         0  
430 0 0       0 if(!exists $init_args{$key}){
431 0         0 push @unknowns, $key;
432             }
433             }
434              
435 0         0 $metaclass->throw_error( sprintf
436             "Unknown attribute passed to the constructor of %s: %s",
437             $metaclass->name, Scalar::Random::PP::OO::Util::english_list(@unknowns),
438             );
439             }
440              
441             package Scalar::Random::PP::OO::Meta::Role;
442              
443 0 0   0 0 0 sub method_metaclass{ $_[0]->{method_metaclass} || 'Scalar::Random::PP::OO::Meta::Role::Method' }
444              
445             sub is_anon_role{
446 0     0 0 0 return exists $_[0]->{anon_serial_id};
447             }
448              
449 0     0 0 0 sub get_roles { $_[0]->{roles} }
450              
451             sub add_before_method_modifier {
452 0     0 0 0 my ($self, $method_name, $method) = @_;
453              
454 0   0     0 push @{ $self->{before_method_modifiers}{$method_name} ||= [] }, $method;
  0         0  
455 0         0 return;
456             }
457             sub add_around_method_modifier {
458 0     0 0 0 my ($self, $method_name, $method) = @_;
459              
460 0   0     0 push @{ $self->{around_method_modifiers}{$method_name} ||= [] }, $method;
  0         0  
461 0         0 return;
462             }
463             sub add_after_method_modifier {
464 0     0 0 0 my ($self, $method_name, $method) = @_;
465              
466 0   0     0 push @{ $self->{after_method_modifiers}{$method_name} ||= [] }, $method;
  0         0  
467 0         0 return;
468             }
469              
470             sub get_before_method_modifiers {
471 0     0 0 0 my ($self, $method_name) = @_;
472 0   0     0 return @{ $self->{before_method_modifiers}{$method_name} ||= [] }
  0         0  
473             }
474             sub get_around_method_modifiers {
475 0     0 0 0 my ($self, $method_name) = @_;
476 0   0     0 return @{ $self->{around_method_modifiers}{$method_name} ||= [] }
  0         0  
477             }
478             sub get_after_method_modifiers {
479 0     0 0 0 my ($self, $method_name) = @_;
480 0   0     0 return @{ $self->{after_method_modifiers}{$method_name} ||= [] }
  0         0  
481             }
482              
483             package Scalar::Random::PP::OO::Meta::Attribute;
484              
485             require Scalar::Random::PP::OO::Meta::Method::Accessor;
486              
487 2 50   2 0 20 sub accessor_metaclass{ $_[0]->{accessor_metaclass} || 'Scalar::Random::PP::OO::Meta::Method::Accessor' }
488              
489             # readers
490              
491 8     8 0 24 sub name { $_[0]->{name} }
492 2     2 0 5 sub associated_class { $_[0]->{associated_class} }
493              
494 0     0 0 0 sub accessor { $_[0]->{accessor} }
495 0     0 0 0 sub reader { $_[0]->{reader} }
496 0     0 0 0 sub writer { $_[0]->{writer} }
497 0     0 0 0 sub predicate { $_[0]->{predicate} }
498 0     0 0 0 sub clearer { $_[0]->{clearer} }
499 0     0 0 0 sub handles { $_[0]->{handles} }
500              
501 0     0   0 sub _is_metadata { $_[0]->{is} }
502 0     0 0 0 sub is_required { $_[0]->{required} }
503 2     2 0 6 sub default { $_[0]->{default} }
504 2     2 0 11 sub is_lazy { $_[0]->{lazy} }
505 0     0 0 0 sub is_lazy_build { $_[0]->{lazy_build} }
506 2     2 0 6 sub is_weak_ref { $_[0]->{weak_ref} }
507 4     4 0 25 sub init_arg { $_[0]->{init_arg} }
508 2     2 0 5 sub type_constraint { $_[0]->{type_constraint} }
509              
510 2     2 0 4 sub trigger { $_[0]->{trigger} }
511 2     2 0 5 sub builder { $_[0]->{builder} }
512 2     2 0 6 sub should_auto_deref { $_[0]->{auto_deref} }
513 0     0 0 0 sub should_coerce { $_[0]->{coerce} }
514              
515 0     0 0 0 sub documentation { $_[0]->{documentation} }
516 0     0 0 0 sub insertion_order { $_[0]->{insertion_order} }
517              
518             # predicates
519              
520 0     0 0 0 sub has_accessor { exists $_[0]->{accessor} }
521 0     0 0 0 sub has_reader { exists $_[0]->{reader} }
522 0     0 0 0 sub has_writer { exists $_[0]->{writer} }
523 0     0 0 0 sub has_predicate { exists $_[0]->{predicate} }
524 0     0 0 0 sub has_clearer { exists $_[0]->{clearer} }
525 0     0 0 0 sub has_handles { exists $_[0]->{handles} }
526              
527 0     0 0 0 sub has_default { exists $_[0]->{default} }
528 0     0 0 0 sub has_type_constraint { exists $_[0]->{type_constraint} }
529 4     4 0 21 sub has_trigger { exists $_[0]->{trigger} }
530 0     0 0 0 sub has_builder { exists $_[0]->{builder} }
531              
532 0     0 0 0 sub has_documentation { exists $_[0]->{documentation} }
533              
534             sub _process_options{
535 2     2   5 my($class, $name, $args) = @_;
536              
537             # taken from Class::MOP::Attribute::new
538              
539 2 50       7 defined($name)
540             or $class->throw_error('You must provide a name for the attribute');
541              
542 2 50       9 if(!exists $args->{init_arg}){
543 2         10 $args->{init_arg} = $name;
544             }
545              
546             # 'required' requires eigher 'init_arg', 'builder', or 'default'
547 2         5 my $can_be_required = defined( $args->{init_arg} );
548              
549 2 50       13 if(exists $args->{builder}){
    50          
550             # XXX:
551             # Moose refuses a CODE ref builder, but Scalar::Random::PP::OO doesn't for backward compatibility
552             # This feature will be changed in a future. (gfx)
553 0 0       0 $class->throw_error('builder must be a defined scalar value which is a method name')
554             #if ref $args->{builder} || !defined $args->{builder};
555             if !defined $args->{builder};
556              
557 0         0 $can_be_required++;
558             }
559             elsif(exists $args->{default}){
560 0 0 0     0 if(ref $args->{default} && ref($args->{default}) ne 'CODE'){
561 0         0 $class->throw_error("References are not allowed as default values, you must "
562             . "wrap the default of '$name' in a CODE reference (ex: sub { [] } and not [])");
563             }
564 0         0 $can_be_required++;
565             }
566              
567 2 50 33     9 if( $args->{required} && !$can_be_required ) {
568 0         0 $class->throw_error("You cannot have a required attribute ($name) without a default, builder, or an init_arg");
569             }
570              
571             # taken from Scalar::Random::PP::OO::Meta::Attribute->new and ->_process_args
572              
573 2 50       8 if(exists $args->{is}){
574 2         4 my $is = $args->{is};
575              
576 2 50       7 if($is eq 'ro'){
    0          
    0          
577 2   33     15 $args->{reader} ||= $name;
578             }
579             elsif($is eq 'rw'){
580 0 0       0 if(exists $args->{writer}){
581 0   0     0 $args->{reader} ||= $name;
582             }
583             else{
584 0   0     0 $args->{accessor} ||= $name;
585             }
586             }
587             elsif($is eq 'bare'){
588             # do nothing, but don't complain (later) about missing methods
589             }
590             else{
591 0 0       0 $is = 'undef' if !defined $is;
592 0         0 $class->throw_error("I do not understand this option (is => $is) on attribute ($name)");
593             }
594             }
595              
596 2         4 my $tc;
597 2 50       8 if(exists $args->{isa}){
598 0         0 $tc = $args->{type_constraint} = Scalar::Random::PP::OO::Util::TypeConstraints::find_or_create_isa_type_constraint($args->{isa});
599             }
600              
601 2 50       7 if(exists $args->{does}){
602 0 0       0 if(defined $tc){ # both isa and does supplied
603 0         0 my $does_ok = do{
604 0         0 local $@;
605 0         0 eval{ "$tc"->does($args) };
  0         0  
606             };
607 0 0       0 if(!$does_ok){
608 0         0 $class->throw_error("Cannot have both an isa option and a does option because '$tc' does not do '$args->{does}' on attribute ($name)");
609             }
610             }
611             else {
612 0         0 $tc = $args->{type_constraint} = Scalar::Random::PP::OO::Util::TypeConstraints::find_or_create_does_type_constraint($args->{does});
613             }
614             }
615              
616 2 50       7 if($args->{coerce}){
617 0 0       0 defined($tc)
618             || $class->throw_error("You cannot have coercion without specifying a type constraint on attribute ($name)");
619              
620 0 0       0 $args->{weak_ref}
621             && $class->throw_error("You cannot have a weak reference to a coerced value on attribute ($name)");
622             }
623              
624 2 50       7 if ($args->{lazy_build}) {
625 0 0       0 exists($args->{default})
626             && $class->throw_error("You can not use lazy_build and default for the same attribute ($name)");
627              
628 0         0 $args->{lazy} = 1;
629 0   0     0 $args->{builder} ||= "_build_${name}";
630 0 0       0 if ($name =~ /^_/) {
631 0   0     0 $args->{clearer} ||= "_clear${name}";
632 0   0     0 $args->{predicate} ||= "_has${name}";
633             }
634             else {
635 0   0     0 $args->{clearer} ||= "clear_${name}";
636 0   0     0 $args->{predicate} ||= "has_${name}";
637             }
638             }
639              
640 2 50       7 if ($args->{auto_deref}) {
641 0 0       0 defined($tc)
642             || $class->throw_error("You cannot auto-dereference without specifying a type constraint on attribute ($name)");
643              
644 0 0 0     0 ( $tc->is_a_type_of('ArrayRef') || $tc->is_a_type_of('HashRef') )
645             || $class->throw_error("You cannot auto-dereference anything other than a ArrayRef or HashRef on attribute ($name)");
646             }
647              
648 2 50       7 if (exists $args->{trigger}) {
649 0 0       0 ('CODE' eq ref $args->{trigger})
650             || $class->throw_error("Trigger must be a CODE ref on attribute ($name)");
651             }
652              
653 2 50       6 if ($args->{lazy}) {
654 0 0 0     0 (exists $args->{default} || defined $args->{builder})
655             || $class->throw_error("You cannot have lazy attribute ($name) without specifying a default value for it");
656             }
657              
658 2         4 return;
659             }
660              
661              
662             package Scalar::Random::PP::OO::Meta::TypeConstraint;
663              
664 0     0 0 0 sub name { $_[0]->{name} }
665 0     0 0 0 sub parent { $_[0]->{parent} }
666 0     0 0 0 sub message { $_[0]->{message} }
667              
668 0     0 0 0 sub type_parameter { $_[0]->{type_parameter} }
669 0     0   0 sub _compiled_type_constraint{ $_[0]->{compiled_type_constraint} }
670 0     0   0 sub _compiled_type_coercion { $_[0]->{_compiled_type_coercion} }
671              
672 0     0   0 sub __is_parameterized { exists $_[0]->{type_parameter} }
673 0     0 0 0 sub has_coercion { exists $_[0]->{_compiled_type_coercion} }
674              
675              
676             sub compile_type_constraint{
677 6     6 0 9 my($self) = @_;
678              
679             # add parents first
680 6         6 my @checks;
681 6         17 for(my $parent = $self->{parent}; defined $parent; $parent = $parent->{parent}){
682 6 50       38 if($parent->{hand_optimized_type_constraint}){
    50          
683 0         0 unshift @checks, $parent->{hand_optimized_type_constraint};
684 0         0 last; # a hand optimized constraint must include all the parents
685             }
686             elsif($parent->{constraint}){
687 0         0 unshift @checks, $parent->{constraint};
688             }
689             }
690              
691             # then add child
692 6 50       49 if($self->{constraint}){
693 0         0 push @checks, $self->{constraint};
694             }
695              
696 6 50       14 if($self->{type_constraints}){ # Union
697 0         0 my @types = map{ $_->{compiled_type_constraint} } @{ $self->{type_constraints} };
  0         0  
  0         0  
698             push @checks, sub{
699 0     0   0 foreach my $c(@types){
700 0 0       0 return 1 if $c->($_[0]);
701             }
702 0         0 return 0;
703 0         0 };
704             }
705              
706 6 50       12 if(@checks == 0){
707 6         13 $self->{compiled_type_constraint} = \&Scalar::Random::PP::OO::Util::TypeConstraints::Any;
708             }
709             else{
710             $self->{compiled_type_constraint} = sub{
711 0     0   0 my(@args) = @_;
712 0         0 local $_ = $args[0];
713 0         0 foreach my $c(@checks){
714 0 0       0 return undef if !$c->(@args);
715             }
716 0         0 return 1;
717 0         0 };
718             }
719 6         10 return;
720             }
721              
722             sub check {
723 0     0 0 0 my $self = shift;
724 0         0 return $self->_compiled_type_constraint->(@_);
725             }
726              
727              
728             package Scalar::Random::PP::OO::Object;
729              
730             sub BUILDARGS {
731 6     6 0 18 my $class = shift;
732              
733 6 50       26 if (scalar @_ == 1) {
734 0 0       0 (ref($_[0]) eq 'HASH')
735             || $class->meta->throw_error("Single parameters to new() must be a HASH ref");
736              
737 0         0 return {%{$_[0]}};
  0         0  
738             }
739             else {
740 6         21 return {@_};
741             }
742             }
743              
744             sub new {
745 4     4 0 12 my $class = shift;
746              
747 4 50       17 $class->meta->throw_error('Cannot call new() on an instance') if ref $class;
748              
749 4         30 my $args = $class->BUILDARGS(@_);
750              
751 4         42 my $meta = Scalar::Random::PP::OO::Meta::Class->initialize($class);
752 4         25 return $meta->new_object($args);
753             }
754              
755             sub DESTROY {
756 4     4   1281 my $self = shift;
757              
758 4 50       284 return unless $self->can('DEMOLISH'); # short circuit
759              
760 0         0 local $?;
761              
762 0         0 my $e = do{
763 0         0 local $@;
764 0         0 eval{
765             # DEMOLISHALL
766              
767             # We cannot count on being able to retrieve a previously made
768             # metaclass, _or_ being able to make a new one during global
769             # destruction. However, we should still be able to use mro at
770             # that time (at least tests suggest so ;)
771              
772 0         0 foreach my $class (@{ Scalar::Random::PP::OO::Util::get_linear_isa(ref $self) }) {
  0         0  
773 0   0     0 my $demolish = Scalar::Random::PP::OO::Util::get_code_ref($class, 'DEMOLISH')
774             || next;
775              
776 0         0 $self->$demolish($Scalar::Random::PP::OO::Util::in_global_destruction);
777             }
778             };
779 0         0 $@;
780             };
781              
782 2     2   12 no warnings 'misc';
  2         3  
  2         344  
783 0 0       0 die $e if $e; # rethrow
784             }
785              
786             sub BUILDALL {
787 0     0 0 0 my $self = shift;
788              
789             # short circuit
790 0 0       0 return unless $self->can('BUILD');
791              
792 0         0 for my $class (reverse $self->meta->linearized_isa) {
793 0   0     0 my $build = Scalar::Random::PP::OO::Util::get_code_ref($class, 'BUILD')
794             || next;
795              
796 0         0 $self->$build(@_);
797             }
798 0         0 return;
799             }
800              
801             sub DEMOLISHALL;
802             *DEMOLISHALL = \&DESTROY;
803              
804             # Contents of Mouse::Exporter
805             package Scalar::Random::PP::OO::Exporter;
806 2     2   11 use strict;
  2         3  
  2         66  
807 2     2   8 use warnings;
  2         3  
  2         54  
808              
809 2     2   8 use Carp ();
  2         4  
  2         68  
810              
811             my %SPEC;
812              
813             my $strict_bits;
814 2     2   83 BEGIN{ $strict_bits = strict::bits(qw(subs refs vars)); }
815              
816             my $warnings_extra_bits;
817 2     2   984 BEGIN{ $warnings_extra_bits = warnings::bits(FATAL => 'recursion') }
818              
819             # it must be "require", because Scalar::Random::PP::OO::Util depends on Scalar::Random::PP::OO::Exporter,
820             # which depends on Scalar::Random::PP::OO::Util::import()
821             require Scalar::Random::PP::OO::Util;
822              
823             sub import{
824             # strict->import;
825 8     8   22 $^H |= $strict_bits;
826             # warnings->import('all', FATAL => 'recursion');
827 8         28 ${^WARNING_BITS} |= $warnings::Bits{all};
828 8         15 ${^WARNING_BITS} |= $warnings_extra_bits;
829 8         7081 return;
830             }
831              
832              
833             sub setup_import_methods{
834 12     12 0 39 my($class, %args) = @_;
835              
836 12   33     68 my $exporting_package = $args{exporting_package} ||= caller();
837              
838 12         46 my($import, $unimport) = $class->build_import_methods(%args);
839              
840             Scalar::Random::PP::OO::Util::install_subroutines($exporting_package,
841             import => $import,
842             unimport => $unimport,
843              
844             export_to_level => sub {
845 0     0   0 my($package, $level, undef, @args) = @_; # the third argument is redundant
846 0         0 $package->import({ into_level => $level + 1 }, @args);
847             },
848             export => sub {
849 0     0   0 my($package, $into, @args) = @_;
850 0         0 $package->import({ into => $into }, @args);
851             },
852 12         88 );
853 12         31 return;
854             }
855              
856             sub build_import_methods{
857 12     12 0 49 my($self, %args) = @_;
858              
859 12   33     38 my $exporting_package = $args{exporting_package} ||= caller();
860              
861 12         20 $SPEC{$exporting_package} = \%args;
862              
863             # canonicalize args
864 12         12 my @export_from;
865 12 100       28 if($args{also}){
866 2         4 my %seen;
867 2         5 my @stack = ($exporting_package);
868              
869 2         8 while(my $current = shift @stack){
870 4         6 push @export_from, $current;
871              
872 4 100       20 my $also = $SPEC{$current}{also} or next;
873 2 50       11 push @stack, grep{ !$seen{$_}++ } ref($also) ? @{ $also } : $also;
  2         15  
  0         0  
874             }
875             }
876             else{
877 10         19 @export_from = ($exporting_package);
878             }
879              
880 12         16 my %exports;
881             my @removables;
882 0         0 my @all;
883              
884 0         0 my @init_meta_methods;
885              
886 12         22 foreach my $package(@export_from){
887 14 50       39 my $spec = $SPEC{$package} or next;
888              
889 14 100       34 if(my $as_is = $spec->{as_is}){
890 12         14 foreach my $thingy (@{$as_is}){
  12         20  
891 138         131 my($code_package, $code_name, $code);
892              
893 138 100       219 if(ref($thingy)){
894 14         13 $code = $thingy;
895 14         30 ($code_package, $code_name) = Scalar::Random::PP::OO::Util::get_code_info($code);
896             }
897             else{
898 124         121 $code_package = $package;
899 124         118 $code_name = $thingy;
900 2     2   10 no strict 'refs';
  2         4  
  2         1874  
901 124         120 $code = \&{ $code_package . '::' . $code_name };
  124         443  
902             }
903              
904 138         239 push @all, $code_name;
905 138         199 $exports{$code_name} = $code;
906 138 100       251 if($code_package eq $package){
907 126         210 push @removables, $code_name;
908             }
909             }
910             }
911              
912 14 100       195 if(my $init_meta = $package->can('init_meta')){
913 6 50       17 if(!grep{ $_ == $init_meta } @init_meta_methods){
  0         0  
914 6         14 push @init_meta_methods, $init_meta;
915             }
916             }
917             }
918 12         55 $args{EXPORTS} = \%exports;
919 12         27 $args{REMOVABLES} = \@removables;
920              
921 12   50     60 $args{groups}{all} ||= \@all;
922              
923 12 100       34 if(my $default_list = $args{groups}{default}){
924 2         3 my %default;
925 2         2 foreach my $keyword(@{$default_list}){
  2         5  
926 0   0     0 $default{$keyword} = $exports{$keyword}
927             || Carp::confess(qq{The $exporting_package package does not export "$keyword"});
928             }
929 2         4 $args{DEFAULT} = \%default;
930             }
931             else{
932 10   50     46 $args{groups}{default} ||= \@all;
933 10         18 $args{DEFAULT} = $args{EXPORTS};
934             }
935              
936 12 100       29 if(@init_meta_methods){
937 6         11 $args{INIT_META} = \@init_meta_methods;
938             }
939              
940 12         45 return (\&do_import, \&do_unimport);
941             }
942              
943              
944             # the entity of general import()
945             sub do_import {
946 36     36 0 103 my($package, @args) = @_;
947              
948 36   33     119 my $spec = $SPEC{$package}
949             || Carp::confess("The package $package package does not use Scalar::Random::PP::OO::Exporter");
950              
951 36 50       114 my $into = _get_caller_package(ref($args[0]) ? shift @args : undef);
952              
953 36         49 my @exports;
954             my @traits;
955              
956 36         86 while(@args){
957 46         58 my $arg = shift @args;
958 46 50       213 if($arg =~ s/^-//){
    100          
959 0 0       0 if($arg eq 'traits'){
960 0 0       0 push @traits, ref($args[0]) ? @{shift(@args)} : shift(@args);
  0         0  
961             }
962             else {
963 0         0 Scalar::Random::PP::OO::Util::not_supported("-$arg");
964             }
965             }
966             elsif($arg =~ s/^://){
967 20   33     64 my $group = $spec->{groups}{$arg}
968             || Carp::confess(qq{The $package package does not export the group "$arg"});
969 20         25 push @exports, @{$group};
  20         87  
970             }
971             else{
972 26         63 push @exports, $arg;
973             }
974             }
975              
976             # strict->import;
977 36         83 $^H |= $strict_bits;
978             # warnings->import('all', FATAL => 'recursion');
979 36         102 ${^WARNING_BITS} |= $warnings::Bits{all};
980 36         73 ${^WARNING_BITS} |= $warnings_extra_bits;
981              
982 36 100       111 if($spec->{INIT_META}){
    50          
983 2         4 my $meta;
984 2         3 foreach my $init_meta(@{$spec->{INIT_META}}){
  2         7  
985 2         10 $meta = $package->$init_meta(for_class => $into);
986             }
987              
988 2 50       10 if(@traits){
989 0         0 my $type = (split /::/, ref $meta)[-1]; # e.g. "Class" for "My::Meta::Class"
990 0 0       0 @traits =
991             map{
992 0         0 ref($_) ? $_
993             : Scalar::Random::PP::OO::Util::resolve_metaclass_alias($type => $_, trait => 1)
994             } @traits;
995              
996 0         0 require Scalar::Random::PP::OO::Util::MetaRole;
997 0 0       0 Scalar::Random::PP::OO::Util::MetaRole::apply_metaroles(
998             for => $into,
999             Scalar::Random::PP::OO::Util::is_a_metarole($into->meta)
1000             ? (role_metaroles => { role => \@traits })
1001             : (class_metaroles => { class => \@traits }),
1002             );
1003             }
1004             }
1005             elsif(@traits){
1006 0         0 Carp::confess("Cannot provide traits when $package does not have an init_meta() method");
1007             }
1008              
1009 36 100       61 if(@exports){
1010 28         28 my @export_table;
1011 28         47 foreach my $keyword(@exports){
1012 86   33     311 push @export_table,
1013             $keyword => ($spec->{EXPORTS}{$keyword}
1014             || Carp::confess(qq{The $package package does not export "$keyword"})
1015             );
1016             }
1017 28         73 Scalar::Random::PP::OO::Util::install_subroutines($into, @export_table);
1018             }
1019             else{
1020 8         10 Scalar::Random::PP::OO::Util::install_subroutines($into, %{$spec->{DEFAULT}});
  8         32  
1021             }
1022 36         7997 return;
1023             }
1024              
1025             # the entity of general unimport()
1026             sub do_unimport {
1027 0     0 0 0 my($package, $arg) = @_;
1028              
1029 0   0     0 my $spec = $SPEC{$package}
1030             || Carp::confess("The package $package does not use Scalar::Random::PP::OO::Exporter");
1031              
1032 0         0 my $from = _get_caller_package($arg);
1033              
1034 0         0 my $stash = do{
1035 2     2   17 no strict 'refs';
  2         2  
  2         393  
1036 0         0 \%{$from . '::'}
  0         0  
1037             };
1038              
1039 0         0 for my $keyword (@{ $spec->{REMOVABLES} }) {
  0         0  
1040 0 0       0 next if !exists $stash->{$keyword};
1041 0         0 my $gv = \$stash->{$keyword};
1042 0 0 0     0 if(ref($gv) eq 'GLOB' && *{$gv}{CODE} == $spec->{EXPORTS}{$keyword}){ # make sure it is from us
  0         0  
1043 0         0 delete $stash->{$keyword};
1044             }
1045             }
1046 0         0 return;
1047             }
1048              
1049             sub _get_caller_package {
1050 36     36   45 my($arg) = @_;
1051              
1052             # We need one extra level because it's called by import so there's a layer
1053             # of indirection
1054 36 50       58 if(ref $arg){
1055 0 0       0 return defined($arg->{into}) ? $arg->{into}
    0          
1056             : defined($arg->{into_level}) ? scalar caller(1 + $arg->{into_level})
1057             : scalar caller(1);
1058             }
1059             else{
1060 36         106 return scalar caller(1);
1061             }
1062             }
1063              
1064             #sub _spec{ %SPEC }
1065              
1066             # Contents of Mouse::Util
1067             package Scalar::Random::PP::OO::Util;
1068 2     2   10 use Scalar::Random::PP::OO::Exporter; # enables strict and warnings
  2         4  
  2         12  
1069 2     2   9 no warnings 'once';
  2         2  
  2         173  
1070              
1071             # must be here because it will be refered by other modules loaded
1072             sub get_linear_isa($;$); ## no critic
1073              
1074             # must be here because it will called in Scalar::Random::PP::OO::Exporter
1075             sub install_subroutines {
1076 58     58 0 76 my $into = shift;
1077              
1078 58         194 while(my($name, $code) = splice @_, 0, 2){
1079 2     2   9 no strict 'refs';
  2         19  
  2         59  
1080 2     2   10 no warnings 'once', 'redefine';
  2         2  
  2         65  
1081 2     2   7 use warnings FATAL => 'uninitialized';
  2         3  
  2         581  
1082 168         158 *{$into . '::' . $name} = \&{$code};
  168         1174  
  168         231  
1083             }
1084 58         110 return;
1085             }
1086              
1087             BEGIN{
1088             # This is used in Scalar::Random::PP::OO::PurePerl
1089 2     2   16 Scalar::Random::PP::OO::Exporter->setup_import_methods(
1090             as_is => [qw(
1091             find_meta
1092             does_role
1093             resolve_metaclass_alias
1094             apply_all_roles
1095             english_list
1096              
1097             load_class
1098             is_class_loaded
1099              
1100             get_linear_isa
1101             get_code_info
1102              
1103             get_code_package
1104             get_code_ref
1105              
1106             not_supported
1107              
1108             does meta dump
1109             )],
1110             groups => {
1111             default => [], # export no functions by default
1112              
1113             # The ':meta' group is 'use metaclass' for Mousse
1114             meta => [qw(does meta dump)],
1115             },
1116             );
1117              
1118 2         5 our $VERSION = '0.70';
1119              
1120 2   33     12 my $xs = !(defined(&is_valid_class_name) || $ENV{MOUSE_PUREPERL} || $ENV{PERL_ONLY});
1121              
1122             # Because Scalar::Random::PP::OO::Util is loaded first in all the Scalar::Random::PP::OO sub-modules,
1123             # XSLoader must be placed here, not in Scalar/Random/PP/OO.pm.
1124 2 50       7 if($xs){
1125             # XXX: XSLoader tries to get the object path from caller's file name
1126             # $hack_mouse_file fools its mechanism
1127 0         0 (my $hack_mouse_file = __FILE__) =~ s/.Util//; # .../Scalar/Random/PP/OO/Util.pm -> .../Scalar/Random/PP/OO.pm
1128 0   0     0 $xs = eval sprintf("#line %d %s\n", __LINE__, $hack_mouse_file) . q{
1129             local $^W = 0; # workaround 'redefine' warning to &install_subroutines
1130             require XSLoader;
1131             XSLoader::load('Scalar::Random::PP::OO', $VERSION);
1132             Scalar::Random::PP::OO::Util->import({ into => 'Scalar::Random::PP::OO::Meta::Method::Constructor::XS' }, ':meta');
1133             Scalar::Random::PP::OO::Util->import({ into => 'Scalar::Random::PP::OO::Meta::Method::Destructor::XS' }, ':meta');
1134             Scalar::Random::PP::OO::Util->import({ into => 'Scalar::Random::PP::OO::Meta::Method::Accessor::XS' }, ':meta');
1135             return 1;
1136             } || 0;
1137             #warn $@ if $@;
1138             }
1139              
1140 2 50       7 if(!$xs){
1141 2         12 require 'Scalar/Random/PP/OO/PurePerl.pm'; # we don't want to create its namespace
1142             }
1143              
1144 2         69 *MOUSE_XS = sub(){ $xs };
  0         0  
1145             }
1146              
1147 2     2   10 use Carp ();
  2         4  
  2         38  
1148 2     2   9 use Scalar::Util ();
  2         3  
  2         750  
1149              
1150             # aliases as public APIs
1151             # it must be 'require', not 'use', because Scalar::Random::PP::OO::Meta::Module depends on Scalar::Random::PP::OO::Util
1152             require Scalar::Random::PP::OO::Meta::Module; # for the entities of metaclass cache utilities
1153              
1154             # aliases
1155             {
1156             *class_of = \&Scalar::Random::PP::OO::Meta::Module::_class_of;
1157             *get_metaclass_by_name = \&Scalar::Random::PP::OO::Meta::Module::_get_metaclass_by_name;
1158             *get_all_metaclass_instances = \&Scalar::Random::PP::OO::Meta::Module::_get_all_metaclass_instances;
1159             *get_all_metaclass_names = \&Scalar::Random::PP::OO::Meta::Module::_get_all_metaclass_names;
1160              
1161             *Scalar::Random::PP::OO::load_class = \&load_class;
1162             *Scalar::Random::PP::OO::is_class_loaded = \&is_class_loaded;
1163              
1164             # is-a predicates
1165             #generate_isa_predicate_for('Scalar::Random::PP::OO::Meta::TypeConstraint' => 'is_a_type_constraint');
1166             #generate_isa_predicate_for('Scalar::Random::PP::OO::Meta::Class' => 'is_a_metaclass');
1167             #generate_isa_predicate_for('Scalar::Random::PP::OO::Meta::Role' => 'is_a_metarole');
1168              
1169             # duck type predicates
1170             generate_can_predicate_for(['_compiled_type_constraint'] => 'is_a_type_constraint');
1171             generate_can_predicate_for(['create_anon_class'] => 'is_a_metaclass');
1172             generate_can_predicate_for(['create_anon_role'] => 'is_a_metarole');
1173             }
1174              
1175             our $in_global_destruction = 0;
1176 2     2   14 END{ $in_global_destruction = 1 }
1177              
1178             # Moose::Util compatible utilities
1179              
1180             sub find_meta{
1181 0     0 0 0 return class_of( $_[0] );
1182             }
1183              
1184             sub does_role{
1185 0     0 0 0 my ($class_or_obj, $role_name) = @_;
1186              
1187 0         0 my $meta = class_of($class_or_obj);
1188              
1189 0 0 0     0 (defined $role_name)
1190             || ($meta || 'Scalar::Random::PP::OO::Meta::Class')->throw_error("You must supply a role name to does()");
1191              
1192 0   0     0 return defined($meta) && $meta->does_role($role_name);
1193             }
1194              
1195             BEGIN {
1196 2     2   4 my $get_linear_isa;
1197 2 50       15 if ($] >= 5.009_005) {
1198 2         1958 require mro;
1199 2         1402 $get_linear_isa = \&mro::get_linear_isa;
1200             } else {
1201             # this code is based on MRO::Compat::__get_linear_isa
1202 0         0 my $_get_linear_isa_dfs; # this recurses so it isn't pretty
1203             $_get_linear_isa_dfs = sub {
1204 0         0 my($classname) = @_;
1205              
1206 0         0 my @lin = ($classname);
1207 0         0 my %stored;
1208              
1209 2     2   11 no strict 'refs';
  2         9  
  2         479  
1210 0         0 foreach my $parent (@{"$classname\::ISA"}) {
  0         0  
1211 0         0 foreach my $p(@{ $_get_linear_isa_dfs->($parent) }) {
  0         0  
1212 0 0       0 next if exists $stored{$p};
1213 0         0 push(@lin, $p);
1214 0         0 $stored{$p} = 1;
1215             }
1216             }
1217 0         0 return \@lin;
1218 0         0 };
1219              
1220             {
1221 0         0 package # hide from PAUSE
1222             Class::C3;
1223 0         0 our %MRO; # avoid 'once' warnings
1224             }
1225              
1226             # MRO::Compat::__get_linear_isa has no prototype, so
1227             # we define a prototyped version for compatibility with core's
1228             # See also MRO::Compat::__get_linear_isa.
1229             $get_linear_isa = sub ($;$){
1230 0         0 my($classname, $type) = @_;
1231              
1232 0 0       0 if(!defined $type){
1233 0 0       0 $type = exists $Class::C3::MRO{$classname} ? 'c3' : 'dfs';
1234             }
1235 0 0       0 if($type eq 'c3'){
1236 0         0 require Class::C3;
1237 0         0 return [Class::C3::calculateMRO($classname)];
1238             }
1239             else{
1240 0         0 return $_get_linear_isa_dfs->($classname);
1241             }
1242 0         0 };
1243             }
1244              
1245 2         1932 *get_linear_isa = $get_linear_isa;
1246             }
1247              
1248              
1249             # taken from Scalar::Random::PP::OO::Util (0.90)
1250             {
1251             my %cache;
1252              
1253             sub resolve_metaclass_alias {
1254 0     0 0 0 my ( $type, $metaclass_name, %options ) = @_;
1255              
1256 0 0       0 my $cache_key = $type . q{ } . ( $options{trait} ? '-Trait' : '' );
1257              
1258 0   0     0 return $cache{$cache_key}{$metaclass_name} ||= do{
1259              
1260 0 0       0 my $possible_full_name = join '::',
1261             'Scalar::Random::PP::OO::Meta', $type, 'Custom', ($options{trait} ? 'Trait' : ()), $metaclass_name
1262             ;
1263              
1264 0         0 my $loaded_class = load_first_existing_class(
1265             $possible_full_name,
1266             $metaclass_name
1267             );
1268              
1269 0 0       0 $loaded_class->can('register_implementation')
1270             ? $loaded_class->register_implementation
1271             : $loaded_class;
1272             };
1273             }
1274             }
1275              
1276             # Utilities from Class::MOP
1277              
1278             sub get_code_info;
1279             sub get_code_package;
1280              
1281             sub is_valid_class_name;
1282              
1283             # taken from Class/MOP.pm
1284             sub load_first_existing_class {
1285 0 0   0 0 0 my @classes = @_
1286             or return;
1287              
1288 0         0 my %exceptions;
1289 0         0 for my $class (@classes) {
1290 0         0 my $e = _try_load_one_class($class);
1291              
1292 0 0       0 if ($e) {
1293 0         0 $exceptions{$class} = $e;
1294             }
1295             else {
1296 0         0 return $class;
1297             }
1298             }
1299              
1300             # not found
1301 0         0 Carp::confess join(
1302             "\n",
1303             map {
1304 0         0 sprintf( "Could not load class (%s) because : %s",
1305             $_, $exceptions{$_} )
1306             } @classes
1307             );
1308             }
1309              
1310             # taken from Class/MOP.pm
1311             sub _try_load_one_class {
1312 2     2   4 my $class = shift;
1313              
1314 2 50       6 unless ( is_valid_class_name($class) ) {
1315 0 0       0 my $display = defined($class) ? $class : 'undef';
1316 0         0 Carp::confess "Invalid class name ($display)";
1317             }
1318              
1319 2 50       9 return '' if is_class_loaded($class);
1320              
1321 0         0 $class =~ s{::}{/}g;
1322 0         0 $class .= '.pm';
1323              
1324 0         0 return do {
1325 0         0 local $@;
1326 0         0 eval { require $class };
  0         0  
1327 0         0 $@;
1328             };
1329             }
1330              
1331              
1332             sub load_class {
1333 2     2 0 3 my $class = shift;
1334 2         7 my $e = _try_load_one_class($class);
1335 2 50       8 Carp::confess "Could not load class ($class) because : $e" if $e;
1336              
1337 2         3 return $class;
1338             }
1339              
1340             sub is_class_loaded;
1341              
1342             sub apply_all_roles {
1343 0 0   0 0 0 my $consumer = Scalar::Util::blessed($_[0])
1344             ? shift # instance
1345             : Scalar::Random::PP::OO::Meta::Class->initialize(shift); # class or role name
1346              
1347 0         0 my @roles;
1348              
1349             # Basis of Data::OptList
1350 0         0 my $max = scalar(@_);
1351 0         0 for (my $i = 0; $i < $max ; $i++) {
1352 0 0 0     0 if ($i + 1 < $max && ref($_[$i + 1])) {
1353 0         0 push @roles, [ $_[$i] => $_[++$i] ];
1354             } else {
1355 0         0 push @roles, [ $_[$i] => undef ];
1356             }
1357 0         0 my $role_name = $roles[-1][0];
1358 0         0 load_class($role_name);
1359              
1360 0 0       0 is_a_metarole( get_metaclass_by_name($role_name) )
1361             || $consumer->meta->throw_error("You can only consume roles, $role_name is not a Scalar::Random::PP::OO role");
1362             }
1363              
1364 0 0       0 if ( scalar @roles == 1 ) {
1365 0         0 my ( $role_name, $params ) = @{ $roles[0] };
  0         0  
1366 0 0       0 get_metaclass_by_name($role_name)->apply( $consumer, defined $params ? $params : () );
1367             }
1368             else {
1369 0         0 Scalar::Random::PP::OO::Meta::Role->combine(@roles)->apply($consumer);
1370             }
1371 0         0 return;
1372             }
1373              
1374             # taken from Moose::Util 0.90
1375             sub english_list {
1376 0 0   0 0 0 return $_[0] if @_ == 1;
1377              
1378 0         0 my @items = sort @_;
1379              
1380 0 0       0 return "$items[0] and $items[1]" if @items == 2;
1381              
1382 0         0 my $tail = pop @items;
1383              
1384 0         0 return join q{, }, @items, "and $tail";
1385             }
1386              
1387             sub quoted_english_list {
1388 0     0 0 0 return english_list(map { qq{'$_'} } @_);
  0         0  
1389             }
1390              
1391             # common utilities
1392              
1393             sub not_supported{
1394 0     0 0 0 my($feature) = @_;
1395              
1396 0   0     0 $feature ||= ( caller(1) )[3]; # subroutine name
1397              
1398 0         0 local $Carp::CarpLevel = $Carp::CarpLevel + 1;
1399 0         0 Carp::confess("Scalar::Random::PP::OO does not currently support $feature");
1400             }
1401              
1402             # general meta() method
1403             sub meta :method{
1404 0   0 0 0 0 return Scalar::Random::PP::OO::Meta::Class->initialize(ref($_[0]) || $_[0]);
1405             }
1406              
1407             # general dump() method
1408             sub dump :method {
1409 0     0 0 0 my($self, $maxdepth) = @_;
1410              
1411 0         0 require 'Data/Dumper.pm'; # we don't want to create its namespace
1412 0         0 my $dd = Data::Dumper->new([$self]);
1413 0 0       0 $dd->Maxdepth(defined($maxdepth) ? $maxdepth : 3);
1414 0         0 $dd->Indent(1);
1415 0         0 return $dd->Dump();
1416             }
1417              
1418             # general does() method
1419             sub does :method {
1420 0     0 0 0 goto &does_role;
1421             }
1422              
1423             # Contents of Mouse::Meta::TypeConstraint
1424             package Scalar::Random::PP::OO::Meta::TypeConstraint;
1425 2     2   14 use Scalar::Random::PP::OO::Util qw(:meta); # enables strict and warnings
  2         3  
  2         12  
1426 2     2   9 use Scalar::Util ();
  2         4  
  2         263  
1427              
1428             use overload
1429             'bool' => sub (){ 1 }, # always true
1430 0     0   0 '""' => sub { $_[0]->name }, # stringify to tc name
1431 0     0   0 '0+' => sub { Scalar::Util::refaddr($_[0]) },
1432             '|' => sub { # or-combination
1433 0     0   0 require Scalar::Random::PP::OO::Util::TypeConstraints;
1434 0         0 return Scalar::Random::PP::OO::Util::TypeConstraints::find_or_parse_type_constraint(
1435             "$_[0] | $_[1]",
1436             );
1437             },
1438              
1439 2     2   3001 fallback => 1;
  2         2234  
  2         28  
1440              
1441             sub new {
1442 44     44 0 45 my $class = shift;
1443 44 50       150 my %args = @_ == 1 ? %{$_[0]} : @_;
  0         0  
1444              
1445 44 50       91 $args{name} = '__ANON__' if !defined $args{name};
1446              
1447 44         59 my $check = delete $args{optimized};
1448              
1449 44 100       75 if($check){
1450 38         48 $args{hand_optimized_type_constraint} = $check;
1451 38         45 $args{compiled_type_constraint} = $check;
1452             }
1453              
1454 44         44 $check = $args{constraint};
1455              
1456 44 50 33     92 if(defined($check) && ref($check) ne 'CODE'){
1457 0         0 $class->throw_error("Constraint for $args{name} is not a CODE reference");
1458             }
1459              
1460 44         105 my $self = bless \%args, $class;
1461 44 100       161 $self->compile_type_constraint() if !$self->{hand_optimized_type_constraint};
1462              
1463 44 50       83 $self->_compile_union_type_coercion() if $self->{type_constraints};
1464 44         158 return $self;
1465             }
1466              
1467             sub create_child_type{
1468 2     2 0 5 my $self = shift;
1469 2         23 return ref($self)->new(
1470             # a child inherits its parent's attributes
1471 2         6 %{$self},
1472              
1473             # but does not inherit 'compiled_type_constraint' and 'hand_optimized_type_constraint'
1474             compiled_type_constraint => undef,
1475             hand_optimized_type_constraint => undef,
1476              
1477             # and is given child-specific args, of course.
1478             @_,
1479              
1480             # and its parent
1481             parent => $self,
1482             );
1483             }
1484              
1485             sub name;
1486             sub parent;
1487             sub message;
1488             sub has_coercion;
1489              
1490             sub check;
1491              
1492             sub type_parameter;
1493             sub __is_parameterized;
1494              
1495             sub _compiled_type_constraint;
1496             sub _compiled_type_coercion;
1497              
1498             sub compile_type_constraint;
1499              
1500              
1501             sub _add_type_coercions{
1502 0     0   0 my $self = shift;
1503              
1504 0   0     0 my $coercions = ($self->{coercion_map} ||= []);
1505 0         0 my %has = map{ $_->[0] => undef } @{$coercions};
  0         0  
  0         0  
1506              
1507 0         0 for(my $i = 0; $i < @_; $i++){
1508 0         0 my $from = $_[ $i];
1509 0         0 my $action = $_[++$i];
1510              
1511 0 0       0 if(exists $has{$from}){
1512 0         0 $self->throw_error("A coercion action already exists for '$from'");
1513             }
1514              
1515 0 0       0 my $type = Scalar::Random::PP::OO::Util::TypeConstraints::find_or_parse_type_constraint($from)
1516             or $self->throw_error("Could not find the type constraint ($from) to coerce from");
1517              
1518 0         0 push @{$coercions}, [ $type => $action ];
  0         0  
1519             }
1520              
1521             # compile
1522 0 0       0 if(exists $self->{type_constraints}){ # union type
1523 0         0 $self->throw_error("Cannot add additional type coercions to Union types");
1524             }
1525             else{
1526 0         0 $self->_compile_type_coercion();
1527             }
1528 0         0 return;
1529             }
1530              
1531             sub _compile_type_coercion {
1532 0     0   0 my($self) = @_;
1533              
1534 0         0 my @coercions = @{$self->{coercion_map}};
  0         0  
1535              
1536             $self->{_compiled_type_coercion} = sub {
1537 0     0   0 my($thing) = @_;
1538 0         0 foreach my $pair (@coercions) {
1539             #my ($constraint, $converter) = @$pair;
1540 0 0       0 if ($pair->[0]->check($thing)) {
1541 0         0 local $_ = $thing;
1542 0         0 return $pair->[1]->($thing);
1543             }
1544             }
1545 0         0 return $thing;
1546 0         0 };
1547 0         0 return;
1548             }
1549              
1550             sub _compile_union_type_coercion {
1551 0     0   0 my($self) = @_;
1552              
1553 0         0 my @coercions;
1554 0         0 foreach my $type(@{$self->{type_constraints}}){
  0         0  
1555 0 0       0 if($type->has_coercion){
1556 0         0 push @coercions, $type;
1557             }
1558             }
1559 0 0       0 if(@coercions){
1560             $self->{_compiled_type_coercion} = sub {
1561 0     0   0 my($thing) = @_;
1562 0         0 foreach my $type(@coercions){
1563 0         0 my $value = $type->coerce($thing);
1564 0 0       0 return $value if $self->check($value);
1565             }
1566 0         0 return $thing;
1567 0         0 };
1568             }
1569 0         0 return;
1570             }
1571              
1572             sub coerce {
1573 0     0 0 0 my $self = shift;
1574              
1575 0         0 my $coercion = $self->_compiled_type_coercion;
1576 0 0       0 if(!$coercion){
1577 0         0 $self->throw_error("Cannot coerce without a type coercion");
1578             }
1579              
1580 0 0       0 return $_[0] if $self->check(@_);
1581              
1582 0         0 return $coercion->(@_);
1583             }
1584              
1585             sub get_message {
1586 0     0 0 0 my ($self, $value) = @_;
1587 0 0       0 if ( my $msg = $self->message ) {
1588 0         0 local $_ = $value;
1589 0         0 return $msg->($value);
1590             }
1591             else {
1592 0 0       0 $value = ( defined $value ? overload::StrVal($value) : 'undef' );
1593 0         0 return "Validation failed for '$self' with value $value";
1594             }
1595             }
1596              
1597             sub is_a_type_of{
1598 0     0 0 0 my($self, $other) = @_;
1599              
1600             # ->is_a_type_of('__ANON__') is always false
1601 0 0 0     0 return 0 if !ref($other) && $other eq '__ANON__';
1602              
1603 0         0 (my $other_name = $other) =~ s/\s+//g;
1604              
1605 0 0       0 return 1 if $self->name eq $other_name;
1606              
1607 0 0       0 if(exists $self->{type_constraints}){ # union
1608 0         0 foreach my $type(@{$self->{type_constraints}}){
  0         0  
1609 0 0       0 return 1 if $type->name eq $other_name;
1610             }
1611             }
1612              
1613 0         0 for(my $parent = $self->parent; defined $parent; $parent = $parent->parent){
1614 0 0       0 return 1 if $parent->name eq $other_name;
1615             }
1616              
1617 0         0 return 0;
1618             }
1619              
1620             # See also Moose::Meta::TypeConstraint::Parameterizable
1621             sub parameterize{
1622 0     0 0 0 my($self, $param, $name) = @_;
1623              
1624 0 0       0 if(!ref $param){
1625 0         0 require Scalar::Random::PP::OO::Util::TypeConstraints;
1626 0         0 $param = Scalar::Random::PP::OO::Util::TypeConstraints::find_or_create_isa_type_constraint($param);
1627             }
1628              
1629 0   0     0 $name ||= sprintf '%s[%s]', $self->name, $param->name;
1630              
1631 0   0     0 my $generator = $self->{constraint_generator}
1632             || $self->throw_error("The $name constraint cannot be used, because $param doesn't subtype from a parameterizable type");
1633              
1634 0         0 return Scalar::Random::PP::OO::Meta::TypeConstraint->new(
1635             name => $name,
1636             parent => $self,
1637             type_parameter => $param,
1638             constraint => $generator->($param), # must be 'constraint', not 'optimized'
1639             );
1640             }
1641              
1642             sub assert_valid {
1643 0     0 0 0 my ($self, $value) = @_;
1644              
1645 0 0       0 if(!$self->check($value)){
1646 0         0 $self->throw_error($self->get_message($value));
1647             }
1648 0         0 return 1;
1649             }
1650              
1651             sub throw_error {
1652 0     0 0 0 require Scalar::Random::PP::OO::Meta::Module;
1653 0         0 goto &Scalar::Random::PP::OO::Meta::Module::throw_error;
1654             }
1655              
1656             # Contents of Mouse::Util::TypeConstraints
1657             package Scalar::Random::PP::OO::Util::TypeConstraints;
1658 2     2   2815 use Scalar::Random::PP::OO::Util qw(does_role not_supported); # enables strict and warnings
  2         3  
  2         14  
1659              
1660 2     2   12 use Carp ();
  2         2  
  2         58  
1661 2     2   11 use Scalar::Util ();
  2         3  
  2         36  
1662              
1663 2     2   12 use Scalar::Random::PP::OO::Meta::TypeConstraint;
  2         4  
  2         71  
1664 2     2   11 use Scalar::Random::PP::OO::Exporter;
  2         3  
  2         14  
1665              
1666             Scalar::Random::PP::OO::Exporter->setup_import_methods(
1667             as_is => [qw(
1668             as where message optimize_as
1669             from via
1670              
1671             type subtype class_type role_type duck_type
1672             enum
1673             coerce
1674              
1675             find_type_constraint
1676             register_type_constraint
1677             )],
1678             );
1679              
1680             our @CARP_NOT = qw(Scalar::Random::PP::OO::Meta::Attribute);
1681              
1682             my %TYPE;
1683              
1684             # The root type
1685             $TYPE{Any} = Scalar::Random::PP::OO::Meta::TypeConstraint->new(
1686             name => 'Any',
1687             );
1688              
1689             my @builtins = (
1690             # $name => $parent, $code,
1691              
1692             # the base type
1693             Item => 'Any', undef,
1694              
1695             # the maybe[] type
1696             Maybe => 'Item', undef,
1697              
1698             # value types
1699             Undef => 'Item', \&Undef,
1700             Defined => 'Item', \&Defined,
1701             Bool => 'Item', \&Bool,
1702             Value => 'Defined', \&Value,
1703             Str => 'Value', \&Str,
1704             Num => 'Str', \&Num,
1705             Int => 'Num', \&Int,
1706              
1707             # ref types
1708             Ref => 'Defined', \&Ref,
1709             ScalarRef => 'Ref', \&ScalarRef,
1710             ArrayRef => 'Ref', \&ArrayRef,
1711             HashRef => 'Ref', \&HashRef,
1712             CodeRef => 'Ref', \&CodeRef,
1713             RegexpRef => 'Ref', \&RegexpRef,
1714             GlobRef => 'Ref', \&GlobRef,
1715              
1716             # object types
1717             FileHandle => 'GlobRef', \&FileHandle,
1718             Object => 'Ref', \&Object,
1719              
1720             # special string types
1721             ClassName => 'Str', \&ClassName,
1722             RoleName => 'ClassName', \&RoleName,
1723             );
1724              
1725              
1726             while (my ($name, $parent, $code) = splice @builtins, 0, 3) {
1727             $TYPE{$name} = Scalar::Random::PP::OO::Meta::TypeConstraint->new(
1728             name => $name,
1729             parent => $TYPE{$parent},
1730             optimized => $code,
1731             );
1732             }
1733              
1734             # make it parametarizable
1735              
1736             $TYPE{Maybe} {constraint_generator} = \&_parameterize_Maybe_for;
1737             $TYPE{ArrayRef}{constraint_generator} = \&_parameterize_ArrayRef_for;
1738             $TYPE{HashRef} {constraint_generator} = \&_parameterize_HashRef_for;
1739              
1740             # sugars
1741              
1742 0     0 0 0 sub as ($) { (as => $_[0]) } ## no critic
1743 0     0 0 0 sub where (&) { (where => $_[0]) } ## no critic
1744 0     0 0 0 sub message (&) { (message => $_[0]) } ## no critic
1745 0     0 0 0 sub optimize_as (&) { (optimize_as => $_[0]) } ## no critic
1746              
1747 0     0 0 0 sub from { @_ }
1748 0     0 0 0 sub via (&) { $_[0] } ## no critic
1749              
1750             # type utilities
1751              
1752             sub optimized_constraints { # DEPRECATED
1753 0     0 0 0 Carp::cluck('optimized_constraints() has been deprecated');
1754 0         0 return \%TYPE;
1755             }
1756              
1757             undef @builtins; # free the allocated memory
1758             @builtins = keys %TYPE; # reuse it
1759 0     0 0 0 sub list_all_builtin_type_constraints { @builtins }
1760              
1761 0     0 0 0 sub list_all_type_constraints { keys %TYPE }
1762              
1763             sub _create_type{
1764 2     2   5 my $mode = shift;
1765              
1766 2         4 my $name;
1767             my %args;
1768              
1769 2 50 33     27 if(@_ == 1 && ref $_[0]){ # @_ : { name => $name, where => ... }
    50 33        
    50          
1770 0         0 %args = %{$_[0]};
  0         0  
1771             }
1772             elsif(@_ == 2 && ref $_[1]){ # @_ : $name => { where => ... }
1773 0         0 $name = $_[0];
1774 0         0 %args = %{$_[1]};
  0         0  
1775             }
1776             elsif(@_ % 2){ # @_ : $name => ( where => ... )
1777 2         10 ($name, %args) = @_;
1778             }
1779             else{ # @_ : (name => $name, where => ...)
1780 0         0 %args = @_;
1781             }
1782              
1783 2 50       9 if(!defined $name){
1784 0         0 $name = $args{name};
1785             }
1786              
1787 2         5 $args{name} = $name;
1788 2         4 my $parent;
1789 2 50       6 if($mode eq 'subtype'){
1790 2         6 $parent = delete $args{as};
1791 2 50       8 if(!$parent){
1792 0         0 $parent = delete $args{name};
1793 0         0 $name = undef;
1794             }
1795             }
1796              
1797 2 50       7 if(defined $name){
1798             # set 'package_defined_in' only if it is not a core package
1799 2         7 my $this = $args{package_defined_in};
1800 2 50       9 if(!$this){
1801 2         4 $this = caller(1);
1802 2 50       15 if($this !~ /\A Scalar::Random::PP::OO \b/xms){
1803 0         0 $args{package_defined_in} = $this;
1804             }
1805             }
1806              
1807 2 50       11 if($TYPE{$name}){
1808 0   0     0 my $that = $TYPE{$name}->{package_defined_in} || __PACKAGE__;
1809 0 0       0 if($this ne $that) {
1810 0         0 my $note = '';
1811 0 0       0 if($that eq __PACKAGE__) {
1812 0         0 $note = sprintf " ('%s' is %s type constraint)",
1813             $name,
1814 0 0       0 scalar(grep { $name eq $_ } list_all_builtin_type_constraints())
1815             ? 'a builtin'
1816             : 'an implicitly created';
1817             }
1818 0         0 Carp::croak("The type constraint '$name' has already been created in $that"
1819             . " and cannot be created again in $this" . $note);
1820             }
1821             }
1822             }
1823             else{
1824 0         0 $args{name} = '__ANON__';
1825             }
1826              
1827 2 50       10 $args{constraint} = delete $args{where} if exists $args{where};
1828 2 50       10 $args{optimized} = delete $args{optimized_as} if exists $args{optimized_as};
1829              
1830 2         3 my $constraint;
1831 2 50       7 if($mode eq 'subtype'){
1832 2         9 $constraint = find_or_create_isa_type_constraint($parent)->create_child_type(%args);
1833             }
1834             else{
1835 0         0 $constraint = Scalar::Random::PP::OO::Meta::TypeConstraint->new(%args);
1836             }
1837              
1838 2 50       8 if(defined $name){
1839 2         12 return $TYPE{$name} = $constraint;
1840             }
1841             else{
1842 0         0 return $constraint;
1843             }
1844             }
1845              
1846             sub type {
1847 0     0 0 0 return _create_type('type', @_);
1848             }
1849              
1850             sub subtype {
1851 0     0 0 0 return _create_type('subtype', @_);
1852             }
1853              
1854             sub coerce {
1855 0     0 0 0 my $type_name = shift;
1856              
1857 0 0       0 my $type = find_type_constraint($type_name)
1858             or Carp::croak("Cannot find type '$type_name', perhaps you forgot to load it.");
1859              
1860 0         0 $type->_add_type_coercions(@_);
1861 0         0 return;
1862             }
1863              
1864             sub class_type {
1865 2     2 0 4 my($name, $options) = @_;
1866 2   33     13 my $class = $options->{class} || $name;
1867              
1868             # ClassType
1869 2         10 return _create_type 'subtype', $name => (
1870             as => 'Object',
1871             optimized_as => Scalar::Random::PP::OO::Util::generate_isa_predicate_for($class),
1872             );
1873             }
1874              
1875             sub role_type {
1876 0     0 0 0 my($name, $options) = @_;
1877 0   0     0 my $role = $options->{role} || $name;
1878              
1879             # RoleType
1880             return _create_type 'subtype', $name => (
1881             as => 'Object',
1882 0 0   0   0 optimized_as => sub { Scalar::Util::blessed($_[0]) && does_role($_[0], $role) },
1883 0         0 );
1884             }
1885              
1886             sub duck_type {
1887 0     0 0 0 my($name, @methods);
1888              
1889 0 0 0     0 if(!(@_ == 1 && ref($_[0]) eq 'ARRAY')){
1890 0         0 $name = shift;
1891             }
1892              
1893 0 0 0     0 @methods = (@_ == 1 && ref($_[0]) eq 'ARRAY') ? @{$_[0]} : @_;
  0         0  
1894              
1895             # DuckType
1896 0         0 return _create_type 'subtype', $name => (
1897             as => 'Object',
1898             optimized_as => Scalar::Random::PP::OO::Util::generate_can_predicate_for(\@methods),
1899             );
1900             }
1901              
1902             sub enum {
1903 0     0 0 0 my($name, %valid);
1904              
1905 0 0 0     0 if(!(@_ == 1 && ref($_[0]) eq 'ARRAY')){
1906 0         0 $name = shift;
1907             }
1908              
1909 0 0 0     0 %valid = map{ $_ => undef } (@_ == 1 && ref($_[0]) eq 'ARRAY' ? @{$_[0]} : @_);
  0         0  
  0         0  
1910              
1911             # EnumType
1912             return _create_type 'subtype', $name => (
1913             as => 'Str',
1914 0 0 0 0   0 optimized_as => sub{ defined($_[0]) && !ref($_[0]) && exists $valid{$_[0]} },
1915 0         0 );
1916             }
1917              
1918             sub _find_or_create_regular_type{
1919 0     0   0 my($spec, $create) = @_;
1920              
1921 0 0       0 return $TYPE{$spec} if exists $TYPE{$spec};
1922              
1923 0         0 my $meta = Scalar::Random::PP::OO::Util::get_metaclass_by_name($spec);
1924              
1925 0 0       0 if(!defined $meta){
1926 0 0       0 return $create ? class_type($spec) : undef;
1927             }
1928              
1929 0 0       0 if(Scalar::Random::PP::OO::Util::is_a_metarole($meta)){
1930 0         0 return role_type($spec);
1931             }
1932             else{
1933 0         0 return class_type($spec);
1934             }
1935             }
1936              
1937             sub _find_or_create_parameterized_type{
1938 0     0   0 my($base, $param) = @_;
1939              
1940 0         0 my $name = sprintf '%s[%s]', $base->name, $param->name;
1941              
1942 0   0     0 $TYPE{$name} ||= $base->parameterize($param, $name);
1943             }
1944              
1945             sub _find_or_create_union_type{
1946 0 0   0   0 return if grep{ not defined } @_;
  0         0  
1947 0 0       0 my @types = sort map{ $_->{type_constraints} ? @{$_->{type_constraints}} : $_ } @_;
  0         0  
  0         0  
1948              
1949 0         0 my $name = join '|', @types;
1950              
1951             # UnionType
1952 0   0     0 $TYPE{$name} ||= Scalar::Random::PP::OO::Meta::TypeConstraint->new(
1953             name => $name,
1954             type_constraints => \@types,
1955             );
1956             }
1957              
1958             # The type parser
1959              
1960             # param : '[' type ']' | NOTHING
1961             sub _parse_param {
1962 0     0   0 my($c) = @_;
1963              
1964 0 0       0 if($c->{spec} =~ s/^\[//){
1965 0         0 my $type = _parse_type($c, 1);
1966              
1967 0 0       0 if($c->{spec} =~ s/^\]//){
1968 0         0 return $type;
1969             }
1970 0         0 Carp::croak("Syntax error in type: missing right square bracket in '$c->{orig}'");
1971             }
1972              
1973 0         0 return undef;
1974             }
1975              
1976             # name : [\w.:]+
1977             sub _parse_name {
1978 0     0   0 my($c, $create) = @_;
1979              
1980 0 0       0 if($c->{spec} =~ s/\A ([\w.:]+) //xms){
1981 0         0 return _find_or_create_regular_type($1, $create);
1982             }
1983 0         0 Carp::croak("Syntax error in type: expect type name near '$c->{spec}' in '$c->{orig}'");
1984             }
1985              
1986             # single_type : name param
1987             sub _parse_single_type {
1988 0     0   0 my($c, $create) = @_;
1989              
1990 0         0 my $type = _parse_name($c, $create);
1991 0         0 my $param = _parse_param($c);
1992              
1993 0 0       0 if(defined $type){
    0          
1994 0 0       0 if(defined $param){
1995 0         0 return _find_or_create_parameterized_type($type, $param);
1996             }
1997             else {
1998 0         0 return $type;
1999             }
2000             }
2001             elsif(defined $param){
2002 0         0 Carp::croak("Undefined type with parameter [$param] in '$c->{orig}'");
2003             }
2004             else{
2005 0         0 return undef;
2006             }
2007             }
2008              
2009             # type : single_type ('|' single_type)*
2010             sub _parse_type {
2011 0     0   0 my($c, $create) = @_;
2012              
2013 0         0 my $type = _parse_single_type($c, $create);
2014 0 0       0 if($c->{spec}){ # can be an union type
2015 0         0 my @types;
2016 0         0 while($c->{spec} =~ s/^\|//){
2017 0         0 push @types, _parse_single_type($c, $create);
2018             }
2019 0 0       0 if(@types){
2020 0         0 return _find_or_create_union_type($type, @types);
2021             }
2022             }
2023 0         0 return $type;
2024             }
2025              
2026              
2027             sub find_type_constraint {
2028 2     2 0 5 my($spec) = @_;
2029 2 50 33     12 return $spec if Scalar::Random::PP::OO::Util::is_a_type_constraint($spec) or not defined $spec;
2030              
2031 2         7 $spec =~ s/\s+//g;
2032 2         16 return $TYPE{$spec};
2033             }
2034              
2035             sub register_type_constraint {
2036 0     0 0 0 my($constraint) = @_;
2037 0 0       0 Carp::croak("No type supplied / type is not a valid type constraint")
2038             unless Scalar::Random::PP::OO::Util::is_a_type_constraint($constraint);
2039 0         0 my $name = $constraint->name;
2040 0 0       0 Carp::croak("can't register an unnamed type constraint")
2041             unless defined $name;
2042 0         0 return $TYPE{$name} = $constraint;
2043             }
2044              
2045             sub find_or_parse_type_constraint {
2046 2     2 0 4 my($spec) = @_;
2047 2 50 33     5 return $spec if Scalar::Random::PP::OO::Util::is_a_type_constraint($spec) or not defined $spec;
2048              
2049 2         6 $spec =~ s/\s+//g;
2050 2   33     29 return $TYPE{$spec} || do{
2051             my $context = {
2052             spec => $spec,
2053             orig => $spec,
2054             };
2055             my $type = _parse_type($context);
2056              
2057             if($context->{spec}){
2058             Carp::croak("Syntax error: extra elements '$context->{spec}' in '$context->{orig}'");
2059             }
2060             $type;
2061             };
2062             }
2063              
2064             sub find_or_create_does_type_constraint{
2065             # XXX: Moose does not register a new role_type, but Scalar::Random::PP::OO does.
2066 0   0 0 0 0 return find_or_parse_type_constraint(@_) || role_type(@_);
2067             }
2068              
2069             sub find_or_create_isa_type_constraint {
2070             # XXX: Moose does not register a new class_type, but Scalar::Random::PP::OO does.
2071 2   33 2 0 8 return find_or_parse_type_constraint(@_) || class_type(@_);
2072             }
2073              
2074             # Contents of Mouse
2075             package Scalar::Random::PP::OO::TOP;
2076 2     2   68 use 5.006_002;
  2         9  
  2         89  
2077              
2078 2     2   9 use Scalar::Random::PP::OO::Exporter; # enables strict and warnings
  2         4  
  2         10  
2079              
2080             our $VERSION = '0.70';
2081              
2082 2     2   21 use Carp qw(confess);
  2         39  
  2         163  
2083 2     2   10 use Scalar::Util qw(blessed);
  2         3  
  2         79  
2084              
2085 2     2   10 use Scalar::Random::PP::OO::Util ();
  2         2  
  2         44  
2086              
2087 2     2   11 use Scalar::Random::PP::OO::Meta::Module;
  2         5  
  2         60  
2088 2     2   8 use Scalar::Random::PP::OO::Meta::Class;
  2         43  
  2         49  
2089 2     2   9 use Scalar::Random::PP::OO::Meta::Role;
  2         2  
  2         50  
2090 2     2   9 use Scalar::Random::PP::OO::Meta::Attribute;
  2         4  
  2         53  
2091 2     2   9 use Scalar::Random::PP::OO::Object;
  2         10  
  2         52  
2092 2     2   9 use Scalar::Random::PP::OO::Util::TypeConstraints ();
  2         2  
  2         1802  
2093              
2094             Scalar::Random::PP::OO::Exporter->setup_import_methods(
2095             as_is => [qw(
2096             extends with
2097             has
2098             before after around
2099             override super
2100             augment inner
2101             ),
2102             \&Scalar::Util::blessed,
2103             \&Carp::confess,
2104             ],
2105             );
2106              
2107              
2108             sub extends {
2109 0     0   0 Scalar::Random::PP::OO::Meta::Class->initialize(scalar caller)->superclasses(@_);
2110 0         0 return;
2111             }
2112              
2113             sub with {
2114 0     0   0 Scalar::Random::PP::OO::Util::apply_all_roles(scalar(caller), @_);
2115 0         0 return;
2116             }
2117              
2118             sub has {
2119 2     2   11 my $meta = Scalar::Random::PP::OO::Meta::Class->initialize(scalar caller);
2120 2         5 my $name = shift;
2121              
2122 2 50       10 $meta->throw_error(q{Usage: has 'name' => ( key => value, ... )})
2123             if @_ % 2; # odd number of arguments
2124              
2125 2 50       8 if(ref $name){ # has [qw(foo bar)] => (...)
2126 0         0 for (@{$name}){
  0         0  
2127 0         0 $meta->add_attribute($_ => @_);
2128             }
2129             }
2130             else{ # has foo => (...)
2131 2         10 $meta->add_attribute($name => @_);
2132             }
2133 2         6 return;
2134             }
2135              
2136             sub before {
2137 0     0   0 my $meta = Scalar::Random::PP::OO::Meta::Class->initialize(scalar caller);
2138 0         0 my $code = pop;
2139 0         0 for my $name($meta->_collect_methods(@_)) {
2140 0         0 $meta->add_before_method_modifier($name => $code);
2141             }
2142 0         0 return;
2143             }
2144              
2145             sub after {
2146 0     0   0 my $meta = Scalar::Random::PP::OO::Meta::Class->initialize(scalar caller);
2147 0         0 my $code = pop;
2148 0         0 for my $name($meta->_collect_methods(@_)) {
2149 0         0 $meta->add_after_method_modifier($name => $code);
2150             }
2151 0         0 return;
2152             }
2153              
2154             sub around {
2155 0     0   0 my $meta = Scalar::Random::PP::OO::Meta::Class->initialize(scalar caller);
2156 0         0 my $code = pop;
2157 0         0 for my $name($meta->_collect_methods(@_)) {
2158 0         0 $meta->add_around_method_modifier($name => $code);
2159             }
2160 0         0 return;
2161             }
2162              
2163             our $SUPER_PACKAGE;
2164             our $SUPER_BODY;
2165             our @SUPER_ARGS;
2166              
2167             sub super {
2168             # This check avoids a recursion loop - see
2169             # t/100_bugs/020_super_recursion.t
2170 0 0 0 0   0 return if defined $SUPER_PACKAGE && $SUPER_PACKAGE ne caller();
2171 0 0       0 return if !defined $SUPER_BODY;
2172 0         0 $SUPER_BODY->(@SUPER_ARGS);
2173             }
2174              
2175             sub override {
2176             # my($name, $method) = @_;
2177 0     0   0 Scalar::Random::PP::OO::Meta::Class->initialize(scalar caller)->add_override_method_modifier(@_);
2178             }
2179              
2180             our %INNER_BODY;
2181             our %INNER_ARGS;
2182              
2183             sub inner {
2184 0     0   0 my $pkg = caller();
2185 0 0       0 if ( my $body = $INNER_BODY{$pkg} ) {
2186 0         0 my $args = $INNER_ARGS{$pkg};
2187 0         0 local $INNER_ARGS{$pkg};
2188 0         0 local $INNER_BODY{$pkg};
2189 0         0 return $body->(@{$args});
  0         0  
2190             }
2191             else {
2192 0         0 return;
2193             }
2194             }
2195              
2196             sub augment {
2197             #my($name, $method) = @_;
2198 0     0   0 Scalar::Random::PP::OO::Meta::Class->initialize(scalar caller)->add_augment_method_modifier(@_);
2199 0         0 return;
2200             }
2201              
2202             sub init_meta {
2203 2     2   4 shift;
2204 2         7 my %args = @_;
2205              
2206 2 50       9 my $class = $args{for_class}
2207             or confess("Cannot call init_meta without specifying a for_class");
2208              
2209 2   50     76 my $base_class = $args{base_class} || 'Scalar::Random::PP::OO::Object';
2210 2   50     14 my $metaclass = $args{metaclass} || 'Scalar::Random::PP::OO::Meta::Class';
2211              
2212 2         19 my $meta = $metaclass->initialize($class);
2213              
2214             $meta->add_method(meta => sub{
2215 0   0 0   0 return $metaclass->initialize(ref($_[0]) || $_[0]);
2216 2         21 });
2217              
2218 2 50       8 $meta->superclasses($base_class)
2219             unless $meta->superclasses;
2220              
2221             # make a class type for each Scalar::Random::PP::OO class
2222 2 50       7 Scalar::Random::PP::OO::Util::TypeConstraints::class_type($class)
2223             unless Scalar::Random::PP::OO::Util::TypeConstraints::find_type_constraint($class);
2224              
2225 2         10 return $meta;
2226             }
2227              
2228             # Contents of Mouse::Meta::Attribute
2229             package Scalar::Random::PP::OO::Meta::Attribute;
2230 2     2   13 use Scalar::Random::PP::OO::Util qw(:meta); # enables strict and warnings
  2         3  
  2         7  
2231              
2232 2     2   10 use Carp ();
  2         2  
  2         31  
2233              
2234 2     2   10 use Scalar::Random::PP::OO::Meta::TypeConstraint;
  2         3  
  2         4391  
2235              
2236             my %valid_options = map { $_ => undef } (
2237             'accessor',
2238             'auto_deref',
2239             'builder',
2240             'clearer',
2241             'coerce',
2242             'default',
2243             'documentation',
2244             'does',
2245             'handles',
2246             'init_arg',
2247             'insertion_order',
2248             'is',
2249             'isa',
2250             'lazy',
2251             'lazy_build',
2252             'name',
2253             'predicate',
2254             'reader',
2255             'required',
2256             'traits',
2257             'trigger',
2258             'type_constraint',
2259             'weak_ref',
2260             'writer',
2261              
2262             # internally used
2263             'associated_class',
2264             'associated_methods',
2265              
2266             # Moose defines, but Scalar::Random::PP::OO doesn't
2267             #'definition_context',
2268             #'initializer',
2269              
2270             # special case for AttributeHelpers
2271             'provides',
2272             'curries',
2273             );
2274              
2275             our @CARP_NOT = qw(Scalar::Random::PP::OO::Meta::Class);
2276              
2277             sub new {
2278 2     2 0 4 my $class = shift;
2279 2         4 my $name = shift;
2280              
2281 2         12 my $args = $class->Scalar::Random::PP::OO::Object::BUILDARGS(@_);
2282              
2283 2         10 $class->_process_options($name, $args);
2284              
2285 2         5 $args->{name} = $name;
2286              
2287             # check options
2288             # (1) known by core
2289 2         4 my @bad = grep{ !exists $valid_options{$_} } keys %{$args};
  8         20  
  2         7  
2290              
2291             # (2) known by subclasses
2292 2 50 33     10 if(@bad && $class ne __PACKAGE__){
2293 0         0 my %valid_attrs = (
2294 0         0 map { $_ => undef }
2295 0         0 grep { defined }
2296 0         0 map { $_->init_arg() }
2297             $class->meta->get_all_attributes()
2298             );
2299 0         0 @bad = grep{ !exists $valid_attrs{$_} } @bad;
  0         0  
2300             }
2301              
2302             # (3) bad options found
2303 2 50       7 if(@bad){
2304 0         0 Carp::carp(
2305             "Found unknown argument(s) passed to '$name' attribute constructor in '$class': "
2306             . Scalar::Random::PP::OO::Util::english_list(@bad));
2307             }
2308              
2309 2         8 my $self = bless $args, $class;
2310              
2311             # extra attributes
2312 2 50       7 if($class ne __PACKAGE__){
2313 0         0 $class->meta->_initialize_object($self, $args);
2314             }
2315              
2316 2         7 return $self;
2317             }
2318              
2319 0 0   0 0 0 sub has_read_method { $_[0]->has_reader || $_[0]->has_accessor }
2320 0 0   0 0 0 sub has_write_method { $_[0]->has_writer || $_[0]->has_accessor }
2321              
2322             sub interpolate_class{
2323 2     2 0 5 my($class, $args) = @_;
2324              
2325 2 50       8 if(my $metaclass = delete $args->{metaclass}){
2326 0         0 $class = Scalar::Random::PP::OO::Util::resolve_metaclass_alias( Attribute => $metaclass );
2327             }
2328              
2329 2         4 my @traits;
2330 2 50       9 if(my $traits_ref = delete $args->{traits}){
2331              
2332 0         0 for (my $i = 0; $i < @{$traits_ref}; $i++) {
  0         0  
2333 0         0 my $trait = Scalar::Random::PP::OO::Util::resolve_metaclass_alias(Attribute => $traits_ref->[$i], trait => 1);
2334              
2335 0 0       0 next if $class->does($trait);
2336              
2337 0         0 push @traits, $trait;
2338              
2339             # are there options?
2340 0 0       0 push @traits, $traits_ref->[++$i]
2341             if ref($traits_ref->[$i+1]);
2342             }
2343              
2344 0 0       0 if (@traits) {
2345 0         0 $class = Scalar::Random::PP::OO::Meta::Class->create_anon_class(
2346             superclasses => [ $class ],
2347             roles => \@traits,
2348             cache => 1,
2349             )->name;
2350             }
2351             }
2352              
2353 2         6 return( $class, @traits );
2354             }
2355              
2356             sub _coerce_and_verify {
2357             #my($self, $value, $instance) = @_;
2358 4     4   10 my($self, $value) = @_;
2359              
2360 4         12 my $type_constraint = $self->{type_constraint};
2361 4 50       180 return $value if !defined $type_constraint;
2362              
2363 0 0 0     0 if ($self->should_coerce && $type_constraint->has_coercion) {
2364 0         0 $value = $type_constraint->coerce($value);
2365             }
2366              
2367 0         0 $self->verify_against_type_constraint($value);
2368              
2369 0         0 return $value;
2370             }
2371              
2372             sub verify_against_type_constraint {
2373 0     0 0 0 my ($self, $value) = @_;
2374              
2375 0         0 my $type_constraint = $self->{type_constraint};
2376 0 0       0 return 1 if !$type_constraint;
2377 0 0       0 return 1 if $type_constraint->check($value);
2378              
2379 0         0 $self->_throw_type_constraint_error($value, $type_constraint);
2380             }
2381              
2382             sub _throw_type_constraint_error {
2383 0     0   0 my($self, $value, $type) = @_;
2384              
2385 0         0 $self->throw_error(
2386             sprintf q{Attribute (%s) does not pass the type constraint because: %s},
2387             $self->name,
2388             $type->get_message($value),
2389             );
2390             }
2391              
2392             sub illegal_options_for_inheritance {
2393 0     0 0 0 return qw(reader writer accessor clearer predicate);
2394             }
2395              
2396             sub clone_and_inherit_options{
2397 0     0 0 0 my $self = shift;
2398 0         0 my $args = $self->Scalar::Random::PP::OO::Object::BUILDARGS(@_);
2399              
2400 0         0 foreach my $illegal($self->illegal_options_for_inheritance) {
2401 0 0 0     0 if(exists $args->{$illegal} and exists $self->{$illegal}) {
2402 0         0 $self->throw_error("Illegal inherited option: $illegal");
2403             }
2404             }
2405              
2406 0         0 foreach my $name(keys %{$self}){
  0         0  
2407 0 0       0 if(!exists $args->{$name}){
2408 0         0 $args->{$name} = $self->{$name}; # inherit from self
2409             }
2410             }
2411              
2412 0         0 my($attribute_class, @traits) = ref($self)->interpolate_class($args);
2413 0 0       0 $args->{traits} = \@traits if @traits;
2414              
2415             # remove temporary caches
2416 0         0 foreach my $attr(keys %{$args}){
  0         0  
2417 0 0       0 if($attr =~ /\A _/xms){
2418 0         0 delete $args->{$attr};
2419             }
2420             }
2421              
2422             # remove default if lazy_build => 1
2423 0 0       0 if($args->{lazy_build}) {
2424 0         0 delete $args->{default};
2425             }
2426              
2427 0         0 return $attribute_class->new($self->name, $args);
2428             }
2429              
2430             sub get_read_method {
2431 0   0 0 0 0 return $_[0]->reader || $_[0]->accessor
2432             }
2433             sub get_write_method {
2434 0   0 0 0 0 return $_[0]->writer || $_[0]->accessor
2435             }
2436              
2437             sub _get_accessor_method_ref {
2438 0     0   0 my($self, $type, $generator) = @_;
2439              
2440 0   0     0 my $metaclass = $self->associated_class
2441             || $self->throw_error('No asocciated class for ' . $self->name);
2442              
2443 0         0 my $accessor = $self->$type();
2444 0 0       0 if($accessor){
2445 0         0 return $metaclass->get_method_body($accessor);
2446             }
2447             else{
2448 0         0 return $self->accessor_metaclass->$generator($self, $metaclass);
2449             }
2450             }
2451              
2452             sub get_read_method_ref{
2453 0     0 0 0 my($self) = @_;
2454 0   0     0 return $self->{_read_method_ref} ||= $self->_get_accessor_method_ref('get_read_method', '_generate_reader');
2455             }
2456              
2457             sub get_write_method_ref{
2458 0     0 0 0 my($self) = @_;
2459 0   0     0 return $self->{_write_method_ref} ||= $self->_get_accessor_method_ref('get_write_method', '_generate_writer');
2460             }
2461              
2462             sub set_value {
2463 0     0 0 0 my($self, $object, $value) = @_;
2464 0         0 return $self->get_write_method_ref()->($object, $value);
2465             }
2466              
2467             sub get_value {
2468 0     0 0 0 my($self, $object) = @_;
2469 0         0 return $self->get_read_method_ref()->($object);
2470             }
2471              
2472             sub has_value {
2473 0     0 0 0 my($self, $object) = @_;
2474 0   0     0 my $accessor_ref = $self->{_predicate_ref}
2475             ||= $self->_get_accessor_method_ref('predicate', '_generate_predicate');
2476              
2477 0         0 return $accessor_ref->($object);
2478             }
2479              
2480             sub clear_value {
2481 0     0 0 0 my($self, $object) = @_;
2482 0   0     0 my $accessor_ref = $self->{_crealer_ref}
2483             ||= $self->_get_accessor_method_ref('clearer', '_generate_clearer');
2484              
2485 0         0 return $accessor_ref->($object);
2486             }
2487              
2488              
2489             sub associate_method{
2490             #my($attribute, $method_name) = @_;
2491 2     2 0 4 my($attribute) = @_;
2492 2         5 $attribute->{associated_methods}++;
2493 2         6 return;
2494             }
2495              
2496             sub install_accessors{
2497 2     2 0 4 my($attribute) = @_;
2498              
2499 2         10 my $metaclass = $attribute->associated_class;
2500 2         10 my $accessor_class = $attribute->accessor_metaclass;
2501              
2502 2         7 foreach my $type(qw(accessor reader writer predicate clearer)){
2503 10 100       29 if(exists $attribute->{$type}){
2504 2         6 my $generator = '_generate_' . $type;
2505 2         21 my $code = $accessor_class->$generator($attribute, $metaclass);
2506 2         9 $metaclass->add_method($attribute->{$type} => $code);
2507 2         9 $attribute->associate_method($attribute->{$type});
2508             }
2509             }
2510              
2511             # install delegation
2512 2 50       9 if(exists $attribute->{handles}){
2513 0         0 my %handles = $attribute->_canonicalize_handles($attribute->{handles});
2514              
2515 0         0 while(my($handle, $method_to_call) = each %handles){
2516 0 0       0 if($metaclass->has_method($handle)) {
2517 0         0 $attribute->throw_error("You cannot overwrite a locally defined method ($handle) with a delegation");
2518             }
2519              
2520 0         0 $metaclass->add_method($handle =>
2521             $attribute->_make_delegation_method(
2522             $handle, $method_to_call));
2523              
2524 0         0 $attribute->associate_method($handle);
2525             }
2526             }
2527              
2528 2         3 return;
2529             }
2530              
2531             sub delegation_metaclass() { ## no critic
2532             'Scalar::Random::PP::OO::Meta::Method::Delegation'
2533             }
2534              
2535             sub _canonicalize_handles {
2536 0     0   0 my($self, $handles) = @_;
2537              
2538 0 0       0 if (ref($handles) eq 'HASH') {
    0          
    0          
    0          
2539 0         0 return %$handles;
2540             }
2541             elsif (ref($handles) eq 'ARRAY') {
2542 0         0 return map { $_ => $_ } @$handles;
  0         0  
2543             }
2544             elsif ( ref($handles) eq 'CODE' ) {
2545 0   0     0 my $class_or_role = ( $self->{isa} || $self->{does} )
2546             || $self->throw_error( "Cannot find delegate metaclass for attribute " . $self->name );
2547 0         0 return $handles->( $self, Scalar::Random::PP::OO::Meta::Class->initialize("$class_or_role"));
2548             }
2549             elsif (ref($handles) eq 'Regexp') {
2550 0   0     0 my $class_or_role = ($self->{isa} || $self->{does})
2551             || $self->throw_error("Cannot delegate methods based on a Regexp without a type constraint (isa)");
2552              
2553 0         0 my $meta = Scalar::Random::PP::OO::Meta::Class->initialize("$class_or_role"); # "" for stringify
2554 0 0       0 return map { $_ => $_ }
  0         0  
2555 0 0       0 grep { !Scalar::Random::PP::OO::Object->can($_) && $_ =~ $handles }
2556             Scalar::Random::PP::OO::Util::is_a_metarole($meta)
2557             ? $meta->get_method_list
2558             : $meta->get_all_method_names;
2559             }
2560             else {
2561 0         0 $self->throw_error("Unable to canonicalize the 'handles' option with $handles");
2562             }
2563             }
2564              
2565             sub _make_delegation_method {
2566 0     0   0 my($self, $handle, $method_to_call) = @_;
2567 0         0 return Scalar::Random::PP::OO::Util::load_class($self->delegation_metaclass)
2568             ->_generate_delegation($self, $handle, $method_to_call);
2569             }
2570              
2571             sub throw_error{
2572 0     0 0 0 my $self = shift;
2573              
2574 0   0     0 my $metaclass = (ref $self && $self->associated_class) || 'Scalar::Random::PP::OO::Meta::Class';
2575 0         0 $metaclass->throw_error(@_, depth => 1);
2576             }
2577              
2578             # Contents of Mouse::Meta::Class
2579             package Scalar::Random::PP::OO::Meta::Class;
2580 2     2   12 use Scalar::Random::PP::OO::Util qw/:meta get_linear_isa not_supported/; # enables strict and warnings
  2         5  
  2         12  
2581 2     2   10 no warnings 'once';
  2         3  
  2         91  
2582              
2583 2     2   20 use Scalar::Util qw/blessed weaken/;
  2         3  
  2         117  
2584              
2585 2     2   10 use Scalar::Random::PP::OO::Meta::Module;
  2         5  
  2         282  
2586             our @ISA = qw(Scalar::Random::PP::OO::Meta::Module);
2587              
2588             our @CARP_NOT = qw(Scalar::Random::PP::OO); # trust Mousse
2589              
2590             sub attribute_metaclass;
2591             sub method_metaclass;
2592              
2593             sub constructor_class;
2594             sub destructor_class;
2595              
2596              
2597             sub _construct_meta {
2598 4     4   14 my($class, %args) = @_;
2599              
2600 4         13 $args{attributes} = {};
2601 4         12 $args{methods} = {};
2602 4         10 $args{roles} = [];
2603              
2604 4         6 $args{superclasses} = do {
2605 2     2   11 no strict 'refs';
  2         3  
  2         5738  
2606 4         8 \@{ $args{package} . '::ISA' };
  4         98  
2607             };
2608              
2609 4   66     29 my $self = bless \%args, ref($class) || $class;
2610 4 50       18 if(ref($self) ne __PACKAGE__){
2611 0         0 $self->meta->_initialize_object($self, \%args);
2612             }
2613 4         37 return $self;
2614             }
2615              
2616             sub create_anon_class{
2617 0     0 0 0 my $self = shift;
2618 0         0 return $self->create(undef, @_);
2619             }
2620              
2621             sub is_anon_class;
2622              
2623             sub roles;
2624              
2625             sub calculate_all_roles {
2626 0     0 0 0 my $self = shift;
2627 0         0 my %seen;
2628 0         0 return grep { !$seen{ $_->name }++ }
  0         0  
2629 0         0 map { $_->calculate_all_roles } @{ $self->roles };
  0         0  
2630             }
2631              
2632             sub superclasses {
2633 4     4 0 6 my $self = shift;
2634              
2635 4 100       11 if (@_) {
2636 2         5 foreach my $super(@_){
2637 2         7 Scalar::Random::PP::OO::Util::load_class($super);
2638 2         7 my $meta = Scalar::Random::PP::OO::Util::get_metaclass_by_name($super);
2639              
2640 2 50       9 next if not defined $meta;
2641              
2642 0 0       0 if(Scalar::Random::PP::OO::Util::is_a_metarole($meta)){
2643 0         0 $self->throw_error("You cannot inherit from a Scalar::Random::PP::OO Role ($super)");
2644             }
2645              
2646 0 0       0 next if $self->isa(ref $meta); # _superclass_meta_is_compatible
2647              
2648 0         0 $self->_reconcile_with_superclass_meta($meta);
2649             }
2650 2         4 @{ $self->{superclasses} } = @_;
  2         34  
2651             }
2652              
2653 4         7 return @{ $self->{superclasses} };
  4         16  
2654             }
2655             my @MetaClassTypes = (
2656             'attribute', # Scalar::Random::PP::OO::Meta::Attribute
2657             'method', # Scalar::Random::PP::OO::Meta::Method
2658             'constructor', # Scalar::Random::PP::OO::Meta::Method::Constructor
2659             'destructor', # Scalar::Random::PP::OO::Meta::Method::Destructor
2660             );
2661              
2662             sub _reconcile_with_superclass_meta {
2663 0     0   0 my($self, $other) = @_;
2664              
2665             # find incompatible traits
2666 0         0 my %metaroles;
2667 0         0 foreach my $metaclass_type(@MetaClassTypes){
2668 0   0     0 my $accessor = $self->can($metaclass_type . '_metaclass')
2669             || $self->can($metaclass_type . '_class');
2670              
2671 0         0 my $other_c = $other->$accessor();
2672 0         0 my $self_c = $self->$accessor();
2673              
2674 0 0       0 if(!$self_c->isa($other_c)){
2675 0         0 $metaroles{$metaclass_type}
2676             = [ $self_c->meta->_collect_roles($other_c->meta) ];
2677             }
2678             }
2679              
2680 0         0 $metaroles{class} = [$self->meta->_collect_roles($other->meta)];
2681              
2682             #use Data::Dumper; print Data::Dumper->new([\%metaroles], ['*metaroles'])->Indent(1)->Dump;
2683              
2684 0         0 require Scalar::Random::PP::OO::Util::MetaRole;
2685 0         0 $_[0] = Scalar::Random::PP::OO::Util::MetaRole::apply_metaroles(
2686             for => $self,
2687             class_metaroles => \%metaroles,
2688             );
2689 0         0 return;
2690             }
2691              
2692             sub _collect_roles {
2693 0     0   0 my ($self, $other) = @_;
2694              
2695             # find common ancestor
2696 0         0 my @self_lin_isa = $self->linearized_isa;
2697 0         0 my @other_lin_isa = $other->linearized_isa;
2698              
2699 0         0 my(@self_anon_supers, @other_anon_supers);
2700 0         0 push @self_anon_supers, shift @self_lin_isa while $self_lin_isa[0]->meta->is_anon_class;
2701 0         0 push @other_anon_supers, shift @other_lin_isa while $other_lin_isa[0]->meta->is_anon_class;
2702              
2703 0   0     0 my $common_ancestor = $self_lin_isa[0] eq $other_lin_isa[0] && $self_lin_isa[0];
2704              
2705 0 0       0 if(!$common_ancestor){
2706 0         0 $self->throw_error(sprintf '%s cannot have %s as a super class because of their metaclass incompatibility',
2707             $self->name, $other->name);
2708             }
2709              
2710 0         0 my %seen;
2711 0         0 return sort grep { !$seen{$_}++ } ## no critic
  0         0  
2712 0         0 (map{ $_->name } map{ $_->meta->calculate_all_roles } @self_anon_supers),
  0         0  
2713 0         0 (map{ $_->name } map{ $_->meta->calculate_all_roles } @other_anon_supers),
  0         0  
2714             ;
2715             }
2716              
2717              
2718             sub find_method_by_name{
2719 0     0 0 0 my($self, $method_name) = @_;
2720 0 0       0 defined($method_name)
2721             or $self->throw_error('You must define a method name to find');
2722              
2723 0         0 foreach my $class( $self->linearized_isa ){
2724 0         0 my $method = $self->initialize($class)->get_method($method_name);
2725 0 0       0 return $method if defined $method;
2726             }
2727 0         0 return undef;
2728             }
2729              
2730             sub get_all_methods {
2731 0     0 0 0 my($self) = @_;
2732 0         0 return map{ $self->find_method_by_name($_) } $self->get_all_method_names;
  0         0  
2733             }
2734              
2735             sub get_all_method_names {
2736 0     0 0 0 my $self = shift;
2737 0         0 my %uniq;
2738 0         0 return grep { $uniq{$_}++ == 0 }
  0         0  
2739 0         0 map { Scalar::Random::PP::OO::Meta::Class->initialize($_)->get_method_list() }
2740             $self->linearized_isa;
2741             }
2742              
2743             sub find_attribute_by_name{
2744 0     0 0 0 my($self, $name) = @_;
2745 0         0 my $attr;
2746 0         0 foreach my $class($self->linearized_isa){
2747 0 0       0 my $meta = Scalar::Random::PP::OO::Util::get_metaclass_by_name($class) or next;
2748 0 0       0 $attr = $meta->get_attribute($name) and last;
2749             }
2750 0         0 return $attr;
2751             }
2752              
2753             sub add_attribute {
2754 2     2 0 5 my $self = shift;
2755              
2756 2         4 my($attr, $name);
2757              
2758 2 50       10 if(blessed $_[0]){
2759 0         0 $attr = $_[0];
2760              
2761 0 0       0 $attr->isa('Scalar::Random::PP::OO::Meta::Attribute')
2762             || $self->throw_error("Your attribute must be an instance of Scalar::Random::PP::OO::Meta::Attribute (or a subclass)");
2763              
2764 0         0 $name = $attr->name;
2765             }
2766             else{
2767             # _process_attribute
2768 2         5 $name = shift;
2769              
2770 2 50       11 my %args = (@_ == 1) ? %{$_[0]} : @_;
  0         0  
2771              
2772 2 50       7 defined($name)
2773             or $self->throw_error('You must provide a name for the attribute');
2774              
2775 2 50       9 if ($name =~ s/^\+//) { # inherited attributes
2776 0 0       0 my $inherited_attr = $self->find_attribute_by_name($name)
2777             or $self->throw_error("Could not find an attribute by the name of '$name' to inherit from in ".$self->name);
2778              
2779 0         0 $attr = $inherited_attr->clone_and_inherit_options(%args);
2780             }
2781             else{
2782 2         9 my($attribute_class, @traits) = $self->attribute_metaclass->interpolate_class(\%args);
2783 2 50       8 $args{traits} = \@traits if @traits;
2784              
2785 2         11 $attr = $attribute_class->new($name, %args);
2786             }
2787             }
2788              
2789 2         18 weaken( $attr->{associated_class} = $self );
2790              
2791             # install accessors first
2792 2         11 $attr->install_accessors();
2793              
2794             # then register the attribute to the metaclass
2795 2         3 $attr->{insertion_order} = keys %{ $self->{attributes} };
  2         8  
2796 2         7 $self->{attributes}{$attr->name} = $attr;
2797              
2798 2 50 0     11 if(!$attr->{associated_methods} && ($attr->{is} || '') ne 'bare'){
      33        
2799 0         0 Carp::carp(qq{Attribute ($name) of class }.$self->name
2800             .qq{ has no associated methods (did you mean to provide an "is" argument?)});
2801             }
2802 2         4 return $attr;
2803             }
2804              
2805             sub linearized_isa;
2806              
2807             sub new_object;
2808             sub clone_object;
2809              
2810             sub immutable_options {
2811 0     0 0 0 my ( $self, @args ) = @_;
2812              
2813             return (
2814 0         0 inline_constructor => 1,
2815             inline_destructor => 1,
2816             constructor_name => 'new',
2817             @args,
2818             );
2819             }
2820              
2821             sub make_immutable {
2822 0     0 0 0 my $self = shift;
2823 0         0 my %args = $self->immutable_options(@_);
2824              
2825 0         0 $self->{is_immutable}++;
2826              
2827 0 0       0 if ($args{inline_constructor}) {
2828 0         0 $self->add_method($args{constructor_name} =>
2829             Scalar::Random::PP::OO::Util::load_class($self->constructor_class)
2830             ->_generate_constructor($self, \%args));
2831             }
2832              
2833 0 0       0 if ($args{inline_destructor}) {
2834 0         0 $self->add_method(DESTROY =>
2835             Scalar::Random::PP::OO::Util::load_class($self->destructor_class)
2836             ->_generate_destructor($self, \%args));
2837             }
2838              
2839             # Moose's make_immutable returns true allowing calling code to skip setting an explicit true value
2840             # at the end of a source file.
2841 0         0 return 1;
2842             }
2843              
2844             sub make_mutable {
2845 0     0 0 0 my($self) = @_;
2846 0         0 $self->{is_immutable} = 0;
2847 0         0 return;
2848             }
2849              
2850             sub is_immutable;
2851 0     0 0 0 sub is_mutable { !$_[0]->is_immutable }
2852              
2853             sub _install_modifier {
2854 0     0   0 my( $self, $type, $name, $code ) = @_;
2855 0         0 my $into = $self->name;
2856              
2857 0 0       0 my $original = $into->can($name)
2858             or $self->throw_error("The method '$name' was not found in the inheritance hierarchy for $into");
2859              
2860 0         0 my $modifier_table = $self->{modifiers}{$name};
2861              
2862 0 0       0 if(!$modifier_table){
2863 0         0 my(@before, @after, @around);
2864 0         0 my $cache = $original;
2865             my $modified = sub {
2866 0 0   0   0 if(@before) {
2867 0         0 for my $c (@before) { $c->(@_) }
  0         0  
2868             }
2869 0 0       0 unless(@after) {
2870 0         0 return $cache->(@_);
2871             }
2872              
2873 0 0       0 if(wantarray){ # list context
    0          
2874 0         0 my @rval = $cache->(@_);
2875              
2876 0         0 for my $c(@after){ $c->(@_) }
  0         0  
2877 0         0 return @rval;
2878             }
2879             elsif(defined wantarray){ # scalar context
2880 0         0 my $rval = $cache->(@_);
2881              
2882 0         0 for my $c(@after){ $c->(@_) }
  0         0  
2883 0         0 return $rval;
2884             }
2885             else{ # void context
2886 0         0 $cache->(@_);
2887              
2888 0         0 for my $c(@after){ $c->(@_) }
  0         0  
2889 0         0 return;
2890             }
2891 0         0 };
2892              
2893 0         0 $self->{modifiers}{$name} = $modifier_table = {
2894             original => $original,
2895              
2896             before => \@before,
2897             after => \@after,
2898             around => \@around,
2899              
2900             cache => \$cache, # cache for around modifiers
2901             };
2902              
2903 0         0 $self->add_method($name => $modified);
2904             }
2905              
2906 0 0       0 if($type eq 'before'){
    0          
2907 0         0 unshift @{$modifier_table->{before}}, $code;
  0         0  
2908             }
2909             elsif($type eq 'after'){
2910 0         0 push @{$modifier_table->{after}}, $code;
  0         0  
2911             }
2912             else{ # around
2913 0         0 push @{$modifier_table->{around}}, $code;
  0         0  
2914              
2915 0         0 my $next = ${ $modifier_table->{cache} };
  0         0  
2916 0     0   0 ${ $modifier_table->{cache} } = sub{ $code->($next, @_) };
  0         0  
  0         0  
2917             }
2918              
2919 0         0 return;
2920             }
2921              
2922             sub add_before_method_modifier {
2923 0     0 0 0 my ( $self, $name, $code ) = @_;
2924 0         0 $self->_install_modifier( 'before', $name, $code );
2925             }
2926              
2927             sub add_around_method_modifier {
2928 0     0 0 0 my ( $self, $name, $code ) = @_;
2929 0         0 $self->_install_modifier( 'around', $name, $code );
2930             }
2931              
2932             sub add_after_method_modifier {
2933 0     0 0 0 my ( $self, $name, $code ) = @_;
2934 0         0 $self->_install_modifier( 'after', $name, $code );
2935             }
2936              
2937             sub add_override_method_modifier {
2938 0     0 0 0 my ($self, $name, $code) = @_;
2939              
2940 0 0       0 if($self->has_method($name)){
2941 0         0 $self->throw_error("Cannot add an override method if a local method is already present");
2942             }
2943              
2944 0         0 my $package = $self->name;
2945              
2946 0 0       0 my $super_body = $package->can($name)
2947             or $self->throw_error("You cannot override '$name' because it has no super method");
2948              
2949             $self->add_method($name => sub {
2950 0     0   0 local $Scalar::Random::PP::OO::SUPER_PACKAGE = $package;
2951 0         0 local $Scalar::Random::PP::OO::SUPER_BODY = $super_body;
2952 0         0 local @Scalar::Random::PP::OO::SUPER_ARGS = @_;
2953              
2954 0         0 $code->(@_);
2955 0         0 });
2956 0         0 return;
2957             }
2958              
2959             sub add_augment_method_modifier {
2960 0     0 0 0 my ($self, $name, $code) = @_;
2961 0 0       0 if($self->has_method($name)){
2962 0         0 $self->throw_error("Cannot add an augment method if a local method is already present");
2963             }
2964              
2965 0 0       0 my $super = $self->find_method_by_name($name)
2966             or $self->throw_error("You cannot augment '$name' because it has no super method");
2967              
2968 0         0 my $super_package = $super->package_name;
2969 0         0 my $super_body = $super->body;
2970              
2971             $self->add_method($name => sub{
2972 0     0   0 local $Scalar::Random::PP::OO::INNER_BODY{$super_package} = $code;
2973 0         0 local $Scalar::Random::PP::OO::INNER_ARGS{$super_package} = [@_];
2974 0         0 $super_body->(@_);
2975 0         0 });
2976 0         0 return;
2977             }
2978              
2979             sub does_role {
2980 0     0 0 0 my ($self, $role_name) = @_;
2981              
2982 0 0       0 (defined $role_name)
2983             || $self->throw_error("You must supply a role name to look for");
2984              
2985 0 0       0 $role_name = $role_name->name if ref $role_name;
2986              
2987 0         0 for my $class ($self->linearized_isa) {
2988 0 0       0 my $meta = Scalar::Random::PP::OO::Util::get_metaclass_by_name($class)
2989             or next;
2990              
2991 0         0 for my $role (@{ $meta->roles }) {
  0         0  
2992              
2993 0 0       0 return 1 if $role->does_role($role_name);
2994             }
2995             }
2996              
2997 0         0 return 0;
2998             }
2999              
3000             # Contents of Mouse::Meta::Method
3001             package Scalar::Random::PP::OO::Meta::Method;
3002 2     2   12 use Scalar::Random::PP::OO::Util qw(:meta); # enables strict and warnings
  2         4  
  2         10  
3003 2     2   18 use Scalar::Util ();
  2         4  
  2         124  
3004              
3005             use overload
3006             '==' => '_equal',
3007             'eq' => '_equal',
3008 0     0   0 '&{}' => sub{ $_[0]->body },
3009 2         23 fallback => 1,
3010 2     2   15 ;
  2         3  
3011              
3012             sub wrap{
3013 0     0 0 0 my $class = shift;
3014              
3015 0         0 return $class->_new(@_);
3016             }
3017              
3018             sub _new{
3019 0     0   0 my($class, %args) = @_;
3020 0         0 my $self = bless \%args, $class;
3021              
3022 0 0       0 if($class ne __PACKAGE__){
3023 0         0 $self->meta->_initialize_object($self, \%args);
3024             }
3025 0         0 return $self;
3026             }
3027              
3028 0     0 0 0 sub body { $_[0]->{body} }
3029 0     0 0 0 sub name { $_[0]->{name} }
3030 0     0 0 0 sub package_name { $_[0]->{package} }
3031 0     0 0 0 sub associated_metaclass { $_[0]->{associated_metaclass} }
3032              
3033             sub fully_qualified_name {
3034 0     0 0 0 my($self) = @_;
3035 0         0 return $self->package_name . '::' . $self->name;
3036             }
3037              
3038             # for Moose compat
3039             sub _equal {
3040 0     0   0 my($l, $r) = @_;
3041              
3042 0   0     0 return Scalar::Util::blessed($r)
3043             && $l->body == $r->body
3044             && $l->name eq $r->name
3045             && $l->package_name eq $r->package_name;
3046             }
3047              
3048             # Contents of Mouse::Meta::Method::Accessor
3049             package Scalar::Random::PP::OO::Meta::Method::Accessor;
3050 2     2   908 use Scalar::Random::PP::OO::Util qw(:meta); # enables strict and warnings
  2         4  
  2         6  
3051              
3052             sub _inline_slot{
3053 2     2   5 my(undef, $self_var, $attr_name) = @_;
3054 2         15 return sprintf '%s->{q{%s}}', $self_var, $attr_name;
3055             }
3056              
3057             sub _generate_accessor_any{
3058 2     2   4 my($method_class, $type, $attribute, $class) = @_;
3059              
3060 2         8 my $name = $attribute->name;
3061 2         8 my $default = $attribute->default;
3062 2         9 my $constraint = $attribute->type_constraint;
3063 2         8 my $builder = $attribute->builder;
3064 2         7 my $trigger = $attribute->trigger;
3065 2         7 my $is_weak = $attribute->is_weak_ref;
3066 2         7 my $should_deref = $attribute->should_auto_deref;
3067 2   33     9 my $should_coerce = (defined($constraint) && $constraint->has_coercion && $attribute->should_coerce);
3068              
3069 2 50       8 my $compiled_type_constraint = defined($constraint) ? $constraint->_compiled_type_constraint : undef;
3070              
3071 2         2 my $self = '$_[0]';
3072 2         9 my $slot = $method_class->_inline_slot($self, $name);;
3073              
3074 2         7 my $accessor = sprintf(qq{package %s;\n#line 1 "%s-accessor for %s (%s)"\n}, $class->name, $type, $name, __FILE__)
3075             . "sub {\n";
3076              
3077 2 50 33     20 if ($type eq 'rw' || $type eq 'wo') {
    50          
3078 0 0       0 if($type eq 'rw'){
3079 0         0 $accessor .=
3080             'if (scalar(@_) >= 2) {' . "\n";
3081             }
3082             else{ # writer
3083 0         0 $accessor .=
3084             'if(@_ < 2){ Carp::confess("Not enough arguments for the writer of '.$name.'") }'.
3085             '{' . "\n";
3086             }
3087            
3088 0         0 my $value = '$_[1]';
3089              
3090 0 0       0 if (defined $constraint) {
3091 0 0       0 if ($should_coerce) {
3092 0         0 $accessor .=
3093             "\n".
3094             'my $val = $constraint->coerce('.$value.');';
3095 0         0 $value = '$val';
3096             }
3097             $accessor .=
3098 0         0 "\n".
3099             '$compiled_type_constraint->('.$value.') or
3100             $attribute->_throw_type_constraint_error('.$value.', $constraint);' . "\n";
3101             }
3102              
3103             # if there's nothing left to do for the attribute we can return during
3104             # this setter
3105 0 0 0     0 $accessor .= 'return ' if !$is_weak && !$trigger && !$should_deref;
      0        
3106              
3107 0         0 $accessor .= "$slot = $value;\n";
3108              
3109 0 0       0 if ($is_weak) {
3110 0         0 $accessor .= "Scalar::Util::weaken($slot) if ref $slot;\n";
3111             }
3112              
3113 0 0       0 if ($trigger) {
3114 0         0 $accessor .= '$trigger->('.$self.', '.$value.');' . "\n";
3115             }
3116              
3117 0         0 $accessor .= "}\n";
3118             }
3119             elsif($type eq 'ro') {
3120 2         6 $accessor .= 'Carp::confess("Cannot assign a value to a read-only accessor") if scalar(@_) >= 2;' . "\n";
3121             }
3122             else{
3123 0         0 $class->throw_error("Unknown accessor type '$type'");
3124             }
3125              
3126 2 50 33     9 if ($attribute->is_lazy and $type ne 'wo') {
3127 0         0 my $value;
3128              
3129 0 0       0 if (defined $builder){
    0          
3130 0         0 $value = "$self->\$builder()";
3131             }
3132             elsif (ref($default) eq 'CODE'){
3133 0         0 $value = "$self->\$default()";
3134             }
3135             else{
3136 0         0 $value = '$default';
3137             }
3138              
3139 0 0       0 $accessor .= "els" if $type eq 'rw';
3140 0         0 $accessor .= "if(!exists $slot){\n";
3141 0 0       0 if($should_coerce){
    0          
3142 0         0 $accessor .= "$slot = \$constraint->coerce($value)";
3143             }
3144             elsif(defined $constraint){
3145 0         0 $accessor .= "my \$tmp = $value;\n";
3146              
3147 0         0 $accessor .= "\$compiled_type_constraint->(\$tmp)";
3148 0         0 $accessor .= " || \$attribute->_throw_type_constraint_error(\$tmp, \$constraint);\n";
3149 0         0 $accessor .= "$slot = \$tmp;\n";
3150             }
3151             else{
3152 0         0 $accessor .= "$slot = $value;\n";
3153             }
3154 0 0       0 if ($is_weak) {
3155 0         0 $accessor .= "Scalar::Util::weaken($slot) if ref $slot;\n";
3156             }
3157 0         0 $accessor .= "}\n";
3158             }
3159              
3160 2 50       7 if ($should_deref) {
3161 0 0       0 if ($constraint->is_a_type_of('ArrayRef')) {
    0          
3162 0         0 $accessor .= "return \@{ $slot || [] } if wantarray;\n";
3163             }
3164             elsif($constraint->is_a_type_of('HashRef')){
3165 0         0 $accessor .= "return \%{ $slot || {} } if wantarray;\n";
3166             }
3167             else{
3168 0         0 $class->throw_error("Can not auto de-reference the type constraint " . $constraint->name);
3169             }
3170             }
3171              
3172 2         7 $accessor .= "return $slot;\n}\n";
3173              
3174             #print $accessor, "\n";
3175 2         4 my $code;
3176 2         3 my $e = do{
3177 2         4 local $@;
3178 2         626 $code = eval $accessor;
3179 2         27 $@;
3180             };
3181 2 50       15 die $e if $e;
3182              
3183 2         8 return $code;
3184             }
3185              
3186             sub _generate_accessor{
3187             #my($self, $attribute, $metaclass) = @_;
3188 0     0   0 my $self = shift;
3189 0         0 return $self->_generate_accessor_any(rw => @_);
3190             }
3191              
3192             sub _generate_reader {
3193             #my($self, $attribute, $metaclass) = @_;
3194 2     2   4 my $self = shift;
3195 2         11 return $self->_generate_accessor_any(ro => @_);
3196             }
3197              
3198             sub _generate_writer {
3199             #my($self, $attribute, $metaclass) = @_;
3200 0     0   0 my $self = shift;
3201 0         0 return $self->_generate_accessor_any(wo => @_);
3202             }
3203              
3204             sub _generate_predicate {
3205             #my($self, $attribute, $metaclass) = @_;
3206 0     0   0 my(undef, $attribute) = @_;
3207              
3208 0         0 my $slot = $attribute->name;
3209             return sub{
3210 0     0   0 return exists $_[0]->{$slot};
3211 0         0 };
3212             }
3213              
3214             sub _generate_clearer {
3215             #my($self, $attribute, $metaclass) = @_;
3216 0     0   0 my(undef, $attribute) = @_;
3217              
3218 0         0 my $slot = $attribute->name;
3219             return sub{
3220 0     0   0 delete $_[0]->{$slot};
3221 0         0 };
3222             }
3223              
3224             # Contents of Mouse::Meta::Method::Constructor
3225             package Scalar::Random::PP::OO::Meta::Method::Constructor;
3226 2     2   11 use Scalar::Random::PP::OO::Util qw(:meta); # enables strict and warnings
  2         3  
  2         7  
3227              
3228             sub _inline_slot{
3229 0     0   0 my(undef, $self_var, $attr_name) = @_;
3230 0         0 return sprintf '%s->{q{%s}}', $self_var, $attr_name;
3231             }
3232              
3233             sub _generate_constructor {
3234 0     0   0 my ($class, $metaclass, $args) = @_;
3235              
3236 0         0 my $associated_metaclass_name = $metaclass->name;
3237              
3238 0         0 my @attrs = $metaclass->get_all_attributes;
3239              
3240 0         0 my $buildall = $class->_generate_BUILDALL($metaclass);
3241 0         0 my $buildargs = $class->_generate_BUILDARGS($metaclass);
3242 0         0 my $processattrs = $class->_generate_processattrs($metaclass, \@attrs);
3243              
3244 0 0       0 my @checks = map { $_ && $_->_compiled_type_constraint }
  0         0  
3245 0         0 map { $_->type_constraint } @attrs;
3246              
3247 0         0 my $source = sprintf("#line %d %s\n", __LINE__, __FILE__).<<"...";
3248             sub \{
3249             my \$class = shift;
3250             return \$class->Scalar::Random::PP::OO::Object::new(\@_)
3251             if \$class ne q{$associated_metaclass_name};
3252             # BUILDARGS
3253             $buildargs;
3254             my \$instance = bless {}, \$class;
3255             # process attributes
3256             $processattrs;
3257             # BUILDALL
3258             $buildall;
3259             return \$instance;
3260             }
3261             ...
3262             #warn $source;
3263 0         0 my $code;
3264 0         0 my $e = do{
3265 0         0 local $@;
3266 0         0 $code = eval $source;
3267 0         0 $@;
3268             };
3269 0 0       0 die $e if $e;
3270 0         0 return $code;
3271             }
3272              
3273             sub _generate_processattrs {
3274 0     0   0 my ($method_class, $metaclass, $attrs) = @_;
3275 0         0 my @res;
3276              
3277             my $has_triggers;
3278 0         0 my $strict = $metaclass->strict_constructor;
3279              
3280 0 0       0 if($strict){
3281 0         0 push @res, 'my $used = 0;';
3282             }
3283              
3284 0         0 for my $index (0 .. @$attrs - 1) {
3285 0         0 my $code = '';
3286              
3287 0         0 my $attr = $attrs->[$index];
3288 0         0 my $key = $attr->name;
3289              
3290 0         0 my $init_arg = $attr->init_arg;
3291 0         0 my $type_constraint = $attr->type_constraint;
3292 0         0 my $is_weak_ref = $attr->is_weak_ref;
3293 0         0 my $need_coercion;
3294              
3295 0         0 my $instance_slot = $method_class->_inline_slot('$instance', $key);
3296 0         0 my $attr_var = "\$attrs[$index]";
3297 0         0 my $constraint_var;
3298              
3299 0 0       0 if(defined $type_constraint){
3300 0         0 $constraint_var = "$attr_var\->{type_constraint}";
3301 0   0     0 $need_coercion = ($attr->should_coerce && $type_constraint->has_coercion);
3302             }
3303              
3304 0         0 $code .= "# initialize $key\n";
3305              
3306 0         0 my $post_process = '';
3307 0 0       0 if(defined $type_constraint){
3308 0         0 $post_process .= "\$checks[$index]->($instance_slot)";
3309 0         0 $post_process .= " or $attr_var->_throw_type_constraint_error($instance_slot, $constraint_var);\n";
3310             }
3311 0 0       0 if($is_weak_ref){
3312 0         0 $post_process .= "Scalar::Util::weaken($instance_slot) if ref $instance_slot;\n";
3313             }
3314              
3315 0 0       0 if (defined $init_arg) {
3316 0         0 my $value = "\$args->{q{$init_arg}}";
3317              
3318 0         0 $code .= "if (exists $value) {\n";
3319              
3320 0 0       0 if($need_coercion){
3321 0         0 $value = "$constraint_var->coerce($value)";
3322             }
3323              
3324 0         0 $code .= "$instance_slot = $value;\n";
3325 0         0 $code .= $post_process;
3326              
3327 0 0       0 if ($attr->has_trigger) {
3328 0         0 $has_triggers++;
3329 0         0 $code .= "push \@triggers, [$attr_var\->{trigger}, $instance_slot];\n";
3330             }
3331              
3332 0 0       0 if ($strict){
3333 0         0 $code .= '++$used;' . "\n";
3334             }
3335              
3336 0         0 $code .= "\n} else {\n"; # $value exists
3337             }
3338              
3339 0 0 0     0 if ($attr->has_default || $attr->has_builder) {
    0          
3340 0 0       0 unless ($attr->is_lazy) {
3341 0         0 my $default = $attr->default;
3342 0         0 my $builder = $attr->builder;
3343              
3344 0         0 my $value;
3345 0 0       0 if (defined($builder)) {
    0          
    0          
3346 0         0 $value = "\$instance->$builder()";
3347             }
3348             elsif (ref($default) eq 'CODE') {
3349 0         0 $value = "$attr_var\->{default}->(\$instance)";
3350             }
3351             elsif (defined($default)) {
3352 0         0 $value = "$attr_var\->{default}";
3353             }
3354             else {
3355 0         0 $value = 'undef';
3356             }
3357              
3358 0 0       0 if($need_coercion){
3359 0         0 $value = "$constraint_var->coerce($value)";
3360             }
3361              
3362 0         0 $code .= "$instance_slot = $value;\n";
3363 0 0       0 if($is_weak_ref){
3364 0         0 $code .= "Scalar::Util::weaken($instance_slot);\n";
3365             }
3366             }
3367             }
3368             elsif ($attr->is_required) {
3369 0         0 $code .= "Carp::confess('Attribute ($key) is required');";
3370             }
3371              
3372 0 0       0 $code .= "}\n" if defined $init_arg;
3373              
3374 0         0 push @res, $code;
3375             }
3376              
3377 0 0       0 if($strict){
3378 0         0 push @res, q{if($used < keys %{$args})}
3379             . q{{ $metaclass->_report_unknown_args(\@attrs, $args) }};
3380             }
3381              
3382 0 0       0 if($metaclass->is_anon_class){
3383 0         0 push @res, q{$instance->{__METACLASS__} = $metaclass;};
3384             }
3385              
3386 0 0       0 if($has_triggers){
3387 0         0 unshift @res, q{my @triggers;};
3388 0         0 push @res, q{$_->[0]->($instance, $_->[1]) for @triggers;};
3389             }
3390              
3391 0         0 return join "\n", @res;
3392             }
3393              
3394             sub _generate_BUILDARGS {
3395 0     0   0 my(undef, $metaclass) = @_;
3396              
3397 0         0 my $class = $metaclass->name;
3398 0 0 0     0 if ( $class->can('BUILDARGS') && $class->can('BUILDARGS') != \&Scalar::Random::PP::OO::Object::BUILDARGS ) {
3399 0         0 return 'my $args = $class->BUILDARGS(@_)';
3400             }
3401              
3402 0         0 return <<'...';
3403             my $args;
3404             if ( scalar @_ == 1 ) {
3405             ( ref( $_[0] ) eq 'HASH' )
3406             || Carp::confess "Single parameters to new() must be a HASH ref";
3407             $args = +{ %{ $_[0] } };
3408             }
3409             else {
3410             $args = +{@_};
3411             }
3412             ...
3413             }
3414              
3415             sub _generate_BUILDALL {
3416 0     0   0 my (undef, $metaclass) = @_;
3417              
3418 0 0       0 return '' unless $metaclass->name->can('BUILD');
3419              
3420 0         0 my @code;
3421 0         0 for my $class ($metaclass->linearized_isa) {
3422 0 0       0 if (Scalar::Random::PP::OO::Util::get_code_ref($class, 'BUILD')) {
3423 0         0 unshift @code, qq{${class}::BUILD(\$instance, \$args);};
3424             }
3425             }
3426 0         0 return join "\n", @code;
3427             }
3428              
3429             # Contents of Mouse::Meta::Method::Delegation
3430             package Scalar::Random::PP::OO::Meta::Method::Delegation;
3431 2     2   35 use Scalar::Random::PP::OO::Util qw(:meta); # enables strict and warnings
  2         3  
  2         15  
3432 2     2   12 use Scalar::Util;
  2         5  
  2         860  
3433              
3434             sub _generate_delegation{
3435 0     0   0 my (undef, $attr, $handle_name, $method_to_call) = @_;
3436              
3437 0         0 my @curried_args;
3438 0 0       0 if(ref($method_to_call) eq 'ARRAY'){
3439 0         0 ($method_to_call, @curried_args) = @{$method_to_call};
  0         0  
3440             }
3441              
3442             # If it has a reader, we must use it to make method modifiers work
3443 0   0     0 my $reader = $attr->get_read_method() || $attr->get_read_method_ref();
3444              
3445 0         0 my $can_be_optimized = $attr->{_method_delegation_can_be_optimized};
3446              
3447 0 0       0 if(!defined $can_be_optimized){
3448 0         0 my $tc = $attr->type_constraint;
3449              
3450 0   0     0 $attr->{_method_delegation_can_be_optimized} =
3451             (defined($tc) && $tc->is_a_type_of('Object'))
3452             && ($attr->is_required || $attr->has_default || $attr->has_builder)
3453             && ($attr->is_lazy || !$attr->has_clearer);
3454             }
3455              
3456 0 0       0 if($can_be_optimized){
3457             # need not check the attribute value
3458             return sub {
3459 0     0   0 return shift()->$reader()->$method_to_call(@curried_args, @_);
3460 0         0 };
3461             }
3462             else {
3463             # need to check the attribute value
3464             return sub {
3465 0     0   0 my $instance = shift;
3466 0         0 my $proxy = $instance->$reader();
3467              
3468 0 0 0     0 my $error = !defined($proxy) ? ' is not defined'
    0          
3469             : ref($proxy) && !Scalar::Util::blessed($proxy) ? qq{ is not an object (got '$proxy')}
3470             : undef;
3471 0 0       0 if ($error) {
3472 0         0 $instance->meta->throw_error(
3473             "Cannot delegate $handle_name to $method_to_call because "
3474             . "the value of "
3475             . $attr->name
3476             . $error
3477             );
3478             }
3479 0         0 $proxy->$method_to_call(@curried_args, @_);
3480 0         0 };
3481             }
3482             }
3483              
3484              
3485             # Contents of Mouse::Meta::Method::Destructor
3486             package Scalar::Random::PP::OO::Meta::Method::Destructor;
3487 2     2   13 use Scalar::Random::PP::OO::Util qw(:meta); # enables strict and warnings
  2         5  
  2         23  
3488              
3489 0     0   0 sub _empty_DESTROY{ }
3490              
3491             sub _generate_destructor{
3492 0     0   0 my (undef, $metaclass) = @_;
3493              
3494 0 0       0 if(!$metaclass->name->can('DEMOLISH')){
3495 0         0 return \&_empty_DESTROY;
3496             }
3497              
3498 0         0 my $demolishall = '';
3499 0         0 for my $class ($metaclass->linearized_isa) {
3500 0 0       0 if (Scalar::Random::PP::OO::Util::get_code_ref($class, 'DEMOLISH')) {
3501 0         0 $demolishall .= sprintf "%s::DEMOLISH(\$self, \$Scalar::Random::PP::OO::Util::in_global_destruction);\n",
3502             $class,
3503             }
3504             }
3505              
3506 0         0 my $source = sprintf(<<'END_DESTROY', __LINE__, __FILE__, $demolishall);
3507             #line %d %s
3508             sub {
3509             my $self = shift;
3510             my $e = do{
3511             local $?;
3512             local $@;
3513             eval{
3514             # demolishall
3515             %s;
3516             };
3517             $@;
3518             };
3519             no warnings 'misc';
3520             die $e if $e; # rethrow
3521             }
3522             END_DESTROY
3523              
3524 0         0 my $code;
3525 0         0 my $e = do{
3526 0         0 local $@;
3527 0         0 $code = eval $source;
3528 0         0 $@;
3529             };
3530 0 0       0 die $e if $e;
3531 0         0 return $code;
3532             }
3533              
3534             # Contents of Mouse::Meta::Module
3535             package Scalar::Random::PP::OO::Meta::Module;
3536 2     2   1260 use Scalar::Random::PP::OO::Util qw/:meta get_code_package get_code_ref not_supported/; # enables strict and warnings
  2         4  
  2         9  
3537 2     2   9 no warnings 'once';
  2         4  
  2         64  
3538              
3539 2     2   9 use Carp ();
  2         3  
  2         33  
3540 2     2   9 use Scalar::Util ();
  2         3  
  2         2808  
3541              
3542             my %METAS;
3543              
3544             if(Scalar::Random::PP::OO::Util::MOUSE_XS){
3545             # register meta storage for performance
3546             Scalar::Random::PP::OO::Util::__register_metaclass_storage(\%METAS, 0);
3547              
3548             # ensure thread safety
3549             *CLONE = sub { Scalar::Random::PP::OO::Util::__register_metaclass_storage(\%METAS, 1) };
3550             }
3551              
3552             sub _metaclass_cache { # DEPRECATED
3553 0     0   0 my($self, $name) = @_;
3554 0         0 Carp::cluck('_metaclass_cache() has been deprecated. Use Scalar::Random::PP::OO::Util::get_metaclass_by_name() instead');
3555 0         0 return $METAS{$name};
3556             }
3557              
3558             sub initialize {
3559 16     16 0 70 my($class, $package_name, @args) = @_;
3560              
3561 16 50 33     90 ($package_name && !ref($package_name))
3562             || $class->throw_error("You must pass a package name and it cannot be blessed");
3563              
3564 16   66     120 return $METAS{$package_name}
3565             ||= $class->_construct_meta(package => $package_name, @args);
3566             }
3567              
3568             sub reinitialize {
3569 0     0 0 0 my($class, $package_name, @args) = @_;
3570              
3571 0 0       0 $package_name = $package_name->name if ref $package_name;
3572              
3573 0 0 0     0 ($package_name && !ref($package_name))
3574             || $class->throw_error("You must pass a package name and it cannot be blessed");
3575              
3576 0         0 delete $METAS{$package_name};
3577 0         0 return $class->initialize($package_name, @args);
3578             }
3579              
3580             sub _class_of{
3581 0     0   0 my($class_or_instance) = @_;
3582 0 0       0 return undef unless defined $class_or_instance;
3583 0   0     0 return $METAS{ ref($class_or_instance) || $class_or_instance };
3584             }
3585              
3586             # Means of accessing all the metaclasses that have
3587             # been initialized thus far
3588             #sub _get_all_metaclasses { %METAS }
3589 0     0   0 sub _get_all_metaclass_instances { values %METAS }
3590 0     0   0 sub _get_all_metaclass_names { keys %METAS }
3591 2     2   4 sub _get_metaclass_by_name { $METAS{$_[0]} }
3592             #sub _store_metaclass_by_name { $METAS{$_[0]} = $_[1] }
3593             #sub _weaken_metaclass { weaken($METAS{$_[0]}) }
3594             #sub _does_metaclass_exist { defined $METAS{$_[0]} }
3595             #sub _remove_metaclass_by_name { delete $METAS{$_[0]} }
3596              
3597             sub name;
3598              
3599             sub namespace;
3600              
3601             # add_attribute is an abstract method
3602              
3603             sub get_attribute_map { # DEPRECATED
3604 0     0 0   Carp::cluck('get_attribute_map() has been deprecated. Use get_attribute_list() and get_attribute() instead');
3605 0           return $_[0]->{attributes};
3606             }
3607              
3608 0     0 0   sub has_attribute { exists $_[0]->{attributes}->{$_[1]} }
3609 0     0 0   sub get_attribute { $_[0]->{attributes}->{$_[1]} }
3610 0     0 0   sub remove_attribute { delete $_[0]->{attributes}->{$_[1]} }
3611              
3612 0     0 0   sub get_attribute_list{ keys %{$_[0]->{attributes}} }
  0            
3613              
3614             # XXX: for backward compatibility
3615             my %foreign = map{ $_ => undef } qw(
3616             Scalar::Random::PP::OO Scalar::Random::PP::OO::Role Scalar::Random::PP::OO::Util Scalar::Random::PP::OO::Util::TypeConstraints
3617             Carp Scalar::Util List::Util
3618             );
3619             sub _code_is_mine{
3620             # my($self, $code) = @_;
3621              
3622 0     0     return !exists $foreign{ get_code_package($_[1]) };
3623             }
3624              
3625             sub add_method;
3626              
3627             sub has_method {
3628 0     0 0   my($self, $method_name) = @_;
3629              
3630 0 0         defined($method_name)
3631             or $self->throw_error('You must define a method name');
3632              
3633 0   0       return defined($self->{methods}{$method_name}) || do{
3634             my $code = get_code_ref($self->{package}, $method_name);
3635             $code && $self->_code_is_mine($code);
3636             };
3637             }
3638              
3639             sub get_method_body {
3640 0     0 0   my($self, $method_name) = @_;
3641              
3642 0 0         defined($method_name)
3643             or $self->throw_error('You must define a method name');
3644              
3645 0   0       return $self->{methods}{$method_name} ||= do{
3646 0           my $code = get_code_ref($self->{package}, $method_name);
3647 0 0 0       $code && $self->_code_is_mine($code) ? $code : undef;
3648             };
3649             }
3650              
3651             sub get_method{
3652 0     0 0   my($self, $method_name) = @_;
3653              
3654 0 0         if(my $code = $self->get_method_body($method_name)){
3655 0           return Scalar::Random::PP::OO::Util::load_class($self->method_metaclass)->wrap(
3656             body => $code,
3657             name => $method_name,
3658             package => $self->name,
3659             associated_metaclass => $self,
3660             );
3661             }
3662              
3663 0           return undef;
3664             }
3665              
3666             sub get_method_list {
3667 0     0 0   my($self) = @_;
3668              
3669 0           return grep { $self->has_method($_) } keys %{ $self->namespace };
  0            
  0            
3670             }
3671              
3672             sub _collect_methods { # Scalar::Random::PP::OO specific
3673 0     0     my($meta, @args) = @_;
3674              
3675 0           my @methods;
3676 0           foreach my $arg(@args){
3677 0 0         if(my $type = ref $arg){
3678 0 0         if($type eq 'Regexp'){
    0          
3679 0           push @methods, grep { $_ =~ $arg } $meta->get_all_method_names;
  0            
3680             }
3681             elsif($type eq 'ARRAY'){
3682 0           push @methods, @{$arg};
  0            
3683             }
3684             else{
3685 0           my $subname = ( caller(1) )[3];
3686 0           $meta->throw_error(
3687             sprintf(
3688             'Methods passed to %s must be provided as a list, ArrayRef or regular expression, not %s',
3689             $subname,
3690             $type,
3691             )
3692             );
3693             }
3694             }
3695             else{
3696 0           push @methods, $arg;
3697             }
3698             }
3699 0           return @methods;
3700             }
3701              
3702             my $ANON_SERIAL = 0; # anonymous class/role id
3703             my %IMMORTALS; # immortal anonymous classes
3704              
3705             sub create {
3706 0     0 0   my($self, $package_name, %options) = @_;
3707              
3708 0   0       my $class = ref($self) || $self;
3709 0 0         $self->throw_error('You must pass a package name') if @_ < 2;
3710              
3711 0           my $superclasses;
3712 0 0         if(exists $options{superclasses}){
3713 0 0         if(Scalar::Random::PP::OO::Util::is_a_metarole($self)){
3714 0           delete $options{superclasses};
3715             }
3716             else{
3717 0           $superclasses = delete $options{superclasses};
3718 0 0         (ref $superclasses eq 'ARRAY')
3719             || $self->throw_error("You must pass an ARRAY ref of superclasses");
3720             }
3721             }
3722              
3723 0           my $attributes = delete $options{attributes};
3724 0 0         if(defined $attributes){
3725 0 0 0       (ref $attributes eq 'ARRAY' || ref $attributes eq 'HASH')
3726             || $self->throw_error("You must pass an ARRAY ref of attributes");
3727             }
3728 0           my $methods = delete $options{methods};
3729 0 0         if(defined $methods){
3730 0 0         (ref $methods eq 'HASH')
3731             || $self->throw_error("You must pass a HASH ref of methods");
3732             }
3733 0           my $roles = delete $options{roles};
3734 0 0         if(defined $roles){
3735 0 0         (ref $roles eq 'ARRAY')
3736             || $self->throw_error("You must pass an ARRAY ref of roles");
3737             }
3738 0           my $mortal;
3739             my $cache_key;
3740              
3741 0 0         if(!defined $package_name){ # anonymous
3742 0           $mortal = !$options{cache};
3743              
3744             # anonymous but immortal
3745 0 0         if(!$mortal){
3746             # something like Super::Class|Super::Class::2=Role|Role::1
3747 0 0         $cache_key = join '=' => (
3748 0 0         join('|', @{$superclasses || []}),
3749 0           join('|', sort @{$roles || []}),
3750             );
3751 0 0         return $IMMORTALS{$cache_key} if exists $IMMORTALS{$cache_key};
3752             }
3753 0           $options{anon_serial_id} = ++$ANON_SERIAL;
3754 0           $package_name = $class . '::__ANON__::' . $ANON_SERIAL;
3755             }
3756              
3757             # instantiate a module
3758             {
3759 2     2   10 no strict 'refs';
  2         4  
  2         1080  
  0            
3760 0 0         ${ $package_name . '::VERSION' } = delete $options{version} if exists $options{version};
  0            
3761 0 0         ${ $package_name . '::AUTHORITY' } = delete $options{authority} if exists $options{authority};
  0            
3762             }
3763              
3764 0           my $meta = $self->initialize( $package_name, %options);
3765              
3766 0 0         Scalar::Util::weaken $METAS{$package_name}
3767             if $mortal;
3768              
3769             $meta->add_method(meta => sub {
3770 0   0 0     $self->initialize(ref($_[0]) || $_[0]);
3771 0           });
3772              
3773 0 0         $meta->superclasses(@{$superclasses})
  0            
3774             if defined $superclasses;
3775              
3776             # NOTE:
3777             # process attributes first, so that they can
3778             # install accessors, but locally defined methods
3779             # can then overwrite them. It is maybe a little odd, but
3780             # I think this should be the order of things.
3781 0 0         if (defined $attributes) {
3782 0 0         if(ref($attributes) eq 'ARRAY'){
3783             # array of Scalar::Random::PP::OO::Meta::Attribute
3784 0           foreach my $attr (@{$attributes}) {
  0            
3785 0           $meta->add_attribute($attr);
3786             }
3787             }
3788             else{
3789             # hash map of name and attribute spec pairs
3790 0           while(my($name, $attr) = each %{$attributes}){
  0            
3791 0           $meta->add_attribute($name => $attr);
3792             }
3793             }
3794             }
3795 0 0         if (defined $methods) {
3796 0           while(my($method_name, $method_body) = each %{$methods}){
  0            
3797 0           $meta->add_method($method_name, $method_body);
3798             }
3799             }
3800 0 0         if (defined $roles){
3801 0           Scalar::Random::PP::OO::Util::apply_all_roles($package_name, @{$roles});
  0            
3802             }
3803              
3804 0 0         if($cache_key){
3805 0           $IMMORTALS{$cache_key} = $meta;
3806             }
3807              
3808 0           return $meta;
3809             }
3810              
3811             sub DESTROY{
3812 0     0     my($self) = @_;
3813              
3814 0 0         return if $Scalar::Random::PP::OO::Util::in_global_destruction;
3815              
3816 0           my $serial_id = $self->{anon_serial_id};
3817              
3818 0 0         return if !$serial_id;
3819             # mortal anonymous class
3820              
3821             # XXX: cleaning stash with threads causes panic/SEGV.
3822 0 0         if(exists $INC{'threads.pm'}) {
3823             # (caller)[2] indicates the caller's line number,
3824             # which is zero when the current thread is joining.
3825 0 0         return if( (caller)[2] == 0);
3826             }
3827              
3828             # @ISA is a magical variable, so we clear it manually.
3829 0 0         @{$self->{superclasses}} = () if exists $self->{superclasses};
  0            
3830              
3831             # Then, clear the symbol table hash
3832 0           %{$self->namespace} = ();
  0            
3833              
3834 0           my $name = $self->name;
3835 0           delete $METAS{$name};
3836              
3837 0           $name =~ s/ $serial_id \z//xms;
3838 2     2   11 no strict 'refs';
  2         3  
  2         337  
3839 0           delete ${$name}{ $serial_id . '::' };
  0            
3840              
3841 0           return;
3842             }
3843              
3844             sub throw_error{
3845 0     0 0   my($self, $message, %args) = @_;
3846              
3847 0   0       local $Carp::CarpLevel = $Carp::CarpLevel + 1 + ($args{depth} || 0);
3848 0           local $Carp::MaxArgNums = 20; # default is 8, usually we use named args which gets messier though
3849              
3850 0 0 0       if(exists $args{longmess} && !$args{longmess}){ # intentionaly longmess => 0
3851 0           Carp::croak($message);
3852             }
3853             else{
3854 0           Carp::confess($message);
3855             }
3856             }
3857              
3858             # Contents of Mouse::Meta::Role
3859             package Scalar::Random::PP::OO::Meta::Role;
3860 2     2   8 use Scalar::Random::PP::OO::Util qw(:meta not_supported); # enables strict and warnings
  2         3  
  2         7  
3861              
3862 2     2   9 use Scalar::Random::PP::OO::Meta::Module;
  2         9  
  2         4282  
3863             our @ISA = qw(Scalar::Random::PP::OO::Meta::Module);
3864              
3865             sub method_metaclass;
3866              
3867             sub _construct_meta {
3868 0     0     my $class = shift;
3869              
3870 0           my %args = @_;
3871              
3872 0           $args{methods} = {};
3873 0           $args{attributes} = {};
3874 0           $args{required_methods} = [];
3875 0           $args{roles} = [];
3876              
3877 0   0       my $self = bless \%args, ref($class) || $class;
3878 0 0         if($class ne __PACKAGE__){
3879 0           $self->meta->_initialize_object($self, \%args);
3880             }
3881              
3882 0           return $self;
3883             }
3884              
3885             sub create_anon_role{
3886 0     0 0   my $self = shift;
3887 0           return $self->create(undef, @_);
3888             }
3889              
3890             sub is_anon_role;
3891              
3892             sub get_roles;
3893              
3894             sub calculate_all_roles {
3895 0     0 0   my $self = shift;
3896 0           my %seen;
3897 0           return grep { !$seen{ $_->name }++ }
  0            
3898 0           ($self, map { $_->calculate_all_roles } @{ $self->get_roles });
  0            
3899             }
3900              
3901             sub get_required_method_list{
3902 0     0 0   return @{ $_[0]->{required_methods} };
  0            
3903             }
3904              
3905             sub add_required_methods {
3906 0     0 0   my($self, @methods) = @_;
3907 0           my %required = map{ $_ => 1 } @{$self->{required_methods}};
  0            
  0            
3908 0   0       push @{$self->{required_methods}}, grep{ !$required{$_}++ && !$self->has_method($_) } @methods;
  0            
  0            
3909 0           return;
3910             }
3911              
3912             sub requires_method {
3913 0     0 0   my($self, $name) = @_;
3914 0           return scalar( grep{ $_ eq $name } @{ $self->{required_methods} } ) != 0;
  0            
  0            
3915             }
3916              
3917             sub add_attribute {
3918 0     0 0   my $self = shift;
3919 0           my $name = shift;
3920              
3921 0 0         $self->{attributes}->{$name} = (@_ == 1) ? $_[0] : { @_ };
3922 0           return;
3923             }
3924              
3925             sub _check_required_methods{
3926 0     0     my($role, $consumer, $args) = @_;
3927              
3928 0 0         if($args->{_to} eq 'role'){
3929 0           $consumer->add_required_methods($role->get_required_method_list);
3930             }
3931             else{ # to class or instance
3932 0           my $consumer_class_name = $consumer->name;
3933              
3934 0           my @missing;
3935 0           foreach my $method_name(@{$role->{required_methods}}){
  0            
3936 0 0         next if exists $args->{aliased_methods}{$method_name};
3937 0 0         next if exists $role->{methods}{$method_name};
3938 0 0         next if $consumer_class_name->can($method_name);
3939              
3940 0           push @missing, $method_name;
3941             }
3942 0 0         if(@missing){
3943 0 0         $role->throw_error(sprintf "'%s' requires the method%s %s to be implemented by '%s'",
3944             $role->name,
3945             (@missing == 1 ? '' : 's'), # method or methods
3946             Scalar::Random::PP::OO::Util::quoted_english_list(@missing),
3947             $consumer_class_name);
3948             }
3949             }
3950              
3951 0           return;
3952             }
3953              
3954             sub _apply_methods{
3955 0     0     my($role, $consumer, $args) = @_;
3956              
3957 0           my $alias = $args->{-alias};
3958 0           my $excludes = $args->{-excludes};
3959              
3960 0           foreach my $method_name($role->get_method_list){
3961 0 0         next if $method_name eq 'meta';
3962              
3963 0           my $code = $role->get_method_body($method_name);
3964              
3965 0 0         if(!exists $excludes->{$method_name}){
3966 0 0         if(!$consumer->has_method($method_name)){
3967             # The third argument $role is used in Role::Composite
3968 0           $consumer->add_method($method_name => $code, $role);
3969             }
3970             }
3971              
3972 0 0         if(exists $alias->{$method_name}){
3973 0           my $dstname = $alias->{$method_name};
3974              
3975 0           my $dstcode = $consumer->get_method_body($dstname);
3976              
3977 0 0 0       if(defined($dstcode) && $dstcode != $code){
3978 0           $role->throw_error("Cannot create a method alias if a local method of the same name exists");
3979             }
3980             else{
3981 0           $consumer->add_method($dstname => $code, $role);
3982             }
3983             }
3984             }
3985              
3986 0           return;
3987             }
3988              
3989             sub _apply_attributes{
3990             #my($role, $consumer, $args) = @_;
3991 0     0     my($role, $consumer) = @_;
3992              
3993 0           for my $attr_name ($role->get_attribute_list) {
3994 0 0         next if $consumer->has_attribute($attr_name);
3995              
3996 0           $consumer->add_attribute($attr_name => $role->get_attribute($attr_name));
3997             }
3998 0           return;
3999             }
4000              
4001             sub _apply_modifiers{
4002             #my($role, $consumer, $args) = @_;
4003 0     0     my($role, $consumer) = @_;
4004              
4005              
4006 0 0         if(my $modifiers = $role->{override_method_modifiers}){
4007 0           foreach my $method_name (keys %{$modifiers}){
  0            
4008 0           $consumer->add_override_method_modifier($method_name => $modifiers->{$method_name});
4009             }
4010             }
4011              
4012 0           for my $modifier_type (qw/before around after/) {
4013 0 0         my $table = $role->{"${modifier_type}_method_modifiers"}
4014             or next;
4015              
4016 0           my $add_modifier = "add_${modifier_type}_method_modifier";
4017              
4018 0           while(my($method_name, $modifiers) = each %{$table}){
  0            
4019 0           foreach my $code(@{ $modifiers }){
  0            
4020 0 0         next if $consumer->{"_applied_$modifier_type"}{$method_name, $code}++; # skip applied modifiers
4021 0           $consumer->$add_modifier($method_name => $code);
4022             }
4023             }
4024             }
4025 0           return;
4026             }
4027              
4028             sub _append_roles{
4029             #my($role, $consumer, $args) = @_;
4030 0     0     my($role, $consumer) = @_;
4031              
4032 0           my $roles = $consumer->{roles};
4033              
4034 0           foreach my $r($role, @{$role->get_roles}){
  0            
4035 0 0         if(!$consumer->does_role($r)){
4036 0           push @{$roles}, $r;
  0            
4037             }
4038             }
4039 0           return;
4040             }
4041              
4042             # Moose uses Application::ToInstance, Application::ToClass, Application::ToRole
4043             sub apply {
4044 0     0 0   my $self = shift;
4045 0           my $consumer = shift;
4046              
4047 0 0         my %args = (@_ == 1) ? %{ $_[0] } : @_;
  0            
4048              
4049 0           my $instance;
4050              
4051 0 0         if(Scalar::Random::PP::OO::Util::is_a_metaclass($consumer)){ # Application::ToClass
    0          
4052 0           $args{_to} = 'class';
4053             }
4054             elsif(Scalar::Random::PP::OO::Util::is_a_metarole($consumer)){ # Application::ToRole
4055 0           $args{_to} = 'role';
4056             }
4057             else{ # Appplication::ToInstance
4058 0           $args{_to} = 'instance';
4059 0           $instance = $consumer;
4060              
4061 0   0       $consumer = (Scalar::Random::PP::OO::Util::class_of($instance) || 'Scalar::Random::PP::OO::Meta::Class')->create_anon_class(
4062             superclasses => [ref $instance],
4063             cache => 1,
4064             );
4065             }
4066              
4067 0 0 0       if($args{alias} && !exists $args{-alias}){
4068 0           $args{-alias} = $args{alias};
4069             }
4070 0 0 0       if($args{excludes} && !exists $args{-excludes}){
4071 0           $args{-excludes} = $args{excludes};
4072             }
4073              
4074 0           $args{aliased_methods} = {};
4075 0 0         if(my $alias = $args{-alias}){
4076 0           @{$args{aliased_methods}}{ values %{$alias} } = ();
  0            
  0            
4077             }
4078              
4079 0 0         if(my $excludes = $args{-excludes}){
4080 0           $args{-excludes} = {}; # replace with a hash ref
4081 0 0         if(ref $excludes){
4082 0           %{$args{-excludes}} = (map{ $_ => undef } @{$excludes});
  0            
  0            
  0            
4083             }
4084             else{
4085 0           $args{-excludes}{$excludes} = undef;
4086             }
4087             }
4088              
4089 0           $self->_check_required_methods($consumer, \%args);
4090 0           $self->_apply_attributes($consumer, \%args);
4091 0           $self->_apply_methods($consumer, \%args);
4092 0           $self->_apply_modifiers($consumer, \%args);
4093 0           $self->_append_roles($consumer, \%args);
4094              
4095              
4096 0 0         if(defined $instance){ # Application::ToInstance
4097             # rebless instance
4098 0           bless $instance, $consumer->name;
4099 0           $consumer->_initialize_object($instance, $instance, 1);
4100             }
4101              
4102 0           return;
4103             }
4104              
4105              
4106             sub combine {
4107 0     0 0   my($self, @role_specs) = @_;
4108              
4109 0           require 'Scalar/Random/PP/OO/Meta/Role/Composite.pm'; # we don't want to create its namespace
4110              
4111 0           my $composite = Scalar::Random::PP::OO::Meta::Role::Composite->create_anon_role();
4112              
4113 0           foreach my $role_spec (@role_specs) {
4114 0           my($role_name, $args) = @{$role_spec};
  0            
4115 0           $role_name->meta->apply($composite, %{$args});
  0            
4116             }
4117 0           return $composite;
4118             }
4119              
4120             sub add_before_method_modifier;
4121             sub add_around_method_modifier;
4122             sub add_after_method_modifier;
4123              
4124             sub get_before_method_modifiers;
4125             sub get_around_method_modifiers;
4126             sub get_after_method_modifiers;
4127              
4128             sub add_override_method_modifier{
4129 0     0 0   my($self, $method_name, $method) = @_;
4130              
4131 0 0         if($self->has_method($method_name)){
4132             # This error happens in the override keyword or during role composition,
4133             # so I added a message, "A local method of ...", only for compatibility (gfx)
4134 0           $self->throw_error("Cannot add an override of method '$method_name' "
4135             . "because there is a local version of '$method_name'"
4136             . "(A local method of the same name as been found)");
4137             }
4138              
4139 0           $self->{override_method_modifiers}->{$method_name} = $method;
4140             }
4141              
4142             sub get_override_method_modifier {
4143 0     0 0   my ($self, $method_name) = @_;
4144 0           return $self->{override_method_modifiers}->{$method_name};
4145             }
4146              
4147             sub does_role {
4148 0     0 0   my ($self, $role_name) = @_;
4149              
4150 0 0         (defined $role_name)
4151             || $self->throw_error("You must supply a role name to look for");
4152              
4153 0 0         $role_name = $role_name->name if ref $role_name;
4154              
4155             # if we are it,.. then return true
4156 0 0         return 1 if $role_name eq $self->name;
4157             # otherwise.. check our children
4158 0           for my $role (@{ $self->get_roles }) {
  0            
4159 0 0         return 1 if $role->does_role($role_name);
4160             }
4161 0           return 0;
4162             }
4163              
4164             # Contents of Mouse::Meta::Role::Composite
4165             package Scalar::Random::PP::OO::Meta::Role::Composite;
4166 2     2   17 use Scalar::Random::PP::OO::Util; # enables strict and warnings
  2         2  
  2         8  
4167 2     2   9 use Scalar::Random::PP::OO::Meta::Role;
  2         4  
  2         1635  
4168             our @ISA = qw(Scalar::Random::PP::OO::Meta::Role);
4169              
4170             sub get_method_list{
4171 0     0 0   my($self) = @_;
4172 0           return keys %{ $self->{methods} };
  0            
4173             }
4174              
4175             sub add_method {
4176 0     0 0   my($self, $method_name, $code, $role) = @_;
4177              
4178 0 0 0       if( ($self->{methods}{$method_name} || 0) == $code){
4179             # This role already has the same method.
4180 0           return;
4181             }
4182              
4183 0 0         if($method_name eq 'meta'){
4184 0           $self->SUPER::add_method($method_name => $code);
4185             }
4186             else{
4187             # no need to add a subroutine to the stash
4188 0   0       my $roles = $self->{composed_roles_by_method}{$method_name} ||= [];
4189 0           push @{$roles}, $role;
  0            
4190 0 0         if(@{$roles} > 1){
  0            
4191 0           $self->{conflicting_methods}{$method_name}++;
4192             }
4193 0           $self->{methods}{$method_name} = $code;
4194             }
4195 0           return;
4196             }
4197              
4198             sub get_method_body {
4199 0     0 0   my($self, $method_name) = @_;
4200 0           return $self->{methods}{$method_name};
4201             }
4202              
4203             sub has_method {
4204             # my($self, $method_name) = @_;
4205 0     0 0   return 0; # to fool _apply_methods() in combine()
4206             }
4207              
4208             sub has_attribute{
4209             # my($self, $method_name) = @_;
4210 0     0 0   return 0; # to fool _appply_attributes() in combine()
4211             }
4212              
4213             sub has_override_method_modifier{
4214             # my($self, $method_name) = @_;
4215 0     0 0   return 0; # to fool _apply_modifiers() in combine()
4216             }
4217              
4218             sub add_attribute{
4219 0     0 0   my $self = shift;
4220 0           my $attr_name = shift;
4221 0 0         my $spec = (@_ == 1 ? $_[0] : {@_});
4222              
4223 0           my $existing = $self->{attributes}{$attr_name};
4224 0 0 0       if($existing && $existing != $spec){
4225 0           $self->throw_error("We have encountered an attribute conflict with '$attr_name' "
4226             . "during composition. This is fatal error and cannot be disambiguated.");
4227             }
4228 0           $self->SUPER::add_attribute($attr_name, $spec);
4229 0           return;
4230             }
4231              
4232             sub add_override_method_modifier{
4233 0     0 0   my($self, $method_name, $code) = @_;
4234              
4235 0           my $existing = $self->{override_method_modifiers}{$method_name};
4236 0 0 0       if($existing && $existing != $code){
4237 0           $self->throw_error( "We have encountered an 'override' method conflict with '$method_name' during "
4238             . "composition (Two 'override' methods of the same name encountered). "
4239             . "This is fatal error.")
4240             }
4241 0           $self->SUPER::add_override_method_modifier($method_name, $code);
4242 0           return;
4243             }
4244              
4245             # components of apply()
4246              
4247             sub _apply_methods{
4248 0     0     my($self, $consumer, $args) = @_;
4249              
4250 0 0         if(exists $self->{conflicting_methods}){
4251 0           my $consumer_class_name = $consumer->name;
4252              
4253 0           my @conflicting = grep{ !$consumer_class_name->can($_) } keys %{ $self->{conflicting_methods} };
  0            
  0            
4254              
4255 0 0         if(@conflicting == 1){
    0          
4256 0           my $method_name = $conflicting[0];
4257 0           my $roles = Scalar::Random::PP::OO::Util::quoted_english_list(map{ $_->name } @{ $self->{composed_roles_by_method}{$method_name} });
  0            
  0            
4258 0           $self->throw_error(
4259             sprintf q{Due to a method name conflict in roles %s, the method '%s' must be implemented or excluded by '%s'},
4260             $roles, $method_name, $consumer_class_name
4261             );
4262             }
4263             elsif(@conflicting > 1){
4264 0           my %seen;
4265 0           my $roles = Scalar::Random::PP::OO::Util::quoted_english_list(
4266 0           grep{ !$seen{$_}++ } # uniq
4267 0           map { $_->name }
4268 0           map { @{$_} } @{ $self->{composed_roles_by_method} }{@conflicting}
  0            
  0            
4269             );
4270              
4271 0           $self->throw_error(
4272             sprintf q{Due to method name conflicts in roles %s, the methods %s must be implemented or excluded by '%s'},
4273             $roles,
4274             Scalar::Random::PP::OO::Util::quoted_english_list(@conflicting),
4275             $consumer_class_name
4276             );
4277             }
4278             }
4279              
4280 0           $self->SUPER::_apply_methods($consumer, $args);
4281 0           return;
4282             }
4283             # Contents of Mouse::Meta::Role::Method
4284             package Scalar::Random::PP::OO::Meta::Role::Method;
4285 2     2   12 use Scalar::Random::PP::OO::Util; # enables strict and warnings
  2         3  
  2         7  
4286              
4287 2     2   14 use Scalar::Random::PP::OO::Meta::Method;
  2         4  
  2         283  
4288             our @ISA = qw(Scalar::Random::PP::OO::Meta::Method);
4289              
4290             sub _new{
4291 0     0     my($class, %args) = @_;
4292 0           my $self = bless \%args, $class;
4293              
4294 0 0         if($class ne __PACKAGE__){
4295 0           $self->meta->_initialize_object($self, \%args);
4296             }
4297 0           return $self;
4298             }
4299              
4300             # Contents of Mouse::Object
4301             package Scalar::Random::PP::OO::Object;
4302 2     2   9 use Scalar::Random::PP::OO::Util qw(does dump meta); # enables strict and warnings
  2         1210  
  2         7  
4303              
4304             sub new;
4305             sub BUILDARGS;
4306             sub BUILDALL;
4307              
4308             sub DESTROY;
4309             sub DEMOLISHALL;
4310              
4311             # Contents of Mouse::Role
4312             package Scalar::Random::PP::OO::Role;
4313 2     2   12 use Scalar::Random::PP::OO::Exporter; # enables strict and warnings
  2         3  
  2         9  
4314              
4315             our $VERSION = '0.70';
4316              
4317 2     2   9 use Carp qw(confess);
  2         8  
  2         135  
4318 2     2   10 use Scalar::Util qw(blessed);
  2         3  
  2         94  
4319              
4320 2     2   8 use Scalar::Random::PP::OO::Util qw(not_supported);
  2         3  
  2         7  
4321 2     2   8 use Scalar::Random::PP::OO::Meta::Role;
  2         4  
  2         30  
4322 2     2   10 use Scalar::Random::PP::OO ();
  2         10  
  2         1578  
4323              
4324             Scalar::Random::PP::OO::Exporter->setup_import_methods(
4325             as_is => [qw(
4326             extends with
4327             has
4328             before after around
4329             override super
4330             augment inner
4331              
4332             requires excludes
4333             ),
4334             \&Scalar::Util::blessed,
4335             \&Carp::confess,
4336             ],
4337             );
4338              
4339              
4340             sub extends {
4341 0     0 0   Carp::croak "Roles do not support 'extends'";
4342             }
4343              
4344             sub with {
4345 0     0 0   my $meta = Scalar::Random::PP::OO::Meta::Role->initialize(scalar caller);
4346 0           Scalar::Random::PP::OO::Util::apply_all_roles($meta->name, @_);
4347 0           return;
4348             }
4349              
4350             sub has {
4351 0     0 0   my $meta = Scalar::Random::PP::OO::Meta::Role->initialize(scalar caller);
4352 0           my $name = shift;
4353              
4354 0 0         $meta->throw_error(q{Usage: has 'name' => ( key => value, ... )})
4355             if @_ % 2; # odd number of arguments
4356              
4357 0 0         if(ref $name){ # has [qw(foo bar)] => (...)
4358 0           for (@{$name}){
  0            
4359 0           $meta->add_attribute($_ => @_);
4360             }
4361             }
4362             else{ # has foo => (...)
4363 0           $meta->add_attribute($name => @_);
4364             }
4365 0           return;
4366             }
4367              
4368             sub before {
4369 0     0 0   my $meta = Scalar::Random::PP::OO::Meta::Role->initialize(scalar caller);
4370 0           my $code = pop;
4371 0           for my $name($meta->_collect_methods(@_)) {
4372 0           $meta->add_before_method_modifier($name => $code);
4373             }
4374 0           return;
4375             }
4376              
4377             sub after {
4378 0     0 0   my $meta = Scalar::Random::PP::OO::Meta::Role->initialize(scalar caller);
4379 0           my $code = pop;
4380 0           for my $name($meta->_collect_methods(@_)) {
4381 0           $meta->add_after_method_modifier($name => $code);
4382             }
4383 0           return;
4384             }
4385              
4386             sub around {
4387 0     0 0   my $meta = Scalar::Random::PP::OO::Meta::Role->initialize(scalar caller);
4388 0           my $code = pop;
4389 0           for my $name($meta->_collect_methods(@_)) {
4390 0           $meta->add_around_method_modifier($name => $code);
4391             }
4392 0           return;
4393             }
4394              
4395              
4396             sub super {
4397 0 0   0 0   return if !defined $Scalar::Random::PP::OO::SUPER_BODY;
4398 0           $Scalar::Random::PP::OO::SUPER_BODY->(@Scalar::Random::PP::OO::SUPER_ARGS);
4399             }
4400              
4401             sub override {
4402             # my($name, $code) = @_;
4403 0     0 0   Scalar::Random::PP::OO::Meta::Role->initialize(scalar caller)->add_override_method_modifier(@_);
4404 0           return;
4405             }
4406              
4407             # We keep the same errors messages as Moose::Role emits, here.
4408             sub inner {
4409 0     0 0   Carp::croak "Roles cannot support 'inner'";
4410             }
4411              
4412             sub augment {
4413 0     0 0   Carp::croak "Roles cannot support 'augment'";
4414             }
4415              
4416             sub requires {
4417 0     0 0   my $meta = Scalar::Random::PP::OO::Meta::Role->initialize(scalar caller);
4418 0 0         $meta->throw_error("Must specify at least one method") unless @_;
4419 0           $meta->add_required_methods(@_);
4420 0           return;
4421             }
4422              
4423             sub excludes {
4424 0     0 0   not_supported;
4425             }
4426              
4427             sub init_meta{
4428 0     0 0   shift;
4429 0           my %args = @_;
4430              
4431 0 0         my $class = $args{for_class}
4432             or Carp::confess("Cannot call init_meta without specifying a for_class");
4433              
4434 0   0       my $metaclass = $args{metaclass} || 'Scalar::Random::PP::OO::Meta::Role';
4435              
4436 0           my $meta = $metaclass->initialize($class);
4437              
4438             $meta->add_method(meta => sub{
4439 0   0 0     $metaclass->initialize(ref($_[0]) || $_[0]);
4440 0           });
4441              
4442             # make a role type for each Scalar::Random::PP::OO role
4443 0 0         Scalar::Random::PP::OO::Util::TypeConstraints::role_type($class)
4444             unless Scalar::Random::PP::OO::Util::TypeConstraints::find_type_constraint($class);
4445              
4446 0           return $meta;
4447             }
4448              
4449             # Contents of Mouse::Util::MetaRole
4450             package Scalar::Random::PP::OO::Util::MetaRole;
4451 2     2   11 use Scalar::Random::PP::OO::Util; # enables strict and warnings
  2         2  
  2         6  
4452 2     2   11 use Scalar::Util ();
  2         3  
  2         2074  
4453              
4454             sub apply_metaclass_roles {
4455 0     0 0   my %args = @_;
4456 0           _fixup_old_style_args(\%args);
4457              
4458 0           return apply_metaroles(%args);
4459             }
4460              
4461             sub apply_metaroles {
4462 0     0 0   my %args = @_;
4463              
4464 0 0         my $for = Scalar::Util::blessed($args{for})
4465             ? $args{for}
4466             : Scalar::Random::PP::OO::Util::get_metaclass_by_name( $args{for} );
4467              
4468 0 0         if(!$for){
4469 0           Carp::confess("You must pass an initialized class, but '$args{for}' has no metaclass");
4470             }
4471              
4472 0 0         if ( Scalar::Random::PP::OO::Util::is_a_metarole($for) ) {
4473 0           return _make_new_metaclass( $for, $args{role_metaroles}, 'role' );
4474             }
4475             else {
4476 0           return _make_new_metaclass( $for, $args{class_metaroles}, 'class' );
4477             }
4478             }
4479              
4480             sub _make_new_metaclass {
4481 0     0     my($for, $roles, $primary) = @_;
4482              
4483 0 0         return $for unless keys %{$roles};
  0            
4484              
4485 0 0         my $new_metaclass = exists($roles->{$primary})
4486             ? _make_new_class( ref $for, $roles->{$primary} ) # new class with traits
4487             : ref $for;
4488              
4489 0           my %classes;
4490              
4491 0           for my $key ( grep { $_ ne $primary } keys %{$roles} ) {
  0            
  0            
4492 0           my $metaclass;
4493 0   0       my $attr = $for->can($metaclass = ($key . '_metaclass'))
4494             || $for->can($metaclass = ($key . '_class'))
4495             || $for->throw_error("Unknown metaclass '$key'");
4496              
4497 0           $classes{ $metaclass }
4498             = _make_new_class( $for->$attr(), $roles->{$key} );
4499             }
4500              
4501 0           return $new_metaclass->reinitialize( $for, %classes );
4502             }
4503              
4504              
4505             sub _fixup_old_style_args {
4506 0     0     my $args = shift;
4507              
4508 0 0 0       return if $args->{class_metaroles} || $args->{roles_metaroles};
4509              
4510 0 0         $args->{for} = delete $args->{for_class}
4511             if exists $args->{for_class};
4512              
4513 0           my @old_keys = qw(
4514             attribute_metaclass_roles
4515             method_metaclass_roles
4516             wrapped_method_metaclass_roles
4517             instance_metaclass_roles
4518             constructor_class_roles
4519             destructor_class_roles
4520             error_class_roles
4521              
4522             application_to_class_class_roles
4523             application_to_role_class_roles
4524             application_to_instance_class_roles
4525             application_role_summation_class_roles
4526             );
4527              
4528 0 0         my $for = Scalar::Util::blessed($args->{for})
4529             ? $args->{for}
4530             : Scalar::Random::PP::OO::Util::get_metaclass_by_name( $args->{for} );
4531              
4532 0           my $top_key;
4533 0 0         if( Scalar::Random::PP::OO::Util::is_a_metaclass($for) ){
4534 0           $top_key = 'class_metaroles';
4535              
4536 0 0         $args->{class_metaroles}{class} = delete $args->{metaclass_roles}
4537             if exists $args->{metaclass_roles};
4538             }
4539             else {
4540 0           $top_key = 'role_metaroles';
4541              
4542 0 0         $args->{role_metaroles}{role} = delete $args->{metaclass_roles}
4543             if exists $args->{metaclass_roles};
4544             }
4545              
4546 0           for my $old_key (@old_keys) {
4547 0           my ($new_key) = $old_key =~ /^(.+)_(?:class|metaclass)_roles$/;
4548              
4549 0 0         $args->{$top_key}{$new_key} = delete $args->{$old_key}
4550             if exists $args->{$old_key};
4551             }
4552              
4553 0           return;
4554             }
4555              
4556              
4557             sub apply_base_class_roles {
4558 0     0 0   my %options = @_;
4559              
4560 0           my $for = $options{for_class};
4561              
4562 0           my $meta = Scalar::Random::PP::OO::Util::class_of($for);
4563              
4564 0           my $new_base = _make_new_class(
4565             $for,
4566             $options{roles},
4567             [ $meta->superclasses() ],
4568             );
4569              
4570 0 0         $meta->superclasses($new_base)
4571             if $new_base ne $meta->name();
4572 0           return;
4573             }
4574              
4575             sub _make_new_class {
4576 0     0     my($existing_class, $roles, $superclasses) = @_;
4577              
4578 0 0         if(!$superclasses){
4579 0 0         return $existing_class if !$roles;
4580              
4581 0           my $meta = Scalar::Random::PP::OO::Meta::Class->initialize($existing_class);
4582              
4583 0   0       return $existing_class
4584 0 0         if !grep { !ref($_) && !$meta->does_role($_) } @{$roles};
  0            
4585             }
4586              
4587 0 0         return Scalar::Random::PP::OO::Meta::Class->create_anon_class(
4588             superclasses => $superclasses ? $superclasses : [$existing_class],
4589             roles => $roles,
4590             cache => 1,
4591             )->name();
4592             }
4593              
4594             ;
4595              
4596             package Scalar::Random::PP::OO;
4597              
4598             our $VERSION = '0.07';
4599              
4600             Scalar::Random::PP::OO::Exporter->setup_import_methods(also => 'Scalar::Random::PP::OO::TOP');
4601              
4602             1;