r29554@brandon-blacks-computer (orig r2002): blblack | 2007-01-04 19:17:22 -0600
make new branch for PurePerl
r29555@brandon-blacks-computer (orig r2003): blblack | 2007-01-04 20:07:32 -0600
break out most of the code to ::PurePerl
r29700@brandon-blacks-computer (orig r2114): blblack | 2007-04-03 13:37:11 -0500
updated for core support
r29702@brandon-blacks-computer (orig r2116): blblack | 2007-04-03 15:35:26 -0500
latest sync-ed up c3.patch against perl-current
r30415@brandon-blacks-computer (orig r2140): blblack | 2007-04-11 22:56:34 -0500
new c3.patch with next::method in core, new changes here to support it
this branch is now getting ugly, will probably wipe it and take some of the diffs to a new branch soon, this PurePerl in the package name thing was a poor idea
r30419@brandon-blacks-computer (orig r2141): blblack | 2007-04-12 10:52:00 -0500
NEXT/next::method thing needed updated for removal of the c3 assumption in next::method
r30428@brandon-blacks-computer (orig r2143): blblack | 2007-04-12 12:53:35 -0500
got rid of PurePerl in classnames, fixed up a few other things, possible alpha release soon
r30453@brandon-blacks-computer (orig r2150): blblack | 2007-04-13 00:15:39 -0500
fix pod coverage, etc
r30508@brandon-blacks-computer (orig r2151): blblack | 2007-04-13 16:55:05 -0500
0.15_01 final changes (includes final patch, works with normal and patched perls)
r30536@brandon-blacks-computer (orig r2169): blblack | 2007-04-15 12:11:14 -0500
Class::C3::XS support
r30544@brandon-blacks-computer (orig r2177): blblack | 2007-04-16 00:04:51 -0500
0.15_02, supports Class::C3::XS
r30573@brandon-blacks-computer (orig r2186): blblack | 2007-04-17 11:04:41 -0500
replace patch with link
r30574@brandon-blacks-computer (orig r2187): blblack | 2007-04-17 11:05:59 -0500
manifest update
r30615@brandon-blacks-computer (orig r2191): blblack | 2007-04-19 16:45:54 -0500
0.15_05, assumes 5.9.5 has patch
r30761@brandon-blacks-computer (orig r2240): blblack | 2007-04-30 23:35:09 -0500
support XS calc_mdt, improved BEGIN block
r30773@brandon-blacks-computer (orig r2250): blblack | 2007-05-01 11:20:49 -0500
Module::Install, small things
r30774@brandon-blacks-computer (orig r2251): blblack | 2007-05-01 11:31:29 -0500
oops, fix META.yml
-use Module::Build;
-
-use strict;
-
-my $build = Module::Build->new(
- module_name => 'Class::C3',
- license => 'perl',
- requires => {
- 'Scalar::Util' => 1.10,
- 'Algorithm::C3' => 0.06,
- },
- optional => {},
- build_requires => {
- 'Test::More' => '0.47',
- 'Test::Exception' => 0.15,
- },
- create_makefile_pl => 'traditional',
- recursive_test_files => 1,
- add_to_cleanup => [
- 'META.yml', '*.bak', '*.gz', 'Makefile.PL',
- ],
-);
-
-$build->create_build_script;
-
+# Dear Distribution Packager. This use of require is intentional.
+# Module::Install detects Build.PL usage and acts accordingly.
+require 'Makefile.PL';
Revision history for Perl extension Class::C3.
+0.15_06
+ - Converted to Module::Install
+ - No deps w/ 5.9.5+
+ - Cleaned up the BEGIN stuff a bit
+ - Added support for C::C3::XS 0.01_07
+ - Fixed overload fallback edge cases.
+
+0.15_05 Thurs, Apr 19, 2007
+ - Patch is in the latest perl-current now,
+ and this dev release assumes 5.9.5 has the patch
+
+0.15_03 Tue, Apr 17, 2007
+ - New c3.patch, improves threads compat and
+ mem mgmt.
+
+0.15_02 Sun, Apr 15, 2007
- Fix for overloading to method name string,
from Ittetsu Miyazaki.
- - Fixed overload fallback edge cases.
+ - Supports Class::C3::XS
+
+0.15_01 Fri, Apr 13, 2007
+ - Supports bleadperl + c3 patches (experimental)
0.14 Tues, Sep 19, 2006
- Fix for rt.cpan.org #21558
--- /dev/null
+
+Please package this dist using Perl < 5.9.5, so that the deps show up in META.yml
Build.PL
ChangeLog
+inc/Module/AutoInstall.pm
+inc/Module/Install.pm
+inc/Module/Install/AutoInstall.pm
+inc/Module/Install/Base.pm
+inc/Module/Install/Build.pm
+inc/Module/Install/Can.pm
+inc/Module/Install/Fetch.pm
+inc/Module/Install/Include.pm
+inc/Module/Install/Makefile.pm
+inc/Module/Install/Metadata.pm
+inc/Module/Install/Win32.pm
+inc/Module/Install/WriteAll.pm
+lib/Class/C3.pm
+lib/Class/C3/next.pm
+Makefile.PL
MANIFEST This list of files
META.yml
-Makefile.PL
-README
-lib/Class/C3.pm
opt/c3.pm
+README
t/00_load.t
t/01_MRO.t
t/02_MRO.t
t/21_C3_with_overload.t
t/22_uninitialize.t
t/23_multi_init.t
+t/24_more_overload.t
t/30_next_method.t
t/31_next_method_skip.t
t/32_next_method_edge_cases.t
^blibdirs$
\.old$
^#.*#$
-^\.#
\ No newline at end of file
+^\.#
+\.gz$
+DEV_README
--- /dev/null
+use inc::Module::Install;
+
+name 'Class-C3';
+all_from 'lib/Class/C3.pm';
+
+# Class::C3 under 5.9.5+ has no deps
+if($] < 5.009_005) {
+ build_requires 'Test::More' => '0.47';
+
+ feature 'XS Speedups',
+ ($] < 5.009_005 ? ('Class::C3::XS' => '0.02') : ());
+
+ # Would like to disable these if they answer yes above too ...
+ requires 'Algorithm::C3' => '0.06';
+ requires 'Scalar::Util' => '1.10';
+}
+
+auto_install;
+WriteAll;
-Class::C3 version 0.14
+Class::C3 version 0.15_06
===========================
INSTALLATION
Algorithm::C3 0.06
Scalar::Util 1.10
+Additionally, this module will optionally take advantage of
+these if installed:
+
+ Class::C3::XS 0.01_07
+
+SPECIAL NOTE FOR 0.15_06
+
+To try this with the new perl core c3 support,
+download the most recent copy perl-current:
+
+http://mirrors.develooper.com/perl/APC/perl-current-snap/
+
+sh Configure -Dusedevel -Dprefix=/where/I/want/it -d -e && make && make test && make install
+
+then try your C3-using software against this perl + Class::C3 0.15_06.
+
COPYRIGHT AND LICENCE
Copyright (C) 2005, 2006 Infinity Interactive, Inc.
use strict;
use warnings;
-use Scalar::Util 'blessed';
-use Algorithm::C3;
+our $VERSION = '0.15_06';
-our $VERSION = '0.14';
+our $C3_IN_CORE;
+our $C3_XS;
+
+BEGIN {
+ if($] > 5.009_004) {
+ $C3_IN_CORE = 1;
+ }
+ else {
+ eval "require Class::C3::XS";
+ my $error = $@;
+ if(!$error) {
+ $C3_XS = 1;
+ }
+ else {
+ die $error if $error !~ /\blocate\b/;
+ require Algorithm::C3;
+ require Class::C3::next;
+ }
+ }
+}
# this is our global stash of both
# MRO's and method dispatch tables
# skip if the caller is main::
# since that is clearly not relevant
return if $class eq 'main';
+
return if $TURN_OFF_C3;
+ mro::set_mro($class, 'c3') if $C3_IN_CORE;
+
# make a note to calculate $class
# during INIT phase
$MRO{$class} = undef unless exists $MRO{$class};
## initializers
sub initialize {
+ %next::METHOD_CACHE = ();
# why bother if we don't have anything ...
return unless keys %MRO;
- if($_initialized) {
- uninitialize();
- $MRO{$_} = undef foreach keys %MRO;
+ if($C3_IN_CORE) {
+ mro::set_mro($_, 'c3') for keys %MRO;
+ }
+ else {
+ if($_initialized) {
+ uninitialize();
+ $MRO{$_} = undef foreach keys %MRO;
+ }
+ _calculate_method_dispatch_tables();
+ _apply_method_dispatch_tables();
+ $_initialized = 1;
}
- _calculate_method_dispatch_tables();
- _apply_method_dispatch_tables();
- %next::METHOD_CACHE = ();
- $_initialized = 1;
}
sub uninitialize {
# why bother if we don't have anything ...
- return unless keys %MRO;
- _remove_method_dispatch_tables();
%next::METHOD_CACHE = ();
- $_initialized = 0;
+ return unless keys %MRO;
+ if($C3_IN_CORE) {
+ mro::set_mro($_, 'dfs') for keys %MRO;
+ }
+ else {
+ _remove_method_dispatch_tables();
+ $_initialized = 0;
+ }
}
sub reinitialize { goto &initialize }
## functions for applying C3 to classes
sub _calculate_method_dispatch_tables {
+ return if $C3_IN_CORE;
my %merge_cache;
foreach my $class (keys %MRO) {
_calculate_method_dispatch_table($class, \%merge_cache);
}
sub _calculate_method_dispatch_table {
+ return if $C3_IN_CORE;
my ($class, $merge_cache) = @_;
no strict 'refs';
my @MRO = calculateMRO($class, $merge_cache);
}
sub _apply_method_dispatch_tables {
+ return if $C3_IN_CORE;
foreach my $class (keys %MRO) {
_apply_method_dispatch_table($class);
}
}
sub _apply_method_dispatch_table {
+ return if $C3_IN_CORE;
my $class = shift;
no strict 'refs';
${"${class}::()"} = $MRO{$class}->{has_overload_fallback}
}
sub _remove_method_dispatch_tables {
+ return if $C3_IN_CORE;
foreach my $class (keys %MRO) {
_remove_method_dispatch_table($class);
- }
+ }
}
sub _remove_method_dispatch_table {
+ return if $C3_IN_CORE;
my $class = shift;
no strict 'refs';
delete ${"${class}::"}{"()"} if $MRO{$class}->{has_overload_fallback};
delete ${"${class}::"}{$method}
if defined *{"${class}::${method}"}{CODE} &&
(*{"${class}::${method}"}{CODE} eq $MRO{$class}->{methods}->{$method}->{code});
- }
+ }
}
-## functions for calculating C3 MRO
-
sub calculateMRO {
my ($class, $merge_cache) = @_;
+
return Algorithm::C3::merge($class, sub {
no strict 'refs';
@{$_[0] . '::ISA'};
}, $merge_cache);
}
-package # hide me from PAUSE
- next;
-
-use strict;
-use warnings;
-
-use Scalar::Util 'blessed';
-
-our $VERSION = '0.05';
+# Method overrides to support 5.9.5+ or Class::C3::XS
-our %METHOD_CACHE;
+sub _core_calculateMRO { @{mro::get_linear_isa($_[0])} }
-sub method {
- my $indirect = caller() =~ /^(?:next|maybe::next)$/;
- my $level = $indirect ? 2 : 1;
-
- my ($method_caller, $label, @label);
- while ($method_caller = (caller($level++))[3]) {
- @label = (split '::', $method_caller);
- $label = pop @label;
- last unless
- $label eq '(eval)' ||
- $label eq '__ANON__';
- }
- my $caller = join '::' => @label;
- my $self = $_[0];
- my $class = blessed($self) || $self;
-
- my $method = $METHOD_CACHE{"$class|$caller|$label"} ||= do {
-
- my @MRO = Class::C3::calculateMRO($class);
-
- my $current;
- while ($current = shift @MRO) {
- last if $caller eq $current;
- }
-
- no strict 'refs';
- my $found;
- foreach my $class (@MRO) {
- next if (defined $Class::C3::MRO{$class} &&
- defined $Class::C3::MRO{$class}{methods}{$label});
- last if (defined ($found = *{$class . '::' . $label}{CODE}));
- }
-
- $found;
- };
-
- return $method if $indirect;
-
- die "No next::method '$label' found for $self" if !$method;
-
- goto &{$method};
+if($C3_IN_CORE) {
+ no warnings 'redefine';
+ *Class::C3::calculateMRO = \&_core_calculateMRO;
+}
+elsif($C3_XS) {
+ no warnings 'redefine';
+ *Class::C3::calculateMRO = \&Class::C3::XS::calculateMRO;
+ *Class::C3::_calculate_method_dispatch_table
+ = \&Class::C3::XS::_calculate_method_dispatch_table;
}
-
-sub can { method($_[0]) }
-
-package # hide me from PAUSE
- maybe::next;
-
-use strict;
-use warnings;
-
-our $VERSION = '0.01';
-
-sub method { (next::method($_[0]) || return)->(@_) }
1;
D->can('hello')->(); # can() also works correctly
UNIVERSAL::can('D', 'hello'); # as does UNIVERSAL::can()
+=head1 SPECIAL NOTE FOR 0.15_06
+
+To try this with the new perl core c3 support,
+download the most recent copy perl-current:
+
+http://mirrors.develooper.com/perl/APC/perl-current-snap/
+
+sh Configure -Dusedevel -Dprefix=/where/I/want/it -d -e && make && make test && make install
+
+then try your C3-using software against this perl + Class::C3 0.15_06.
+
=head1 DESCRIPTION
This is pragma to change Perl 5's standard method resolution order from depth-first left-to-right
=back
+=head1 COMPATIBILITY
+
+If your software requires Perl 5.9.5 or higher, you do not need L<Class::C3>, you can simply C<use mro 'c3'>, and not worry about C<initialize()>, avoid some of the above caveats, and get the best possible performance. See L<mro> for more details.
+
+If your software is meant to work on earlier Perls, use L<Class::C3> as documented here. L<Class::C3> will detect Perl 5.9.5+ and take advantage of the core support when available.
+
+=head1 Class::C3::XS
+
+This module will load L<Class::C3::XS> if it's installed and you are running on a Perl version older than 5.9.5. Installing this is recommended when possible, as it results in significant performance improvements (but unlike the 5.9.5+ core support, it still has all of the same caveats as L<Class::C3>).
+
=head1 CODE COVERAGE
I use B<Devel::Cover> to test the code coverage of my tests, below is the B<Devel::Cover> report on this
--- /dev/null
+package # hide me from PAUSE
+ next;
+
+use strict;
+use warnings;
+no warnings 'redefine'; # for 00load.t w/ core support
+
+use Scalar::Util 'blessed';
+
+our $VERSION = '0.06';
+
+our %METHOD_CACHE;
+
+sub method {
+ my $self = $_[0];
+ my $class = blessed($self) || $self;
+ my $indirect = caller() =~ /^(?:next|maybe::next)$/;
+ my $level = $indirect ? 2 : 1;
+
+ my ($method_caller, $label, @label);
+ while ($method_caller = (caller($level++))[3]) {
+ @label = (split '::', $method_caller);
+ $label = pop @label;
+ last unless
+ $label eq '(eval)' ||
+ $label eq '__ANON__';
+ }
+
+ my $method;
+
+ my $caller = join '::' => @label;
+
+ $method = $METHOD_CACHE{"$class|$caller|$label"} ||= do {
+
+ my @MRO = Class::C3::calculateMRO($class);
+
+ my $current;
+ while ($current = shift @MRO) {
+ last if $caller eq $current;
+ }
+
+ no strict 'refs';
+ my $found;
+ foreach my $class (@MRO) {
+ next if (defined $Class::C3::MRO{$class} &&
+ defined $Class::C3::MRO{$class}{methods}{$label});
+ last if (defined ($found = *{$class . '::' . $label}{CODE}));
+ }
+
+ $found;
+ };
+
+ return $method if $indirect;
+
+ die "No next::method '$label' found for $self" if !$method;
+
+ goto &{$method};
+}
+
+sub can { method($_[0]) }
+
+package # hide me from PAUSE
+ maybe::next;
+
+use strict;
+use warnings;
+no warnings 'redefine'; # for 00load.t w/ core support
+
+our $VERSION = '0.02';
+
+sub method { (next::method($_[0]) || return)->(@_) }
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Class::C3::next - Pure-perl next::method and friends
+
+=head1 DESCRIPTION
+
+This module is used internally by L<Class::C3> when
+neccesary, and shouldn't be used (or required in
+distribution dependencies) directly. It
+defines C<next::method>, C<next::can>, and
+C<maybe::next::method> in pure perl.
+
+=head1 AUTHOR
+
+Stevan Little, E<lt>stevan@iinteractive.comE<gt>
+
+Brandon L. Black, E<lt>blblack@gmail.comE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 2005, 2006 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.
+
+=cut
use strict;
use warnings;
-use Test::More tests => 1;
+use Test::More tests => 2;
BEGIN {
use_ok('Class::C3');
-}
\ No newline at end of file
+ use_ok('Class::C3::next');
+}
=cut
-{
- package X;
- use Class::C3;
-
- package Y;
- use Class::C3;
-
- package XY;
- use Class::C3;
- use base ('X', 'Y');
-
- package YX;
- use Class::C3;
- use base ('Y', 'X');
-
- package Z;
- # use Class::C3; << Dont do this just yet ...
- use base ('XY', 'YX');
-}
+eval q{
+ {
+ package X;
+ use Class::C3;
+
+ package Y;
+ use Class::C3;
+
+ package XY;
+ use Class::C3;
+ use base ('X', 'Y');
+
+ package YX;
+ use Class::C3;
+ use base ('Y', 'X');
+
+ package Z;
+ eval 'use Class::C3' if $Class::C3::C3_IN_CORE;
+ use base ('XY', 'YX');
+ }
-Class::C3::initialize();
+ Class::C3::initialize();
-eval {
# now try to calculate the MRO
# and watch it explode :)
- Class::C3::calculateMRO('Z')
+ Class::C3::calculateMRO('Z');
};
#diag $@;
-like($@, qr/^Inconsistent hierarchy/, '... got the right error with an inconsistent hierarchy');
+like($@, qr/Inconsistent hierarchy /, '... got the right error with an inconsistent hierarchy');
[ qw(Diamond_D Diamond_B Diamond_E Diamond_C Diamond_A) ],
'... got the new MRO for Diamond_D');
-is(Diamond_D->hello, 'Diamond_C::hello', '... method still resolves with old MRO');
+# Doesn't work with core support, since reinit is not neccesary and the change
+# takes effect immediately
+SKIP: {
+ skip "This test does not work with a c3-patched perl interpreter", 1
+ if $Class::C3::C3_IN_CORE;
+ is(Diamond_D->hello, 'Diamond_C::hello', '... method still resolves with old MRO');
+}
Class::C3::reinitialize();