File Coverage

blib/lib/Util/DataThing.pm
Criterion Covered Total %
statement 47 47 100.0
branch 12 14 85.7
condition n/a
subroutine 15 15 100.0
pod 0 3 0.0
total 74 79 93.6


line stmt bran cond sub pod time code
1              
2             =head1 NAME
3              
4             Util::DataThing - A simple framework for creating introspectable business objects
5              
6             =head1 SYNOPSIS
7              
8             package ExampleApp::Person;
9             use base qw(Util::DataThing);
10            
11             __PACKAGE__->declare_property('name', STRING);
12              
13             =head1 DESCRIPTION
14              
15             This class provides a framework for providing business objects
16             within an application.
17              
18             Subclasses of this class support introspection via the
19             C method, which returns a L object
20             describing the class.
21              
22             The internal structure of the objects is opaque to subclasses
23             and should not be relied upon. Subclasses may define new methods
24             in addition to those created with this class's C
25             methods, but they should be implemented in terms of the
26             property accessors created by this class, not direct access
27             to the object internals.
28              
29             This is not an ORM or other mechanism for abstracting away
30             your data access layer, but if you want to use an ORM then
31             objects created with this class may be a good thing for your
32             ORM to return.
33              
34             TODO: Write more docs
35              
36             =cut
37              
38             package Util::DataThing;
39              
40 4     4   48394 use strict;
  4         9  
  4         162  
41 4     4   24 use warnings;
  4         10  
  4         118  
42 4     4   1223 use Util::DataThing::Type;
  4         10  
  4         114  
43 4     4   23 use Carp qw(croak);
  4         8  
  4         233  
44 4     4   21 use Sub::Name;
  4         7  
  4         964  
45              
46             our $VERSION = "0.01_01";
47              
48             sub new {
49 4     4 0 71 my $class = shift;
50              
51 4 50       27 my $args = (scalar(@_) == 1 ? $_[0] : {@_});
52              
53 4         13 my $self = bless {}, $class;
54 4         31 $self->{data} = {};
55              
56 4         13 foreach my $property (keys %$args) {
57 4         25 $self->$property($args->{$property});
58             }
59              
60 4         17 return $self;
61             }
62              
63             sub register_property {
64 11     11 0 20 my ($class, $name, $type) = @_;
65              
66 11         38 my ($existing_type, $existing_class) = $class->type->property_type($name);
67 11 100       32 croak("$class tried to override property ${existing_class}->$name") if $existing_type;
68              
69             # Create an accessor for this field
70             {
71 4     4   22 no strict 'refs';
  4         8  
  4         1623  
  10         13  
72 10         17 my $full_name = "${class}::${name}";
73              
74 10         32 my $coerce_in = $type->coerce_in;
75 10         28 my $coerce_out = $type->coerce_out;
76              
77             my $method = sub {
78 42     42   1306 my $self = shift;
        42      
        40      
        19      
        42      
        21      
79              
80 42 100       91 if (@_) {
81 15         20 my $value = shift;
82 15 50       34 croak("Unexpected extra arguments to ${class}->${name}") if @_;
83 15 100       65 return $self->{data}{$name} = defined($value) ? $coerce_in->($value, $type) : undef;
84             }
85             else {
86 27         50 my $value = $self->{data}{$name};
87 27 100       101 return defined($value) ? $coerce_out->($value, $type) : undef;
88             }
89 10         48 };
90              
91 10         72 Sub::Name::subname($full_name, $method);
92 10         9 *{$full_name} = $method;
  10         53  
93             }
94              
95             # Tell Util::DataThing::Type about this field using
96             # our super-secret backdoor!
97 10         42 Util::DataThing::Type->_register_object_property($class, $name, $type);
98             }
99              
100             sub type {
101 13     13 0 21 my ($thing) = @_;
102              
103 13 100       35 my $class = ref($thing) ? ref($thing) : $thing;
104 13         47 return Util::DataThing::Type->object($class);
105             }
106              
107             1;
108              
109             =head1 AUTHOR AND COPYRIGHT
110              
111             Written and maintained by Martin Atkins .
112              
113             Copyright 2009 Six Apart Ltd. All Rights Reserved.
114              
115             The items in this distribution may be distributed under the same
116             terms as Perl itself.
117              
118