File Coverage

blib/lib/Object/Base.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Object::Base;
2             =head1 NAME
3              
4             Object::Base - Multi-threaded base class to establish a class deriving relationship with base classes at compile time
5              
6             =head1 VERSION
7              
8             version 1.00
9              
10             =head1 ABSTRACT
11              
12             Multi-threaded base class to establish a class deriving relationship with base classes at compile time
13              
14             package Foo;
15             use Object::Base;
16             attributes ':shared', 'attr1', 'attr2';
17            
18             package Bar;
19             use Object::Base 'Foo';
20             attributes 'attr3', ':shared' => undef, 'attr2' => undef;
21            
22             package main;
23             use threads;
24             use threads::shared;
25            
26             # object of Foo
27             my $foo = Foo->new();
28            
29             # usage of attribute
30             $foo->attr1(1);
31             print $foo->attr1, "\n"; # prints '1'
32            
33             # attributes are also lvaluable
34             $foo->attr1++;
35             print $foo->attr1, "\n"; # prints '2'
36            
37             # class attributes, eg: ':shared'
38             print "\$foo is ", is_shared($foo)? "shared": "not shared", "\n";
39            
40             # object of derived class Bar
41             my $bar = Bar->new();
42            
43             # attributes can be added derived classes
44             $bar->attr3(3);
45            
46             # attributes are inheritable
47             $bar->attr1(3);
48            
49             # attributes are overridable #1
50             eval { $bar->attr2 = 4 }; print $@; # prints error 'Attribute attr2 is not defined in Bar at ...'
51            
52             # attributes are overridable #2
53             print "\$bar is ", is_shared($bar)? "shared": "not shared", "\n"; # prints '$bar is not shared'
54            
55             # assigning ref values to shared class attributes
56             eval { $foo->attr2 = { key1 => 'val1' } }; print $@; # prints error 'Invalid value for shared scalar at ...'
57             $foo->attr2({ key2 => 'val2' }); # uses shared_clone assigning ref value
58              
59             =cut
60 1     1   13141 use strict;
  1         1  
  1         26  
61 1     1   3 no strict qw(refs);
  1         1  
  1         19  
62 1     1   3 use warnings;
  1         4  
  1         19  
63 1     1   551 use threads;
  0            
  0            
64             use threads::shared;
65              
66              
67             BEGIN
68             {
69             require 5.008;
70             $Object::Base::VERSION = '1.00';
71             $Object::Base::ISA = ();
72             }
73              
74              
75             my $package = __PACKAGE__;
76             my $context = $package;
77             $context =~ s/\Q::\E//g;
78              
79              
80             sub import
81             {
82             my $importer = shift;
83             my $caller = caller;
84             return unless $importer eq $package;
85             eval join "\n",
86             "package $caller;",
87             "use strict;",
88             "use warnings;",
89             "use threads;",
90             "use threads::shared;",
91             "\$${caller}::attributes = undef;",
92             "\*${caller}::attributes = \\\&${package}::attributes;",
93             "\%${caller}::${context} = () unless defined(\\\%${caller}::${context});",
94             (
95             map {
96             my $p = (defined and not ref)? $_: "";
97             $p and /^[^\W\d]\w*(\:\:[^\W\d]\w*)*\z/s or die "Invalid package name $p";
98             << "EOF";
99             eval { require $_ };
100             push \@${caller}::ISA, '$_';
101             if ($_->isa('$package'))
102             {
103             \$${caller}::${context}{\$_} = \$$_::${context}{\$_} for (keys \%$_::${context});
104             }
105             EOF
106             } @_
107             ),
108             "push \@${caller}::ISA, '$package' unless UNIVERSAL::isa('${caller}', '$package');";
109             die "Failed to import $package in $caller: $@" if $@;
110             return 1;
111             }
112              
113             sub attributes
114             {
115             my $caller = caller;
116             die "$caller is not $package class" unless UNIVERSAL::isa($caller, $package);
117             %{"${caller}::${context}"} = () unless defined(\%{"${caller}::${context}"});
118             my $l;
119             for (@_)
120             {
121             if (not defined($_) or ref($_))
122             {
123             next if not defined($l) or ref($l);
124             ${"${caller}::${context}"}{$l} = $_;
125             next;
126             }
127             ${"${caller}::${context}"}{$_} = {};
128             } continue
129             {
130             $l = $_;
131             }
132             eval join "\n",
133             "package $caller;",
134             map {
135             << "EOF";
136             sub $_(\$) :lvalue
137             {
138             my \$self = shift;
139             die 'Attribute $_ is not defined in $caller' if not defined(\$self) or
140             not UNIVERSAL::isa(ref(\$self), '$package') or
141             not \$${caller}::${context}{$_};
142             if (\@_ >= 1)
143             {
144             if (ref(\$_[0]))
145             {
146             \$self->{$_} = shared_clone(\$_[0]);
147             } else
148             {
149             \$self->{$_} = \$_[0];
150             }
151             }
152             return \$self->{$_};
153             }
154             EOF
155             } grep /^[^\W\d]\w*\z/s, keys %{"${caller}::${context}"};
156             die "Failed to generate attributes in $caller: $@" if $@;
157             return 1;
158             }
159              
160             sub new
161             {
162             my $class = shift;
163             my $self = {};
164             $self = &share($self) if ${"${class}::${context}"}{":shared"};
165             bless $self, $class;
166             return $self;
167             }
168              
169              
170             1;
171             __END__