[libclass-tiny-perl] 02/05: implement lazy defaults
gregor herrmann
gregoa at debian.org
Sun May 31 14:03:15 UTC 2015
This is an automated email from the git hooks/post-receive script.
gregoa pushed a commit to annotated tag release-0.005
in repository libclass-tiny-perl.
commit afc5430725bf18d8c6d4694ec1258a30b97da7c7
Author: David Golden <dagolden at cpan.org>
Date: Wed Aug 21 17:36:01 2013 -0400
implement lazy defaults
---
lib/Class/Tiny.pm | 50 ++++++++++++++++++++++++++++++++++++++++----------
t/golf.t | 35 +++++++++++++++++++++++++++++++++++
t/lib/Golf.pm | 12 ++++++++++++
3 files changed, 87 insertions(+), 10 deletions(-)
diff --git a/lib/Class/Tiny.pm b/lib/Class/Tiny.pm
index 211c9ee..76ec15a 100644
--- a/lib/Class/Tiny.pm
+++ b/lib/Class/Tiny.pm
@@ -35,20 +35,35 @@ sub prepare_class {
# adapted from Object::Tiny and Object::Tiny::RW
sub create_attributes {
no strict 'refs';
- my ( $class, $pkg, @attr ) = @_;
- @attr = grep {
+ my ( $class, $pkg, @spec ) = @_;
+ my %defaults = map { ref $_ eq 'HASH' ? %$_ : ( $_ => undef ) } @spec;
+ my @attr = grep {
defined and !ref and /^[^\W\d]\w*$/s
or Carp::croak "Invalid accessor name '$_'"
- } @attr;
- $CLASS_ATTRIBUTES{$pkg}{$_} = undef for @attr;
+ } keys %defaults;
+ $CLASS_ATTRIBUTES{$pkg}{$_} = $defaults{$_} for @attr;
#<<< No perltidy
eval join "\n", ## no critic: intentionally eval'ing subs here
- "package $pkg;",
+ "package $pkg;\n",
map {
- "sub $_ { return \@_ == 1 ? \$_[0]->{$_} : (\$_[0]->{$_} = \$_[1]) }\n"
+ <<CODE
+ sub $_ {
+ if ( \@_ == 1 ) {
+ if ( !exists \$_[0]{$_} && defined \$CLASS_ATTRIBUTES{'$pkg'}{$_} ) {
+ \$_[0]{$_} = ref \$CLASS_ATTRIBUTES{'$pkg'}{$_} eq 'CODE'
+ ? \$CLASS_ATTRIBUTES{'$pkg'}{$_}->(\$_[0])
+ : \$CLASS_ATTRIBUTES{'$pkg'}{$_};
+ }
+ return \$_[0]{$_};
+ }
+ else {
+ return \$_[0]{$_} = \$_[1];
+ }
+ }
+CODE
} grep { ! *{"$pkg\::$_"}{CODE} } @attr;
#>>>
- Carp::croak("Failed to generate attributes for $pkg: @attr") if $@;
+ Carp::croak("Failed to generate attributes for $pkg: $@\n") if $@;
return;
}
@@ -166,6 +181,7 @@ code. Here is a list of features:
=for :list
* defines attributes via import arguments
* generates read-write accessors
+* supports lazy attribute defaults
* supports custom accessors
* superclass provides a standard C<new> constructor
* C<new> takes a hash reference or list of key/value pairs
@@ -210,7 +226,7 @@ Define attributes as a list of import arguments:
weight
);
-For each item, a read-write accessor is created unless a subroutine of that
+For each attribute, a read-write accessor is created unless a subroutine of that
name already exists:
$obj->name; # getter
@@ -219,6 +235,19 @@ name already exists:
Attribute names must be valid subroutine identifiers or an exception will
be thrown.
+You can specify lazy defaults by defining attributes with a hash reference.
+Keys define attribute names and values are constants or code references that
+will be evaluated when the attribute is first accessed if no value has been
+set. The object is passed as an argument to a code reference.
+
+ package Foo::WithDefaults;
+
+ use Class::Tiny qw/name id/, {
+ title => 'Peon',
+ skills => sub { [] },
+ hire_date => sub { $_[0]->_build_hire_date },
+ };
+
To make your own custom accessors, just pre-declare the method name before
loading Class::Tiny:
@@ -230,8 +259,9 @@ loading Class::Tiny:
sub id { ... }
-By declaring C<id> also with Class::Tiny, you include it in the list
-of allowed constructor parameters.
+By declaring C<id> also with Class::Tiny, you include it in the list of known
+attributes for introspection. Default values will not be set for custom
+accessors unless you handle that yourself.
=head2 Class::Tiny::Object is your base class
diff --git a/t/golf.t b/t/golf.t
new file mode 100644
index 0000000..8d0395e
--- /dev/null
+++ b/t/golf.t
@@ -0,0 +1,35 @@
+use 5.008001;
+use strict;
+use warnings;
+use lib 't/lib';
+
+use Test::More 0.96;
+use TestUtils;
+
+require_ok("Golf");
+
+subtest "lazy defaults" => sub {
+ my $obj = new_ok("Golf");
+ is( $obj->foo, undef, "foo is undef" );
+ is( $obj->bar, undef, "bar is undef" );
+ ok( !exists( $obj->{wibble} ), "lazy wibble doesn't exist" );
+ ok( !exists( $obj->{wobble} ), "lazy wobble doesn't exist" );
+ is( $obj->wibble, 42, "wibble access gives default" );
+ is( ref $obj->wobble, 'ARRAY', "wobble access gives default" );
+ ok( exists( $obj->{wibble} ), "lazy wibble does exist" );
+ ok( exists( $obj->{wobble} ), "lazy wobble does exist" );
+ my $obj2 = new_ok("Golf");
+ isnt( $obj->wobble, $obj2->wobble, "coderefs run for each object" );
+};
+
+subtest "exceptions" => sub {
+ like(
+ exception { Golf->new( foo => 23, bar => 42, zoom => 13 ) },
+ qr/Invalid attributes for Golf: zoom/,
+ "creating object with 'baz' dies",
+ );
+};
+
+done_testing;
+# COPYRIGHT
+# vim: ts=4 sts=4 sw=4 et:
diff --git a/t/lib/Golf.pm b/t/lib/Golf.pm
new file mode 100644
index 0000000..315e58b
--- /dev/null
+++ b/t/lib/Golf.pm
@@ -0,0 +1,12 @@
+use 5.008001;
+use strict;
+use warnings;
+
+package Golf;
+
+use Class::Tiny qw/foo bar/, {
+ wibble => 42,
+ wobble => sub { [] },
+}, qw/zig zag/;
+
+1;
--
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