-#!perl
package Mouse;
use strict;
use warnings;
-
-our $VERSION = '0.05';
use 5.006;
+use base 'Exporter';
+
+our $VERSION = '0.15';
+
+BEGIN {
+ if ($ENV{MOUSE_DEBUG}) {
+ *DEBUG = sub (){ 1 };
+ } else {
+ *DEBUG = sub (){ 0 };
+ }
+}
-use Sub::Exporter;
use Carp 'confess';
use Scalar::Util 'blessed';
-use Class::Method::Modifiers ();
+use Mouse::Util;
use Mouse::Meta::Attribute;
use Mouse::Meta::Class;
use Mouse::Object;
use Mouse::TypeRegistry;
-do {
- my $CALLER;
-
- my %exports = (
- meta => sub {
- my $meta = Mouse::Meta::Class->initialize($CALLER);
- return sub { $meta };
- },
-
- extends => sub {
- my $caller = $CALLER;
- return sub {
- $caller->meta->superclasses(@_);
- };
- },
-
- has => sub {
- return sub {
- my $package = caller;
- my $names = shift;
- $names = [$names] if !ref($names);
-
- for my $name (@$names) {
- if ($name =~ s/^\+//) {
- Mouse::Meta::Attribute->clone_parent($package, $name, @_);
- }
- else {
- Mouse::Meta::Attribute->create($package, $name, @_);
- }
- }
- };
- },
-
- confess => sub {
- return \&confess;
- },
-
- blessed => sub {
- return \&blessed;
- },
-
- before => sub {
- return \&Class::Method::Modifiers::before;
- },
-
- after => sub {
- return \&Class::Method::Modifiers::after;
- },
-
- around => sub {
- return \&Class::Method::Modifiers::around;
- },
-
- with => sub {
- my $caller = $CALLER;
-
- return sub {
- my $role = shift;
- my $class = $caller->meta;
-
- confess "Mouse::Role only supports 'with' on individual roles at a time" if @_;
-
- Mouse::load_class($role);
- $role->meta->apply_to_class($class);
- };
- },
- );
-
- my $exporter = Sub::Exporter::build_exporter({
- exports => \%exports,
- groups => { default => [':all'] },
- });
-
- sub import {
- $CALLER = caller;
-
- strict->import;
- warnings->import;
-
- my $meta = Mouse::Meta::Class->initialize($CALLER);
- $meta->superclasses('Mouse::Object')
- unless $meta->superclasses;
-
- goto $exporter;
+our @EXPORT = qw(extends has before after around blessed confess with);
+
+sub extends { Mouse::Meta::Class->initialize(caller)->superclasses(@_) }
+
+sub has {
+ my $meta = Mouse::Meta::Class->initialize(caller);
+
+ my $names = shift;
+ $names = [$names] if !ref($names);
+
+ for my $name (@$names) {
+ if ($name =~ s/^\+//) {
+ Mouse::Meta::Attribute->clone_parent($meta, $name, @_);
+ }
+ else {
+ Mouse::Meta::Attribute->create($meta, $name, @_);
+ }
+ }
+}
+
+sub before {
+ my $meta = Mouse::Meta::Class->initialize(caller);
+
+ my $code = pop;
+
+ for (@_) {
+ $meta->add_before_method_modifier($_ => $code);
}
+}
+
+sub after {
+ my $meta = Mouse::Meta::Class->initialize(caller);
+
+ my $code = pop;
+
+ for (@_) {
+ $meta->add_after_method_modifier($_ => $code);
+ }
+}
+
+sub around {
+ my $meta = Mouse::Meta::Class->initialize(caller);
+
+ my $code = pop;
+
+ for (@_) {
+ $meta->add_around_method_modifier($_ => $code);
+ }
+}
+
+sub with {
+ Mouse::Util::apply_all_roles((caller)[0], @_);
+}
+
+sub import {
+ my $class = shift;
+
+ strict->import;
+ warnings->import;
- sub unimport {
- my $caller = caller;
+ my $caller = caller;
+ # we should never export to main
+ if ($caller eq 'main') {
+ warn qq{$class does not export its sugar to the 'main' package.\n};
+ return;
+ }
+
+ my $meta = Mouse::Meta::Class->initialize($caller);
+ $meta->superclasses('Mouse::Object')
+ unless $meta->superclasses;
+
+ no strict 'refs';
+ no warnings 'redefine';
+ *{$caller.'::meta'} = sub { $meta };
+
+ if (@_) {
+ __PACKAGE__->export_to_level( 1, $class, @_);
+ } else {
+ # shortcut for the common case of no type character
no strict 'refs';
- for my $keyword (keys %exports) {
- next if $keyword eq 'meta'; # we don't delete this one
- delete ${ $caller . '::' }{$keyword};
+ for my $keyword (@EXPORT) {
+ *{ $caller . '::' . $keyword } = *{__PACKAGE__ . '::' . $keyword};
}
}
-};
+}
+
+sub unimport {
+ my $caller = caller;
+
+ no strict 'refs';
+ for my $keyword (@EXPORT) {
+ delete ${ $caller . '::' }{$keyword};
+ }
+}
sub load_class {
my $class = shift;
confess "Invalid class name ($display)";
}
+ return 1 if $class eq 'Mouse::Object';
return 1 if is_class_loaded($class);
(my $file = "$class.pm") =~ s{::}{/}g;
functionality, faster. In particular, L<Moose/has> is missing only a few
expert-level features.
+We're also going as light on dependencies as possible. Most functions we use
+from L<Scalar::Util> are copied into this dist. L<Scalar::Util> is required if
+you'd like weak references; there's simply no way to do it from pure Perl.
+L<Class::Method::Modifiers> is required if you want support for L</before>,
+L</after>, and L</around>.
+
=head2 MOOSE COMPAT
Compatibility with Moose has been the utmost concern. Fewer than 1% of the
tests fail when run against Moose instead of Mouse. Mouse code coverage is also
-over 99%. Even the error messages are taken from Moose. The Mouse code just
-runs the test suite 3x-4x faster.
+over 96%. Even the error messages are taken from Moose. The Mouse code just
+runs the test suite 4x faster.
The idea is that, if you need the extra power, you should be able to run
C<s/Mouse/Moose/g> on your codebase and have nothing break. To that end,
Mouse also has the blessings of Moose's author, stevan.
-=head2 MISSING FEATURES
-
-=head3 Roles
-
-Fixing this one slightly less soon. stevan has suggested an implementation
-strategy. Mouse currently mostly ignores methods.
-
-=head3 Complex types
-
-User-defined type constraints and parameterized types may be implemented. Type
-coercions probably not (patches welcome).
-
-=head3 Bootstrapped meta world
-
-Very handy for extensions to the MOP. Not pressing, but would be nice to have.
-
-=head3 Modification of attribute metaclass
-
-When you declare an attribute with L</has>, you get the inlined accessors
-installed immediately. Modifying the attribute metaclass, even if possible,
-does nothing.
-
-=head3 Lots more..
-
-MouseX?
-
=head1 KEYWORDS
=head2 meta -> Mouse::Meta::Class
Installs a "before" method modifier. See L<Moose/before> or
L<Class::Method::Modifiers/before>.
+Use of this feature requires L<Class::Method::Modifiers>!
+
=head2 after (method|methods) => Code
Installs an "after" method modifier. See L<Moose/after> or
L<Class::Method::Modifiers/after>.
+Use of this feature requires L<Class::Method::Modifiers>!
+
=head2 around (method|methods) => Code
Installs an "around" method modifier. See L<Moose/around> or
L<Class::Method::Modifiers/around>.
+Use of this feature requires L<Class::Method::Modifiers>!
+
=head2 has (name|names) => parameters
Adds an attribute (or if passed an arrayref of names, multiple attributes) to
has a builder, then providing a value for the attribute in the constructor is
optional.
-=item init_arg => Str
+=item init_arg => Str | Undef
-Allows you to use a different key name in the constructor.
+Allows you to use a different key name in the constructor. If undef, the
+attribue can't be passed to the constructor.
=item default => Value | CodeRef
Lets you automatically weaken any reference stored in the attribute.
-=item trigger => Coderef
+Use of this feature requires L<Scalar::Util>!
-Any time the attribute's value is set (either through the accessor or the
-constructor), the trigger is called on it. The trigger receives as arguments
-the instance, the new value, and the attribute instance.
+=item trigger => CodeRef
+
+Any time the attribute's value is set (either through the accessor or the constructor), the trigger is called on it. The trigger receives as arguments the instance, the new value, and the attribute instance.
+
+Mouse 0.05 supported more complex triggers, but this behavior is now removed.
=item builder => Str
bucket status). You must specify an appropriate type constraint to use
auto_deref.
+=item lazy_build => 0|1
+
+Automatically define lazy => 1 as well as builder => "_build_$attr", clearer =>
+"clear_$attr', predicate => 'has_$attr' unless they are already defined.
+
=back
=head2 confess error -> BOOM
involves checking for the existence of C<$VERSION>, C<@ISA>, and any
locally-defined method.
-=head1 AUTHOR
+=head1 AUTHORS
Shawn M Moore, C<< <sartak at gmail.com> >>
+Yuval Kogman, C<< <nothingmuch at woobling.org> >>
+
+tokuhirom
+
+Yappo
+
with plenty of code borrowed from L<Class::MOP> and L<Moose>
=head1 BUGS