* Moose::Meta::Attribute::Native
- Fix Hash, which still had 'empty' instead of 'is_empty'. (hdp)
+ * Moose::Meta::Attribute::Native::Trait::Array
+ - Added a number of functions from List::Util and List::MoreUtils,
+ including reduce, shuffle, uniq, and natatime. (doy)
+
* Moose::Exporter
- This module will now generate an init_meta method for your exporting
class if you pass it options for
Moose::Util::MetaRole::apply_metaclass_roles or
apply_base_class_roles. This eliminates a lot of repetitive
boilerplate for typical MooseX modules. (doy).
+ - Documented the with_meta feature, which is a replacement for
+ with_caller. This feature was added by josh a while ago.
+ - The with_caller feature is now deprecated, but will not issue a
+ warning yet. (Dave Rolsky)
+
0.89_01 Wed Sep 2, 2009
* Moose::Meta::Attribute
}
sub extends {
- my $class = shift;
+ my $meta = shift;
Moose->throw_error("Must derive at least one class") unless @_;
# this checks the metaclass to make sure
# it is correct, sometimes it can get out
# of sync when the classes are being built
- Moose::Meta::Class->initialize($class)->superclasses(@_);
+ $meta->superclasses(@_);
}
sub with {
- my $class = shift;
- Moose::Util::apply_all_roles(Class::MOP::Class->initialize($class), @_);
+ Moose::Util::apply_all_roles(shift, @_);
}
sub has {
- my $class = shift;
- my $name = shift;
+ my $meta = shift;
+ my $name = shift;
Moose->throw_error('Usage: has \'name\' => ( key => value, ... )')
if @_ % 2 == 1;
my %options = ( definition_context => Moose::Util::_caller_info(), @_ );
my $attrs = ( ref($name) eq 'ARRAY' ) ? $name : [ ($name) ];
- Class::MOP::Class->initialize($class)->add_attribute( $_, %options ) for @$attrs;
+ $meta->add_attribute( $_, %options ) for @$attrs;
}
sub before {
- my $class = shift;
- Moose::Util::add_method_modifier($class, 'before', \@_);
+ Moose::Util::add_method_modifier(shift, 'before', \@_);
}
sub after {
- my $class = shift;
- Moose::Util::add_method_modifier($class, 'after', \@_);
+ Moose::Util::add_method_modifier(shift, 'after', \@_);
}
sub around {
- my $class = shift;
- Moose::Util::add_method_modifier($class, 'around', \@_);
+ Moose::Util::add_method_modifier(shift, 'around', \@_);
}
our $SUPER_PACKAGE;
}
sub override {
- my $class = shift;
+ my $meta = shift;
my ( $name, $method ) = @_;
- Class::MOP::Class->initialize($class)->add_override_method_modifier( $name => $method );
+ $meta->add_override_method_modifier( $name => $method );
}
sub inner {
}
sub augment {
- my $class = shift;
+ my $meta = shift;
my ( $name, $method ) = @_;
- Class::MOP::Class->initialize($class)->add_augment_method_modifier( $name => $method );
+ $meta->add_augment_method_modifier( $name => $method );
}
Moose::Exporter->setup_import_methods(
- with_caller => [
+ with_meta => [
qw( extends with has before after around override augment)
],
as_is => [
use Moose::Exporter;
Moose::Exporter->setup_import_methods(
- with_caller => ['embiggen'],
- also => 'Moose',
+ with_meta => ['embiggen'],
+ also => 'Moose',
);
sub embiggen {
- my $caller = shift;
- $caller->meta()->embiggen(@_);
+ my $meta = shift;
+ $meta->embiggen(@_);
}
And then the consumer of your extension can use your C<embiggen> sub:
use Moose::Exporter;
Moose::Exporter->setup_import_methods(
- with_caller => ['has_table'],
- also => 'Moose',
+ with_meta => ['has_table'],
+ also => 'Moose',
);
sub init_meta {
}
sub has_table {
- my $caller = shift;
- $caller->meta->table(shift);
+ my $meta = shift;
+ $meta->table(shift);
}
package MyApp::Meta::Class;
Moose> with C<use MyApp::Mooseish>. Similarly, C<no Moose> is now
replaced with C<no MyApp::Mooseish>.
-The C<with_caller> parameter specifies a list of functions that should
+The C<with_meta> parameter specifies a list of functions that should
be wrapped before exporting. The wrapper simply ensures that the
importing package name is the first argument to the function, so we
can do C<S<my $caller = shift;>>.
my $export_recorder = {};
- my ( $exports, $is_removable, $groups )
+ my ( $exports, $is_removable )
= $class->_make_sub_exporter_params(
[ @exports_from, $exporting_package ], $export_recorder );
my $exporter = Sub::Exporter::build_exporter(
{
exports => $exports,
- groups => { default => [':all'], %$groups }
+ groups => { default => [':all'] }
}
);
my $packages = shift;
my $export_recorder = shift;
- my %groups;
my %exports;
my %is_removable;
my $args = $EXPORT_SPEC{$package}
or die "The $package package does not use Moose::Exporter\n";
- # one group for each 'also' package
- $groups{$package} = [
- @{ $args->{with_caller} || [] },
- @{ $args->{with_meta} || [] },
- @{ $args->{as_is} || [] },
- map ":$_",
- keys %{ $args->{groups} || {} }
- ];
-
- for my $name ( @{ $args->{with_caller} } ) {
+ for my $name ( @{ $args->{with_meta} } ) {
my $sub = do {
no strict 'refs';
\&{ $package . '::' . $name };
my $fq_name = $package . '::' . $name;
- $exports{$name} = $class->_make_wrapped_sub(
+ $exports{$name} = $class->_make_wrapped_sub_with_meta(
$fq_name,
$sub,
$export_recorder,
$is_removable{$name} = 1;
}
- for my $name ( @{ $args->{with_meta} } ) {
+ for my $name ( @{ $args->{with_caller} } ) {
my $sub = do {
no strict 'refs';
\&{ $package . '::' . $name };
my $fq_name = $package . '::' . $name;
- $exports{$name} = $class->_make_wrapped_sub_with_meta(
+ $exports{$name} = $class->_make_wrapped_sub(
$fq_name,
$sub,
$export_recorder,
$exports{$coderef_name} = sub {$sub};
}
-
- for my $name ( keys %{ $args->{groups} } ) {
- my $group = $args->{groups}{$name};
-
- if (ref $group eq 'CODE') {
- $groups{$name} = $class->_make_wrapped_group(
- $package,
- $group,
- $export_recorder,
- \%exports,
- \%is_removable
- );
- }
- elsif (ref $group eq 'ARRAY') {
- $groups{$name} = $group;
- }
- }
}
- return ( \%exports, \%is_removable, \%groups );
+ return ( \%exports, \%is_removable );
}
our $CALLER;
use Moose::Exporter;
Moose::Exporter->setup_import_methods(
- with_caller => [ 'has_rw', 'sugar2' ],
- as_is => [ 'sugar3', \&Some::Random::thing ],
- also => 'Moose',
+ with_meta => [ 'has_rw', 'sugar2' ],
+ as_is => [ 'sugar3', \&Some::Random::thing ],
+ also => 'Moose',
);
sub has_rw {
- my ($caller, $name, %options) = @_;
- Class::MOP::class_of($caller)->add_attribute($name,
+ my ( $meta, $name, %options ) = @_;
+ $meta->add_attribute(
+ $name,
is => 'rw',
%options,
);
=over 8
-=item * with_caller => [ ... ]
+=item * with_meta => [ ... ]
This list of function I<names only> will be wrapped and then exported. The
-wrapper will pass the name of the calling package as the first argument to the
-function. Many sugar functions need to know their caller so they can get the
-calling package's metaclass object.
+wrapper will pass the metaclass object for the caller as its first argument.
+
+Many sugar functions will need to use this metaclass object to do something to
+the calling package.
=item * as_is => [ ... ]
This is a list of modules which contain functions that the caller
wants to export. These modules must also use C<Moose::Exporter>. The
most common use case will be to export the functions from C<Moose.pm>.
-Functions specified by C<with_caller> or C<as_is> take precedence over
+Functions specified by C<with_meta> or C<as_is> take precedence over
functions exported by modules specified by C<also>, so that a module
can selectively override functions exported by another module.
it documented here, or think we missed an important feature, please
send us a patch.
-=head1 Version XX
+=head1 Version 0.89_02
=over 4
In particular, we now have C<reduce>, C<shuffle>, C<uniq>, and C<natatime>.
+=item The Moose::Exporter with_caller feature is now deprecated
+
+Use C<with_meta> instead. The C<with_caller> option will start warning in a
+future release.
+
=back
=head1 Version 0.89_01
}
sub with {
- Moose::Util::apply_all_roles( Moose::Meta::Role->initialize(shift), @_ );
+ Moose::Util::apply_all_roles( shift, @_ );
}
sub requires {
- my $meta = Moose::Meta::Role->initialize(shift);
+ my $meta = shift;
croak "Must specify at least one method" unless @_;
$meta->add_required_methods(@_);
}
sub excludes {
- my $meta = Moose::Meta::Role->initialize(shift);
+ my $meta = shift;
croak "Must specify at least one role" unless @_;
$meta->add_excluded_roles(@_);
}
sub has {
- my $meta = Moose::Meta::Role->initialize(shift);
+ my $meta = shift;
my $name = shift;
croak 'Usage: has \'name\' => ( key => value, ... )' if @_ == 1;
my %options = ( definition_context => Moose::Util::_caller_info(), @_ );
sub _add_method_modifier {
my $type = shift;
- my $meta = Moose::Meta::Role->initialize(shift);
+ my $meta = shift;
my $code = pop @_;
for (@_) {
}
sub override {
- my $meta = Moose::Meta::Role->initialize(shift);
+ my $meta = shift;
my ( $name, $code ) = @_;
$meta->add_override_method_modifier( $name, $code );
}
}
Moose::Exporter->setup_import_methods(
- with_caller => [
+ with_meta => [
qw( with requires excludes has before after around override )
],
as_is => [
sub add_method_modifier {
my ( $class_or_obj, $modifier_name, $args ) = @_;
- my $meta = find_meta($class_or_obj);
+ my $meta
+ = $class_or_obj->can('add_before_method_modifier')
+ ? $class_or_obj
+ : find_meta($class_or_obj);
my $code = pop @{$args};
my $add_modifier_method = 'add_' . $modifier_name . '_method_modifier';
if ( my $method_modifier_type = ref( @{$args}[0] ) ) {
use Test::Exception;
{
+
package ExGroups1;
use Moose::Exporter;
use Moose ();
with_meta => ['with_meta1'],
with_caller => ['default_export1'],
as_is => ['default_export2'],
- groups => { all_group => [':all'],
- just_one => ['default_export1'] }
+ groups => {
+ all_group => [':all'],
+ just_one => ['default_export1']
+ }
);
- sub default_export1 { 1 }
- sub default_export2 { 2 }
+ sub default_export1 {1}
+ sub default_export2 {2}
sub with_meta1 (&) {
- my ($meta, $code) = @_;
+ my ( $meta, $code ) = @_;
return $meta;
}
}
{
+
package UseAllGroup;
-
+
ExGroups1->import(':all_group');
::can_ok( __PACKAGE__, 'with_meta1' );
my $meta;
eval q/$meta = with_meta1 { return 'coderef'; }/;
- ::is($@, '', 'calling with_meta1 with prototype is not an error');
+ ::is( $@, '', 'calling with_meta1 with prototype is not an error' );
::isa_ok( $meta, 'Moose::Meta::Class', 'with_meta first argument' );
- ::is( prototype( __PACKAGE__->can('with_meta1') ),
- prototype( ExGroups1->can('with_meta1') ),
- 'using correct prototype on with_meta function' );
+ ::is(
+ prototype( __PACKAGE__->can('with_meta1') ),
+ prototype( ExGroups1->can('with_meta1') ),
+ 'using correct prototype on with_meta function'
+ );
ExGroups1->unimport();
- ::ok( ! __PACKAGE__->can('with_meta1'), __PACKAGE__.'::with_meta1() has been cleaned' );
- ::ok( ! __PACKAGE__->can('default_export1'), __PACKAGE__.'::default_export1() has been cleaned' );
- ::ok( ! __PACKAGE__->can('default_export2'), __PACKAGE__.'::default_export2() has been cleaned' );
- ::ok( ! __PACKAGE__->can('has'), __PACKAGE__.'::has() has been cleaned' );
+ ::ok( !__PACKAGE__->can('with_meta1'),
+ __PACKAGE__ . '::with_meta1() has been cleaned' );
+ ::ok( !__PACKAGE__->can('default_export1'),
+ __PACKAGE__ . '::default_export1() has been cleaned' );
+ ::ok( !__PACKAGE__->can('default_export2'),
+ __PACKAGE__ . '::default_export2() has been cleaned' );
+ ::ok( !__PACKAGE__->can('has'),
+ __PACKAGE__ . '::has() has been cleaned' );
}
{
+
package UseJustOne;
ExGroups1->import(':just_one');
::can_ok( __PACKAGE__, 'default_export1' );
- ::ok( ! __PACKAGE__->can('default_export2'), __PACKAGE__.'::default_export2() was not imported' );
- ::ok( ! __PACKAGE__->can('has'), __PACKAGE__.'::has() was not imported' );
+ ::ok( !__PACKAGE__->can('default_export2'),
+ __PACKAGE__ . '::default_export2() was not imported' );
+ ::ok( !__PACKAGE__->can('has'),
+ __PACKAGE__ . '::has() was not imported' );
ExGroups1->unimport();
- ::ok( ! __PACKAGE__->can('default_export1'), __PACKAGE__.'::default_export1() has been cleared' );
+ ::ok( !__PACKAGE__->can('default_export1'),
+ __PACKAGE__ . '::default_export1() has been cleared' );
}
{
+
package ExGroups2;
use Moose::Exporter;
-
+
Moose::Exporter->setup_import_methods(
also => ['ExGroups1'],
as_is => ['exgroups2_as_is'],
with_caller => ['exgroups2_with_caller'],
- groups => { default => ['exgroups2_as_is'],
- code_group => \&generate_group,
- parent1 => [qw(:ExGroups1 :code_group)],
- parent2 => [qw(:all)] }
+ groups => {
+ default => ['exgroups2_as_is'],
+ code_group => \&generate_group,
+ parent1 => [qw(:ExGroups1 :code_group)],
+ parent2 => [qw(:all)]
+ }
);
- sub exgroups2_as_is { 3 }
+ sub exgroups2_as_is {3}
sub exgroups2_with_caller { 4 }
sub generate_group {
- my ($caller, $group_name, $args, $context) = @_;
+ my ( $caller, $group_name, $args, $context ) = @_;
- ::is($group_name, 'code_group', 'original name is passed to group code');
- ::is($args->{install_as}, $caller . '_code', 'group code arguments match caller');
- ::is($context->{from}, __PACKAGE__, 'defined package name is passed to group code');
+ ::is( $group_name, 'code_group',
+ 'original name is passed to group code' );
+ ::is( $args->{install_as}, $caller . '_code',
+ 'group code arguments match caller' );
+ ::is( $context->{from}, __PACKAGE__,
+ 'defined package name is passed to group code' );
return { $args->{install_as} => \&exported_by_group };
}
sub exported_by_group (&) {
- my ($caller, $coderef) = @_;
+ my ( $caller, $coderef ) = @_;
return $caller;
}
}
{
+
package UseDefault;
-
+
ExGroups2->import;
::can_ok( __PACKAGE__, 'exgroups2_as_is' );
- ::ok( ! __PACKAGE__->can('exgroups2_with_caller'), '"default" group is no longer "all"' );
+ ::ok( !__PACKAGE__->can('exgroups2_with_caller'),
+ '"default" group is no longer "all"' );
}
{
+
package UseCodeGroup;
- ExGroups2->import(':code_group', { install_as => (my $export_name = __PACKAGE__.'_code') });
+ ExGroups2->import( ':code_group',
+ { install_as => ( my $export_name = __PACKAGE__ . '_code' ) } );
::can_ok( __PACKAGE__, $export_name );
- ::ok( &UseCodeGroup_code() eq __PACKAGE__, 'code group exports act like "with_caller" subs' );
- ::lives_ok(sub { UseCodeCodeGroup_code { return 'code block'; } }, 'code group exports keep their prototypes');
+ ::ok( &UseCodeGroup_code() eq __PACKAGE__,
+ 'code group exports act like "with_caller" subs' );
+ ::lives_ok(
+ sub {
+ UseCodeCodeGroup_code { return 'code block'; };
+ },
+ 'code group exports keep their prototypes'
+ );
- ::ok( ! __PACKAGE__->can('exgroups2_as_is'), 'code group will not automatically export any symbols' );
+ ::ok( !__PACKAGE__->can('exgroups2_as_is'),
+ 'code group will not automatically export any symbols' );
ExGroups2->unimport;
-
- ::ok( ! __PACKAGE__->can($export_name),
- 'dynamically-named '. __PACKAGE__."::$export_name() has been cleared" );
+
+ ::ok(
+ !__PACKAGE__->can($export_name),
+ 'dynamically-named '
+ . __PACKAGE__
+ . "::$export_name() has been cleared"
+ );
}
{
+
package UseParent1;
- ExGroups2->import(':parent1', { install_as => (my $export_name = __PACKAGE__.'_code') });
+ ExGroups2->import( ':parent1',
+ { install_as => ( my $export_name = __PACKAGE__ . '_code' ) } );
::can_ok( __PACKAGE__, $export_name );
::can_ok( __PACKAGE__, 'default_export1' );
ExGroups2->unimport;
- ::ok( ! __PACKAGE__->can($export_name), __PACKAGE__."::$export_name() has been cleared" );
- ::ok( ! __PACKAGE__->can('default_export1'), __PACKAGE__.'::default_export1() has been cleaned' );
- ::ok( ! __PACKAGE__->can('default_export2'), __PACKAGE__.'::default_export2() has been cleaned' );
- ::ok( ! __PACKAGE__->can('has'), __PACKAGE__.'::has() has been cleaned' );
+ ::ok( !__PACKAGE__->can($export_name),
+ __PACKAGE__ . "::$export_name() has been cleared" );
+ ::ok( !__PACKAGE__->can('default_export1'),
+ __PACKAGE__ . '::default_export1() has been cleaned' );
+ ::ok( !__PACKAGE__->can('default_export2'),
+ __PACKAGE__ . '::default_export2() has been cleaned' );
+ ::ok( !__PACKAGE__->can('has'),
+ __PACKAGE__ . '::has() has been cleaned' );
}
{
+
package UseParent2;
- ExGroups2->import(':parent2', { install_as => (my $export_name = __PACKAGE__.'_code') });
+ ExGroups2->import( ':parent2',
+ { install_as => ( my $export_name = __PACKAGE__ . '_code' ) } );
- ::ok( ! __PACKAGE__->can($export_name), '"all" group will not call code groups' );
+ ::ok( !__PACKAGE__->can($export_name),
+ '"all" group will not call code groups' );
::can_ok( __PACKAGE__, 'exgroups2_as_is' );
::can_ok( __PACKAGE__, 'exgroups2_with_caller' );
::can_ok( __PACKAGE__, 'default_export1' );
ExGroups2->unimport;
- ::ok( ! __PACKAGE__->can('exgroups2_as_is'), __PACKAGE__.'::exgroups2_as_is() has been cleaned' );
- ::ok( ! __PACKAGE__->can('exgroups2_with_caller'), __PACKAGE__.'::exgroups2_with_caller() has been cleaned' );
- ::ok( ! __PACKAGE__->can('default_export1'), __PACKAGE__.'::default_export1() has been cleaned' );
- ::ok( ! __PACKAGE__->can('has'), __PACKAGE__.'::has() has been cleaned' );
+ ::ok( !__PACKAGE__->can('exgroups2_as_is'),
+ __PACKAGE__ . '::exgroups2_as_is() has been cleaned' );
+ ::ok( !__PACKAGE__->can('exgroups2_with_caller'),
+ __PACKAGE__ . '::exgroups2_with_caller() has been cleaned' );
+ ::ok( !__PACKAGE__->can('default_export1'),
+ __PACKAGE__ . '::default_export1() has been cleaned' );
+ ::ok( !__PACKAGE__->can('has'),
+ __PACKAGE__ . '::has() has been cleaned' );
}
BEGIN {
eval "use Test::Output;";
plan skip_all => "Test::Output is required for this test" if $@;
- plan tests => 49;
+ plan tests => 65;
}
use Moose ();
sub wrapped1 {
- my $caller = shift;
- return $caller . ' called wrapped1';
+ my $meta = shift;
+ return $meta->name . ' called wrapped1';
}
Moose::Exporter->setup_import_methods(
- with_caller => ['wrapped1'],
- also => 'Moose',
+ with_meta => ['wrapped1'],
+ also => 'Moose',
);
}
::ok(!__PACKAGE__->can('does_not_exist'),
"undefined subs do not get exported");
+
+ package AllOptions;
+ use Moose ();
+ use Moose::Exporter;
+
+ Moose::Exporter->setup_import_methods(
+ also => ['Moose'],
+ with_meta => [ 'with_meta1', 'with_meta2' ],
+ with_caller => [ 'with_caller1', 'with_caller2' ],
+ as_is => ['as_is1'],
+ );
+
+ sub with_caller1 {
+ return @_;
+ }
+
+ sub with_caller2 (&) {
+ return @_;
+ }
+
+ sub as_is1 {2}
+
+ sub with_meta1 {
+ return @_;
+ }
+
+ sub with_meta2 (&) {
+ return @_;
+ }
+}
+
+{
+ package UseAllOptions;
+
+ AllOptions->import();
+}
+
+{
+ can_ok( 'UseAllOptions', $_ )
+ for qw( with_meta1 with_meta2 with_caller1 with_caller2 as_is1 );
+
+ {
+ my ( $caller, $arg1 ) = UseAllOptions::with_caller1(42);
+ is( $caller, 'UseAllOptions', 'with_caller wrapped sub gets the right caller' );
+ is( $arg1, 42, 'with_caller wrapped sub returns argument it was passed' );
+ }
+
+ {
+ my ( $meta, $arg1 ) = UseAllOptions::with_meta1(42);
+ isa_ok( $meta, 'Moose::Meta::Class', 'with_meta first argument' );
+ is( $arg1, 42, 'with_meta1 returns argument it was passed' );
+ }
+
+ is(
+ prototype( UseAllOptions->can('with_caller2') ),
+ prototype( AllOptions->can('with_caller2') ),
+ 'using correct prototype on with_meta function'
+ );
+
+ is(
+ prototype( UseAllOptions->can('with_meta2') ),
+ prototype( AllOptions->can('with_meta2') ),
+ 'using correct prototype on with_meta function'
+ );
+
+ {
+ package UseAllOptions;
+ AllOptions->unimport();
+ }
+
+ ok( ! UseAllOptions->can($_), "UseAllOptions::$_ has been unimported" )
+ for qw( with_meta1 with_meta2 with_caller1 with_caller2 as_is1 );
}