my
%METAS
;
if
(Mouse::Util::MOUSE_XS){
Mouse::Util::__register_metaclass_storage(\
%METAS
, 0);
*CLONE
=
sub
{ Mouse::Util::__register_metaclass_storage(\
%METAS
, 1) };
}
sub
initialize {
my
(
$class
,
$package_name
,
@args
) =
@_
;
(
$package_name
&& !
ref
(
$package_name
))
||
$class
->throw_error(
"You must pass a package name and it cannot be blessed"
);
return
$METAS
{
$package_name
}
||=
$class
->_construct_meta(
package
=>
$package_name
,
@args
);
}
sub
reinitialize {
my
(
$class
,
$package_name
,
@args
) =
@_
;
$package_name
=
$package_name
->name
if
ref
$package_name
;
(
$package_name
&& !
ref
(
$package_name
))
||
$class
->throw_error(
"You must pass a package name and it cannot be blessed"
);
if
(
exists
$METAS
{
$package_name
}) {
unshift
@args
, %{
$METAS
{
$package_name
} };
}
delete
$METAS
{
$package_name
};
return
$class
->initialize(
$package_name
,
@args
);
}
sub
_class_of{
my
(
$class_or_instance
) =
@_
;
return
undef
unless
defined
$class_or_instance
;
return
$METAS
{
ref
(
$class_or_instance
) ||
$class_or_instance
};
}
sub
_get_all_metaclass_instances {
values
%METAS
}
sub
_get_all_metaclass_names {
keys
%METAS
}
sub
_get_metaclass_by_name {
$METAS
{
$_
[0]} }
sub
name;
sub
namespace;
sub
get_attribute_map {
Carp::cluck(
'get_attribute_map() has been deprecated. Use get_attribute_list() and get_attribute() instead'
);
return
$_
[0]->{attributes};
}
sub
has_attribute {
exists
$_
[0]->{attributes}->{
$_
[1]} }
sub
get_attribute {
$_
[0]->{attributes}->{
$_
[1]} }
sub
remove_attribute {
delete
$_
[0]->{attributes}->{
$_
[1]} }
sub
get_attribute_list{
keys
%{
$_
[0]->{attributes}} }
my
%foreign
=
map
{
$_
=>
undef
}
qw(
Mouse Mouse::Role Mouse::Util Mouse::Util::TypeConstraints
Carp Scalar::Util List::Util
builtin
)
;
sub
_get_method_body {
my
(
$self
,
$method_name
) =
@_
;
my
$code
= Mouse::Util::get_code_ref(
$self
->{
package
},
$method_name
);
return
$code
&& !
exists
$foreign
{ Mouse::Util::get_code_package(
$code
) }
?
$code
:
undef
;
}
sub
add_method;
sub
has_method {
my
(
$self
,
$method_name
) =
@_
;
defined
(
$method_name
)
or
$self
->throw_error(
'You must define a method name'
);
return
defined
(
$self
->{methods}{
$method_name
} )
||
defined
(
$self
->_get_method_body(
$method_name
) );
}
sub
get_method_body {
my
(
$self
,
$method_name
) =
@_
;
defined
(
$method_name
)
or
$self
->throw_error(
'You must define a method name'
);
return
$self
->{methods}{
$method_name
}
||=
$self
->_get_method_body(
$method_name
);
}
sub
get_method {
my
(
$self
,
$method_name
) =
@_
;
if
(
my
$code
=
$self
->get_method_body(
$method_name
)){
return
Mouse::Util::load_class(
$self
->method_metaclass)->wrap(
body
=>
$code
,
name
=>
$method_name
,
package
=>
$self
->name,
associated_metaclass
=>
$self
,
);
}
return
undef
;
}
sub
get_method_list {
my
(
$self
) =
@_
;
return
grep
{
$self
->has_method(
$_
) }
keys
%{
$self
->namespace };
}
sub
_collect_methods {
my
(
$meta
,
@args
) =
@_
;
my
@methods
;
foreach
my
$arg
(
@args
){
if
(
my
$type
=
ref
$arg
){
if
(
$type
eq
'Regexp'
){
push
@methods
,
grep
{
$_
=~
$arg
}
$meta
->get_all_method_names;
}
elsif
(
$type
eq
'ARRAY'
){
push
@methods
, @{
$arg
};
}
else
{
my
$subname
= (
caller
(1) )[3];
$meta
->throw_error(
sprintf
(
'Methods passed to %s must be provided as a list,'
.
' ArrayRef or regular expression, not %s'
,
$subname
,
$type
,
)
);
}
}
else
{
push
@methods
,
$arg
;
}
}
return
@methods
;
}
my
$ANON_SERIAL
= 0;
my
%IMMORTALS
;
sub
create {
my
(
$self
,
$package_name
,
%options
) =
@_
;
my
$class
=
ref
(
$self
) ||
$self
;
$self
->throw_error(
'You must pass a package name'
)
if
@_
< 2;
my
$superclasses
;
if
(
exists
$options
{superclasses}){
if
(Mouse::Util::is_a_metarole(
$self
)){
delete
$options
{superclasses};
}
else
{
$superclasses
=
delete
$options
{superclasses};
(
ref
$superclasses
eq
'ARRAY'
)
||
$self
->throw_error(
"You must pass an ARRAY ref of superclasses"
);
}
}
my
$attributes
=
delete
$options
{attributes};
if
(
defined
$attributes
){
(
ref
$attributes
eq
'ARRAY'
||
ref
$attributes
eq
'HASH'
)
||
$self
->throw_error(
"You must pass an ARRAY ref of attributes"
);
}
my
$methods
=
delete
$options
{methods};
if
(
defined
$methods
){
(
ref
$methods
eq
'HASH'
)
||
$self
->throw_error(
"You must pass a HASH ref of methods"
);
}
my
$roles
=
delete
$options
{roles};
if
(
defined
$roles
){
(
ref
$roles
eq
'ARRAY'
)
||
$self
->throw_error(
"You must pass an ARRAY ref of roles"
);
}
my
$mortal
;
my
$cache_key
;
if
(!
defined
$package_name
){
$mortal
= !
$options
{cache};
if
(!
$mortal
){
$cache_key
=
join
'='
=> (
join
(
'|'
, @{
$superclasses
|| []}),
join
(
'|'
,
sort
@{
$roles
|| []}),
);
return
$IMMORTALS
{
$cache_key
}
if
exists
$IMMORTALS
{
$cache_key
};
}
$options
{anon_serial_id} = ++
$ANON_SERIAL
;
$package_name
=
$class
.
'::__ANON__::'
.
$ANON_SERIAL
;
}
{
no
strict
'refs'
;
${
$package_name
.
'::VERSION'
} =
delete
$options
{version}
if
exists
$options
{version};
${
$package_name
.
'::AUTHORITY'
} =
delete
$options
{authority}
if
exists
$options
{authority};
}
my
$meta
=
$self
->initialize(
$package_name
,
%options
);
Scalar::Util::weaken(
$METAS
{
$package_name
})
if
$mortal
;
$meta
->add_method(
meta
=>
sub
{
$self
->initialize(
ref
(
$_
[0]) ||
$_
[0]);
});
$meta
->superclasses(@{
$superclasses
})
if
defined
$superclasses
;
if
(
defined
$attributes
) {
if
(
ref
(
$attributes
) eq
'ARRAY'
){
foreach
my
$attr
(@{
$attributes
}) {
$meta
->add_attribute(
$attr
);
}
}
else
{
while
(
my
(
$name
,
$attr
) =
each
%{
$attributes
}){
$meta
->add_attribute(
$name
=>
$attr
);
}
}
}
if
(
defined
$methods
) {
while
(
my
(
$method_name
,
$method_body
) =
each
%{
$methods
}){
$meta
->add_method(
$method_name
,
$method_body
);
}
}
if
(
defined
$roles
and !
$options
{in_application_to_instance}){
Mouse::Util::apply_all_roles(
$package_name
, @{
$roles
});
}
if
(
$cache_key
){
$IMMORTALS
{
$cache_key
} =
$meta
;
}
return
$meta
;
}
sub
DESTROY{
my
(
$self
) =
@_
;
return
if
Mouse::Util::in_global_destruction();
my
$serial_id
=
$self
->{anon_serial_id};
return
if
!
$serial_id
;
if
(
exists
$INC
{
'threads.pm'
}) {
return
if
( (
caller
)[2] == 0);
}
@{
$self
->{superclasses}} = ()
if
exists
$self
->{superclasses} &&
scalar
(@{
$self
->{superclasses}}) > 0;
%{
$self
->namespace} = ();
my
$name
=
$self
->name;
delete
$METAS
{
$name
};
$name
=~ s/
$serial_id
\z//xms;
no
strict
'refs'
;
delete
${
$name
}{
$serial_id
.
'::'
};
return
;
}
1;