=pod

=begin testing-SETUP

BEGIN {
    eval 'use DateTime; use DateTime::Calendar::Mayan;';
    if ($@) {
        diag 'DateTime & DateTime::Calendar::Mayan required for this test';
        ok(1);
        exit 0;
    }
}

=end testing-SETUP

=head1 NAME

Moose::Cookbook::Basics::Recipe11 - Extending a non-Moose base class

=head1 SYNOPSIS

  package My::DateTime;

  use Moose;
  extends qw( DateTime Moose::Object );

  use DateTime::Calendar::Mayan;

  has 'mayan_date' => (
      is        => 'ro',
      isa       => 'DateTime::Calendar::Mayan',
      init_arg  => undef,
      lazy      => 1,
      builder   => '_build_mayan_date',
      clearer   => '_clear_mayan_date',
      predicate => 'has_mayan_date',
  );

  sub new {
      my $class = shift;

      my $obj = $class->SUPER::new(@_);

      return $class->meta->new_object(
          __INSTANCE__ => $obj,
          @_,
      );
  }

  after 'set' => sub {
      $_[0]->_clear_mayan_date;
  };

  sub _build_mayan_date {
      DateTime::Calendar::Mayan->from_object( object => $_[0] );
  }

=head1 DESCRIPTION

This recipe demonstrates how to use Moose to subclass a parent which
is not Moose based. This recipe only works if the parent class uses a
blessed hash reference for object instances. If your parent is doing
something funkier, you should check out L<MooseX::InsideOut>.

You might also want to check out L<MooseX::NonMoose>, which does all
the grunt work for you.

There are a couple pieces worth noting:

  use Moose;
  extends qw( DateTime Moose::Object );

First, we C<use Moose> just like we always do. This lets us declare
attributes and use all the Moose sugar to which we are accustomed.

The C<extends> declaration explicitly include L<Moose::Object> as well
as L<DateTime>. This lets us use methods which are provided by
L<Moose::Object>, like C<does>.

The constructor demonstrates a particular hack/pattern (hacktern?) for
working with non-Moose parent classes:

  sub new {
      my $class = shift;

      my $obj = $class->SUPER::new(@_);

      return $class->meta->new_object(
          __INSTANCE__ => $obj,
          @_,
      );
  }

We explicitly call C<< $class->meta->new_object >> and pass the
already-created object in the C<__INSTANCE__> key. Internally, Moose
will take the existing object and initialize any attributes defined in
our subclass.

The C<after> modifier works just like we'd expect. The fact that
C<set> is defined in our non-Moose parent does not matter.

=head1 CONCLUSION

Moose can play nice with non-Moose classes when you follow the pattern
shown here. Your subclass has access to all the power of Moose,
including attribute declaration, method modifiers, type constraints
(for new attributes), and roles.

However, you won't be able to easily override a parent's "attributes",
since they're not Moose attributes. Nor will you be able to inline a
constructor, since you need to explicitly use the metaclass's object
constructor.

=head1 AUTHOR

Dave Rolsky E<lt>autarch@urth.orgE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright 2009 by Infinity Interactive, Inc.

L<http://www.iinteractive.com>

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

=begin testing

my $dt = My::DateTime->new( year => 1970, month => 2, day => 24 );

can_ok( $dt, 'mayan_date' );
isa_ok( $dt->mayan_date, 'DateTime::Calendar::Mayan' );
is( $dt->mayan_date->date, '12.17.16.9.19', 'got expected mayan date' );

$dt->set( year => 2009 );
ok( ! $dt->has_mayan_date, 'mayan_date is cleared after call to ->set' );

=end testing

=cut