X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FClass%2FMOP%2FMethod%2FConstructor.pm;h=3755a4eea79f9b88de618332a98ceebb15cffc3d;hb=5e5102f19ccb1dc52b290577b0363e97dacbd5b3;hp=9a95e9e54722e586af83f512e70c1fb3082c0b1a;hpb=7931f7dbb7c24340c20560f49e32ec258968949b;p=gitmo%2FClass-MOP.git diff --git a/lib/Class/MOP/Method/Constructor.pm b/lib/Class/MOP/Method/Constructor.pm index 9a95e9e..3755a4e 100644 --- a/lib/Class/MOP/Method/Constructor.pm +++ b/lib/Class/MOP/Method/Constructor.pm @@ -6,8 +6,9 @@ use warnings; use Carp 'confess'; use Scalar::Util 'blessed', 'weaken'; +use Try::Tiny; -our $VERSION = '1.10'; +our $VERSION = '1.11'; $VERSION = eval $VERSION; our $AUTHORITY = 'cpan:STEVAN'; @@ -92,102 +93,116 @@ sub _generate_constructor_method { return sub { Class::MOP::Class->initialize(shift)->new_object(@_) } } -sub _generate_constructor_method_inline { +sub _eval_environment { my $self = shift; - my $defaults = [map { $_->default } @{ $self->_attributes }]; - - my $close_over = { + return { '$defaults' => \$defaults, }; +} - my $source = 'sub {'; - $source .= "\n" . 'my $class = shift;'; - - $source .= "\n" . 'return Class::MOP::Class->initialize($class)->new_object(@_)'; - $source .= "\n" . ' if $class ne \'' . $self->associated_metaclass->name . '\';'; +sub _generate_constructor_method_inline { + my $self = shift; - $source .= "\n" . 'my $params = @_ == 1 ? $_[0] : {@_};'; + my $meta = $self->associated_metaclass; - $source .= "\n" . 'my $instance = ' . $self->associated_metaclass->inline_create_instance('$class'); my $idx = 0; - $source .= ";\n" . (join ";\n" => map { - $self->_generate_slot_initializer($_, $idx++) - } @{ $self->_attributes }); - if (Class::MOP::metaclass_is_weak($self->associated_metaclass->name)) { - $source .= ";\n" . $self->associated_metaclass->_inline_set_mop_slot('$instance', 'Class::MOP::class_of($class)'); - } - $source .= ";\n" . 'return $instance'; - $source .= ";\n" . '}'; - warn $source if $self->options->{debug}; - - my ( $code, $e ) = $self->_eval_closure( - $close_over, - $source + my @source = ( + 'sub {', + 'my $class = shift;', + 'return Class::MOP::Class->initialize($class)->new_object(@_)', + 'if $class ne \'' . $meta->name . '\';', + 'my $params = @_ == 1 ? $_[0] : {@_};', + 'my $instance = ' . $meta->inline_create_instance('$class') . ';', + (map { $self->_generate_slot_initializer($_, $idx++) } + @{ $self->_attributes }), + $self->_preserve_weak_metaclasses, + 'return $instance', + '}', ); - confess "Could not eval the constructor :\n\n$source\n\nbecause :\n\n$e" if $e; + + warn join("\n", @source) if $self->options->{debug}; + + my $code = try { + $self->_compile_code(\@source); + } + catch { + my $source = join("\n", @source); + confess "Could not eval the constructor :\n\n$source\n\nbecause :\n\n$_"; + }; return $code; } sub _generate_slot_initializer { my $self = shift; - my $attr = shift; - my $idx = shift; + my ($attr, $idx) = @_; - my $default; - if ($attr->has_default) { - $default = $self->_generate_default_value($attr, $idx); - } elsif( $attr->has_builder ) { - $default = '$instance->'.$attr->builder; - } + my $default = $self->_generate_default_value($attr, $idx); - if ( defined( my $init_arg = $attr->init_arg ) ) { - return ( - 'if(exists $params->{\'' - . $init_arg . '\'}){' . "\n" - . $attr->inline_set( - '$instance', - '$params->{\'' . $init_arg . '\'}' - ) - . "\n" . '} ' - . ( - !defined $default ? '' : 'else {' . "\n" - . $attr->inline_set( - '$instance', - $default - ) - . "\n" . '}' - ) + if (defined(my $init_arg = $attr->init_arg)) { + my @source = ( + 'if (exists $params->{\'' . $init_arg . '\'}) {', + $attr->_inline_set_value( + '$instance', '$params->{\'' . $init_arg . '\'}' + ), + '}', ); + if (defined $default) { + push @source, ( + 'else {', + $attr->_inline_set_value('$instance', $default), + '}', + ); + } + return @source; + } + elsif (defined $default) { + return $attr->_inline_set_value('$instance', $default); } - elsif ( defined $default ) { + else { + return (); + } +} + +sub _preserve_weak_metaclasses { + my $self = shift; + my $meta = $self->associated_metaclass; + if (Class::MOP::metaclass_is_weak($meta->name)) { return ( - $attr->inline_set( - '$instance', - $default - ) - . "\n" + $meta->_inline_set_mop_slot( + '$instance', 'Class::MOP::class_of($class)' + ) . ';' ); } else { - return ''; + return (); } } sub _generate_default_value { - my ($self, $attr, $index) = @_; - # NOTE: - # default values can either be CODE refs - # in which case we need to call them. Or - # they can be scalars (strings/numbers) - # in which case we can just deal with them - # in the code we eval. - if ($attr->is_default_a_coderef) { - return '$defaults->[' . $index . ']->($instance)'; + my $self = shift; + my ($attr, $index) = @_; + + if ($attr->has_default) { + # NOTE: + # default values can either be CODE refs + # in which case we need to call them. Or + # they can be scalars (strings/numbers) + # in which case we can just deal with them + # in the code we eval. + if ($attr->is_default_a_coderef) { + return '$defaults->[' . $index . ']->($instance)'; + } + else { + return '$defaults->[' . $index . ']'; + } + } + elsif ($attr->has_builder) { + return '$instance->' . $attr->builder; } else { - return '$defaults->[' . $index . ']'; + return; } }