File Coverage

blib/lib/Class/PObject.pm
Criterion Covered Total %
statement 67 77 87.0
branch 17 26 65.3
condition 6 10 60.0
subroutine 8 8 100.0
pod 0 1 0.0
total 98 122 80.3


line stmt bran cond sub pod time code
1             package Class::PObject;
2              
3             # $Id: PObject.pm,v 1.54.2.3 2004/05/20 06:59:14 sherzodr Exp $
4              
5 6     6   41 use strict;
  6         10  
  6         245  
6             #use diagnostics;
7 6     6   3219 use Log::Agent;
  6         52760  
  6         699  
8 6     6   63 use vars ('$VERSION', '$revision');
  6         10  
  6         801  
9              
10             $VERSION = '2.15_01';
11             $revision = '$Revision: 1.54.2.3 $';
12              
13             # configuring Log::Agent
14             logconfig(-level=>$ENV{POBJECT_DEBUG} || 0,
15             -prefix=>'***',
16             -caller => [-format => '%-30s->', -info => "sub"]);
17              
18             sub import {
19 16     16   30 my $class = shift;
20 16         82 my $caller_pkg = (caller)[0];
21              
22 16 50       65 unless ( @_ ) {
23 6     6   38 no strict 'refs';
  6         12  
  6         1286  
24 16         18 *{ "$caller_pkg\::pobject" } = \&{ "$class\::pobject" };
  16         104  
  16         59  
25 16         362 return 1
26             }
27 0         0 require Exporter;
28 0         0 return $class->Exporter::import( @_ )
29             }
30              
31             sub pobject {
32 8     8 0 15 my ($class, $props);
33              
34             # are we given explicit class name to be created in?
35 8 100 33     48 if ( @_ == 2 ) {
    50          
36 5         11 ($class, $props) = @_;
37 5         142 logtrc 1, "pobject %s => %s", $class, $props
38             }
39             # Is class name assumed to be the current caller's package?
40             elsif ( $_[0] && (ref($_[0]) eq 'HASH') ) {
41 3         5 $props = $_[0];
42 3         15 $class = (caller())[0];
43 3         125 logtrc 1, "pobject ('%s'), %s", $class, $props
44             }
45             # otherwise, we throw a usage exception:
46             else {
47 0         0 logcroak "Usage error"
48             }
49             # should we make sure that current package is not 'main'?
50 8 50       617 if ( $class eq 'main' ) {
51 0         0 logcroak "'main' cannot be the class name"
52             }
53              
54             # creating the class virtually. Note, that it is different
55             # then the way Class::Struct works. Class::Struct literally builds
56             # the class contents in a string, and then eval()s them.
57             # And we play with symtables. However, I'm not sure how secure this method is.
58              
59 6     6   31 no strict 'refs';
  6         12  
  6         3104  
60             # if the properties have already been created, it means the user
61             # is declaring the class with the same name twice. He should be shot!
62 8 50       14 if ( ${ "$class\::props" } ) {
  8         82  
63 0         0 logcroak "are you trying to create the same class two times?"
64             }
65              
66             # we should have some columns
67 8 50       12 unless ( @{$props->{columns}} ) {
  8         31  
68 0         0 logcroak "class '%s' should have columns!", $class
69             }
70              
71             # one of the columns should be 'id'. I believe this is a limitation,
72             # which should be eliminated in next release
73 8         15 my $has_id = 0;
74 8         12 for ( @{$props->{columns}} ) {
  8         25  
75 8 50       29 $has_id = ($_ eq 'id') and last
76             }
77 8 50       25 unless ( $has_id ) {
78 0         0 logcroak "one of the columns must be 'id'"
79             }
80              
81             # certain method names are reserved. Making sure they won't get overridden
82 8         60 my @reserved_methods = qw(
83             new load fetch save remove remove_all set get
84             pobject_init drop_datasource init_datasource DESTROY
85             );
86 8         18 for my $method ( @reserved_methods ) {
87 96         62 for my $column ( @{$props->{columns}} ) {
  96         94  
88 300 50       424 if ( $method eq $column ) {
89 0         0 logcroak "method '%s' is reserved", $method
90             }
91             }
92             }
93              
94 8         14 for my $colname ( @{$props->{columns}} ) {
  8         28  
95 25 100 66     97 unless ( defined($props->{tmap}) && $props->{tmap}->{$colname} ) {
96 18 100       34 if ( $colname eq 'id' ) {
97 7         36 $props->{tmap}->{$colname} = 'INTEGER', next
98             }
99 11         34 $props->{tmap}->{$colname} = 'VARCHAR(255)'
100             }
101             }
102              
103             # if no driver was specified, default driver to be used is 'file'
104 8   50     26 $props->{driver} ||= 'file';
105              
106             # if no serializer set defaulting to 'storable'
107 8   100     31 $props->{serializer} ||= 'storable';
108              
109             # it's important that we cache all the properties passed to the pobject()
110             # as a static data. This lets multiple instances of the pobject to access
111             # this data whenever needed
112 8         10 ${ "$class\::props" } = $props;
  8         27  
113              
114 8         3146 require Class::PObject::Template;
115             # To ensure operator overloading works properly on these
116             # objects, let's also set the caller's @ISA array:
117 8         18 push @{ "$class\::ISA" }, "Class::PObject::Template";
  8         95  
118              
119             # creating accessor methods
120 8         13 for my $colname ( @{ $props->{columns} } ) {
  8         25  
121 25 50       159 if ( $class->UNIVERSAL::can($colname) ) {
122 0         0 logcarp "method '%s' exists in the caller's package", $colname;
123             next
124 0         0 }
125 25         106 *{ "$class\::$colname" } = sub {
126 210 100   210   500 if ( @_ == 2 ) {
127 41         69 my $set = \&Class::PObject::Template::set;
128 41         151 return $set->( $_[0], $colname, $_[1] )
129             }
130 169         239 my $get = \&Class::PObject::Template::get;
131 169         420 return $get->( $_[0], $colname )
132             }
133 25         79 }
134             }
135              
136             logtrc 1, "%s loaded successfully", __PACKAGE__;
137              
138             1;
139             __END__