The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package MooseX::Blessed::Reconstruct;
BEGIN {
  $MooseX::Blessed::Reconstruct::AUTHORITY = 'cpan:YANICK';
}
# ABSTRACT: A L<Data::Visitor> for creating Moose objects from blessed placeholders
$MooseX::Blessed::Reconstruct::VERSION = '1.00';

use Moose;

use Carp qw(croak);

use Class::MOP;
use Class::Load;
use Data::Visitor 0.21; # n-arity visit

use Scalar::Util qw(reftype);

use namespace::clean -except => 'meta';

extends qw(Data::Visitor);

has load_classes => (
	isa => "Bool",
	is  => "rw",
	default => 1,
);

sub visit_object {
	my ( $v, $obj ) = @_;

	my $class = ref $obj;

	Class::Load::load_class($class) if $v->load_classes;

	my $meta = Class::MOP::get_metaclass_by_name($class);

	if ( ref $meta ) {
		return $v->visit_object_with_meta($obj, $meta);
	} else {
		return $v->visit_ref($obj);
	}
}

sub visit_object_with_meta {
	my ( $v, $obj, $meta ) = @_;

	my $instance = $meta->get_meta_instance->create_instance;

	$v->_register_mapping( $obj => $instance );

	my $args = $v->prepare_args( $meta, $obj );

	$meta->new_object( %$args, __INSTANCE__ => $instance );

	return $instance;
}

sub prepare_args {
	my ( $v, $meta, $obj ) = @_;

    my @args;

    if ( reftype $obj eq 'HASH' ) {
        @args = %$obj;
    } elsif ( reftype $obj eq 'ARRAY' ) {
        @args = @$obj;
    } elsif ( reftype $obj eq 'SCALAR' ) {
        @args = $$obj;
    } else {
        croak "unknown ref type $obj";
    }

    my @processed = $v->visit(@args);

    return $meta->name->BUILDARGS(@processed);
}

__PACKAGE__->meta->make_immutable;

__PACKAGE__

__END__

=pod

=encoding UTF-8

=head1 NAME

MooseX::Blessed::Reconstruct - A L<Data::Visitor> for creating Moose objects from blessed placeholders

=head1 VERSION

version 1.00

=head1 SYNOPSIS

	use MooseX::Blessed::Reconstruct;


	my $obj = bless( {
		init_arg_foo => "Blah",
		arf => "yay",
	}, "Foo" );

	my $proper = MooseX::Blessed::Reconstruct->new->visit($obj);



	# equivalent to:

	my $proper = Foo->meta->new_object(%$obj);

	# but recursive (and works with shared references)

=head1 DESCRIPTION

The purpose of this module is to "fix up" blessed data into a real Moose
object.

This is used internally by L<MooseX::YAML> but has no implementation details
having to do with L<YAML> itself.

=head1 METHODS

See L<Data::Visitor>

=over 4

=item visit_object $object

Calls L<Class::MOP/load_class> on the C<ref> of $object.

If there's a metaclass, calls C<visit_object_with_meta>, otherwise C<visit_ref>
is used to walk the object brutishly.

Returns a deep clone of the input structure with all the L<Moose> objects
reconstructed "properly".

=item visit_object_with_meta $obj, $meta

Uses the metaclass C<$meta> to create a new instance, registers the instance
with L<Data::Visitor>'s cycle tracking, and then inflates it using
L<Moose::Meta::Class/new_object>.

=item prepare_args $obj

Collapses $obj into key value pairs to be used as init args to
L<Moose::Meta::Class/new_object>.

=back

=head1 AUTHORS

=over 4

=item *

Yuval Kogman <nothingmuch@woobling.org>

=item *

Jonathan Rockway <jrockway@cpan.org>

=back

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2008 by Infinity Interactive, Yuval Kogman.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut