[libclass-tiny-perl] 09/19: validate args after BUILD; allow BUILD to hide args
gregor herrmann
gregoa at debian.org
Sun May 31 14:03:11 UTC 2015
This is an automated email from the git hooks/post-receive script.
gregoa pushed a commit to annotated tag release-0.004
in repository libclass-tiny-perl.
commit 0b54c231597dd40b06ee243544b56fce696b8bcc
Author: David Golden <dagolden at cpan.org>
Date: Tue Aug 20 22:01:57 2013 -0400
validate args after BUILD; allow BUILD to hide args
---
README.pod | 26 ++++++++++++++++++++++++++
lib/Class/Tiny.pm | 47 ++++++++++++++++++++++++++++++++++++-----------
t/delta.t | 7 +++++++
t/lib/Delta.pm | 3 +++
4 files changed, 72 insertions(+), 11 deletions(-)
diff --git a/README.pod b/README.pod
index 95df30c..8047edb 100644
--- a/README.pod
+++ b/README.pod
@@ -181,6 +181,9 @@ If a reference is passed as a single argument, it must be able to be
dereferenced as a hash or an exception is thrown. A shallow copy is made of
the reference provided.
+Unknown arguments will result in a fatal exception, but see L</BUILD> for how
+to avoid this if desired.
+
=head2 BUILD
If your class or any superclass defines a C<BUILD> method, it will be called
@@ -196,6 +199,29 @@ is ignored. Use C<BUILD> for validation or setting default values.
croak "Foo must be non-negative" if $self->foo < 0;
}
+If you want to hide a non-attribute constructor argument from validation,
+delete it from the passed-in argument hash reference.
+
+ sub BUILD {
+ my ($self, $args) = @_;
+
+ if ( delete $args->{do_something_special} ) {
+ ...
+ }
+ }
+
+The argument reference is a copy, so deleting elements won't affect data in the
+object. You have to delete it from both if that's what you want.
+
+ sub BUILD {
+ my ($self, $args) = @_;
+
+ if ( delete $args->{do_something_special} ) {
+ delete $self->{do_something_special};
+ ...
+ }
+ }
+
=head2 DEMOLISH
Class::Tiny provides a C<DESTROY> method. If your class or any superclass
diff --git a/lib/Class/Tiny.pm b/lib/Class/Tiny.pm
index e59e578..4ddfb3b 100644
--- a/lib/Class/Tiny.pm
+++ b/lib/Class/Tiny.pm
@@ -67,9 +67,17 @@ sub new {
Carp::croak("$class->new() got an odd number of elements");
}
- # unknown attributes are fatal
- my @bad;
+ # create object and invoke BUILD
+ my $self = bless {%$args}, $class;
my @search = @{ mro::get_linear_isa($class) };
+ for my $s ( reverse @search ) {
+ no strict 'refs';
+ my $builder = *{ $s . "::BUILD" }{CODE};
+ $self->$builder($args) if defined $builder;
+ }
+
+ # unknown attributes still in $args are fatal
+ my @bad;
for my $k ( keys %$args ) {
push @bad, $k
unless grep { exists $CLASS_ATTRIBUTES{$_}{$k} } @search;
@@ -78,14 +86,6 @@ sub new {
Carp::croak("Invalid attributes for $class: @bad");
}
- # create object and invoke BUILD
- my $self = bless {%$args}, $class;
- for my $s ( reverse @search ) {
- no strict 'refs';
- my $builder = *{ $s . "::BUILD" }{CODE};
- $self->$builder($args) if defined $builder;
- }
-
return $self;
}
@@ -262,6 +262,9 @@ If a reference is passed as a single argument, it must be able to be
dereferenced as a hash or an exception is thrown. A shallow copy is made of
the reference provided.
+Unknown arguments will result in a fatal exception, but see L</BUILD> for how
+to avoid this if desired.
+
=head2 BUILD
If your class or any superclass defines a C<BUILD> method, it will be called
@@ -277,6 +280,29 @@ is ignored. Use C<BUILD> for validation or setting default values.
croak "Foo must be non-negative" if $self->foo < 0;
}
+If you want to hide a non-attribute constructor argument from validation,
+delete it from the passed-in argument hash reference.
+
+ sub BUILD {
+ my ($self, $args) = @_;
+
+ if ( delete $args->{do_something_special} ) {
+ ...
+ }
+ }
+
+The argument reference is a copy, so deleting elements won't affect data in the
+object. You have to delete it from both if that's what you want.
+
+ sub BUILD {
+ my ($self, $args) = @_;
+
+ if ( delete $args->{do_something_special} ) {
+ delete $self->{do_something_special};
+ ...
+ }
+ }
+
=head2 DEMOLISH
Class::Tiny provides a C<DESTROY> method. If your class or any superclass
@@ -301,5 +327,4 @@ method.
=cut
-
# vim: ts=4 sts=4 sw=4 et:
diff --git a/t/delta.t b/t/delta.t
index 4ec60c0..042f82b 100644
--- a/t/delta.t
+++ b/t/delta.t
@@ -14,6 +14,13 @@ subtest "attribute set as list" => sub {
is( $obj->bar, 23, "bar is set" );
};
+subtest "hiding constructor argument" => sub {
+ my $obj = new_ok( "Delta", [ foo => 42, bar => 23, hide_me => 1 ] );
+ is( $obj->foo, 42, "foo is set" );
+ is( $obj->bar, 23, "bar is set" );
+ is( $obj->{hide_me}, 1, "hidden constructor argument still in object" );
+};
+
subtest "destructor" => sub {
my @objs = map { new_ok( "Delta", [ foo => 42, bar => 23 ] ) } 1 .. 3;
is( $Delta::counter, 3, "BUILD incremented counter" );
diff --git a/t/lib/Delta.pm b/t/lib/Delta.pm
index bde1cd5..23e81aa 100644
--- a/t/lib/Delta.pm
+++ b/t/lib/Delta.pm
@@ -13,11 +13,14 @@ use Class::Tiny qw/foo bar/;
sub BUILD {
my $self = shift;
+ my $args = shift;
Carp::croak("foo must be positive")
unless defined $self->foo && $self->foo > 0;
$self->bar(42) unless defined $self->bar;
$counter++;
+
+ delete $args->{hide_me};
}
sub DEMOLISH {
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-perl/packages/libclass-tiny-perl.git
More information about the Pkg-perl-cvs-commits
mailing list