summaryrefslogtreecommitdiff
path: root/cpan/Test-Simple/lib/Test/Stream/ArrayBase.pm
diff options
context:
space:
mode:
Diffstat (limited to 'cpan/Test-Simple/lib/Test/Stream/ArrayBase.pm')
-rw-r--r--cpan/Test-Simple/lib/Test/Stream/ArrayBase.pm374
1 files changed, 374 insertions, 0 deletions
diff --git a/cpan/Test-Simple/lib/Test/Stream/ArrayBase.pm b/cpan/Test-Simple/lib/Test/Stream/ArrayBase.pm
new file mode 100644
index 0000000000..967a070d9a
--- /dev/null
+++ b/cpan/Test-Simple/lib/Test/Stream/ArrayBase.pm
@@ -0,0 +1,374 @@
+package Test::Stream::ArrayBase;
+use strict;
+use warnings;
+
+use Test::Stream::ArrayBase::Meta;
+use Test::Stream::Carp qw/confess croak/;
+use Scalar::Util qw/blessed reftype/;
+
+use Test::Stream::Exporter();
+
+sub import {
+ my $class = shift;
+ my $caller = caller;
+
+ $class->apply_to($caller, @_);
+}
+
+sub apply_to {
+ my $class = shift;
+ my ($caller, %args) = @_;
+
+ # Make the calling class an exporter.
+ my $exp_meta = Test::Stream::Exporter::Meta->new($caller);
+ Test::Stream::Exporter->export_to($caller, 'import')
+ unless $args{no_import};
+
+ my $ab_meta = Test::Stream::ArrayBase::Meta->new($caller);
+
+ my $ISA = do { no strict 'refs'; \@{"$caller\::ISA"} };
+
+ if ($args{base}) {
+ my ($base) = grep { $_->isa($class) } @$ISA;
+
+ croak "$caller is already a subclass of '$base', cannot subclass $args{base}"
+ if $base;
+
+ my $file = $args{base};
+ $file =~ s{::}{/}g;
+ $file .= ".pm";
+ require $file unless $INC{$file};
+
+ my $pmeta = Test::Stream::ArrayBase::Meta->get($args{base});
+ croak "Base class '$args{base}' is not a subclass of $class!"
+ unless $pmeta;
+
+ push @$ISA => $args{base};
+
+ $ab_meta->subclass($args{base});
+ }
+ elsif( !grep { $_->isa($class) } @$ISA) {
+ push @$ISA => $class;
+ $ab_meta->baseclass();
+ }
+
+ if ($args{accessors}) {
+ $ab_meta->add_accessor($_) for @{$args{accessors}};
+ }
+
+ 1;
+}
+
+sub new {
+ my $class = shift;
+ my $self = bless [@_], $class;
+ $self->init if $self->can('init');
+ return $self;
+}
+
+sub new_from_pairs {
+ my $class = shift;
+ my %params = @_;
+ my $self = bless [], $class;
+
+ while (my ($k, $v) = each %params) {
+ my $const = uc($k);
+ croak "$class has no accessor named '$k'" unless $class->can($const);
+ my $id = $class->$const;
+ $self->[$id] = $v;
+ }
+
+ $self->init if $self->can('init');
+ return $self;
+}
+
+sub to_hash {
+ my $array_obj = shift;
+ my $meta = Test::Stream::ArrayBase::Meta->get(blessed $array_obj);
+ my $fields = $meta->fields;
+ my %out;
+ for my $f (keys %$fields) {
+ my $i = $fields->{$f};
+ my $val = $array_obj->[$i];
+ my $ao = blessed($val) && $val->isa(__PACKAGE__);
+ $out{$f} = $ao ? $val->to_hash : $val;
+ }
+ return \%out;
+};
+
+1;
+
+__END__
+
+=head1 NAME
+
+Test::Stream::ArrayBase - Base class for classes that use an arrayref instead
+of a hash.
+
+=head1 SYNOPSYS
+
+A class:
+
+ package My::Class;
+ use strict;
+ use warnings;
+
+ use Test::Stream::ArrayBase accessors => [qw/foo bar baz/];
+
+ # Chance to initialize defaults
+ sub init {
+ my $self = shift; # No other args
+ $self->[FOO] ||= "foo";
+ $self->[BAR] ||= "bar";
+ $self->[BAZ] ||= "baz";
+ }
+
+ sub print {
+ print join ", " => map { $self->[$_] } FOO, BAR, BAZ;
+ }
+
+Subclass it
+
+ package My::Subclass;
+ use strict;
+ use warnings;
+ use Test::Stream::ArrayBase base => 'My::Class', # subclass
+ accessors => ['bat'];
+
+ sub init {
+ my $self = shift;
+
+ # We get the constants from the base class for free.
+ $self->[FOO] ||= 'SubFoo';
+ $self->[BAT] || = 'bat';
+
+ $self->SUPER::init();
+ }
+
+use it:
+
+ package main;
+ use strict;
+ use warnings;
+ use My::Class;
+
+ my $one = My::Class->new('MyFoo', 'MyBar');
+
+ # Accessors!
+ my $foo = $one->foo; # 'MyFoo'
+ my $bar = $one->bar; # 'MyBar'
+ my $baz = $one->baz; # Defaulted to: 'baz'
+
+ # Setters!
+ $one->set_foo('A Foo');
+ $one->set_bar('A Bar');
+ $one->set_baz('A Baz');
+
+ # It is an arrayref, you can do this!
+ my ($foo, $bar, $baz) = @$one;
+
+ # import constants:
+ use My::Class qw/FOO BAR BAZ/;
+
+ $one->[FOO] = 'xxx';
+
+=head1 DESCRIPTION
+
+This package is used to generate classes based on arrays instead of hashes. The
+primary motivation for this is performance (not premature!). Using this class
+will give you a C<new()> method, as well as generating accessors you request.
+Generated accessors will be getters, C<set_ACCESSOR> setters will also be
+generated for you. You also get constants for each accessor (all caps) which
+return the index into the array for that accessor. Single inheritence is also
+supported. For obvious reasons you cannot use multiple inheritence with an
+array based object.
+
+=head1 METHODS
+
+=head2 PROVIDED BY ARRAY BASE
+
+=over 4
+
+=item $it = $class->new(@VALUES)
+
+Create a new instance from a list of ordered values.
+
+=item $it = $class->new_from_pairs(%ACCESSOR_VAL_PAIRS)
+
+Create a new instance using key/value pairs.
+
+=item $hr = $it->to_hash()
+
+Get a hashref dump of the object. This will also dump any ArrayBase objects
+within to a hash, but only surface-depth ones.
+
+=item $it->import()
+
+This import method is actually provided by L<Test::Stream::Exporter> and allows
+you to import the constants generated for you.
+
+=back
+
+=head2 HOOKS
+
+=over 4
+
+=item $self->init()
+
+This gives you the chance to set some default values to your fields. The only
+argument is C<$self> with its indexes already set from the constructor.
+
+=back
+
+=head1 ACCESSORS
+
+To generate accessors you list them when using the module:
+
+ use Test::Stream::ArrayBase accessors => [qw/foo/];
+
+This will generate the following subs in your namespace:
+
+=over 4
+
+=item import()
+
+This will let you import the constants
+
+=item foo()
+
+Getter, used to get the value of the C<foo> field.
+
+=item set_foo()
+
+Setter, used to set the value of the C<foo> field.
+
+=item FOO()
+
+Constant, returs the field C<foo>'s index into the class arrayref. This
+function is also exported, but only when requested. Subclasses will also get
+this function as a constant, not simply a method, that means it is copied into
+the subclass namespace.
+
+=back
+
+=head1 SUBCLASSING
+
+You can subclass an existing ArrayBase class.
+
+ use Test::Stream::ArrayBase
+ base => 'Another::ArrayBase::Class',
+ accessors => [qw/foo bar baz/],
+
+Once an ArrayBase class is used as a subclass it is locked and no new fields
+can be added. All fields in any subclass will start at the next index after the
+last field of the parent. All constants from base classes are added to
+subclasses automatically.
+
+=head1 WHY?
+
+Switching to an arrayref base has resulted in significant performance boosts.
+
+When Test::Builder was initially refactored to support events, it was slow
+beyond reason. A large part of the slowdown was due to the use of proper
+methods instead of directly accessing elements. We also switched to using a LOT
+more objects that have methods.
+
+=encoding utf8
+
+=head1 SOURCE
+
+The source code repository for Test::More can be found at
+F<http://github.com/Test-More/test-more/>.
+
+=head1 MAINTAINER
+
+=over 4
+
+=item Chad Granum E<lt>exodist@cpan.orgE<gt>
+
+=back
+
+=head1 AUTHORS
+
+The following people have all contributed to the Test-More dist (sorted using
+VIM's sort function).
+
+=over 4
+
+=item Chad Granum E<lt>exodist@cpan.orgE<gt>
+
+=item Fergal Daly E<lt>fergal@esatclear.ie>E<gt>
+
+=item Mark Fowler E<lt>mark@twoshortplanks.comE<gt>
+
+=item Michael G Schwern E<lt>schwern@pobox.comE<gt>
+
+=item 唐鳳
+
+=back
+
+=head1 COPYRIGHT
+
+There has been a lot of code migration between modules,
+here are all the original copyrights together:
+
+=over 4
+
+=item Test::Stream
+
+=item Test::Stream::Tester
+
+Copyright 2014 Chad Granum E<lt>exodist7@gmail.comE<gt>.
+
+This program is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+See F<http://www.perl.com/perl/misc/Artistic.html>
+
+=item Test::Simple
+
+=item Test::More
+
+=item Test::Builder
+
+Originally authored by Michael G Schwern E<lt>schwern@pobox.comE<gt> with much
+inspiration from Joshua Pritikin's Test module and lots of help from Barrie
+Slaymaker, Tony Bowden, blackstar.co.uk, chromatic, Fergal Daly and the perl-qa
+gang.
+
+Idea by Tony Bowden and Paul Johnson, code by Michael G Schwern
+E<lt>schwern@pobox.comE<gt>, wardrobe by Calvin Klein.
+
+Copyright 2001-2008 by Michael G Schwern E<lt>schwern@pobox.comE<gt>.
+
+This program is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+See F<http://www.perl.com/perl/misc/Artistic.html>
+
+=item Test::use::ok
+
+To the extent possible under law, 唐鳳 has waived all copyright and related
+or neighboring rights to L<Test-use-ok>.
+
+This work is published from Taiwan.
+
+L<http://creativecommons.org/publicdomain/zero/1.0>
+
+=item Test::Tester
+
+This module is copyright 2005 Fergal Daly <fergal@esatclear.ie>, some parts
+are based on other people's work.
+
+Under the same license as Perl itself
+
+See http://www.perl.com/perl/misc/Artistic.html
+
+=item Test::Builder::Tester
+
+Copyright Mark Fowler E<lt>mark@twoshortplanks.comE<gt> 2002, 2004.
+
+This program is free software; you can redistribute it
+and/or modify it under the same terms as Perl itself.
+
+=back