comparison Lib/IMPL/Class/Property/Direct.pm @ 59:0f3e369553bd

Rewritten property implementation (probably become slower but more flexible) Configuration infrastructure in progress (in the aspect of the lazy activation) Initial concept for the code generator
author wizard
date Tue, 09 Mar 2010 02:50:45 +0300
parents 609b59c9f03c
children b0c068da93ac
comparison
equal deleted inserted replaced
58:a35b60b16a99 59:0f3e369553bd
1 package IMPL::Class::Property::Direct; 1 package IMPL::Class::Property::Direct;
2 use strict; 2 use strict;
3 3
4 use base qw(IMPL::Object::Accessor Exporter); 4 use base qw(IMPL::Object::Accessor IMPL::Class::Property::Base Exporter);
5 our @EXPORT = qw(_direct); 5 our @EXPORT = qw(_direct);
6 6
7 require IMPL::Object::List; 7 require IMPL::Object::List;
8 use IMPL::Class::Property; 8 use IMPL::Class::Property;
9 require IMPL::Exception; 9 require IMPL::Exception;
10 10
11 __PACKAGE__->mk_accessors qw(ExportField); 11 __PACKAGE__->mk_accessors qw(ExportField);
12 12
13 push @IMPL::Class::Property::Base::factoryParams, qw($field);
14
13 sub _direct($) { 15 sub _direct($) {
14 my ($prop_info) = @_; 16 my ($prop_info) = @_;
15 $prop_info->Implementor( IMPL::Class::Property::Direct->new({ExportField => 1}) ); 17 $prop_info->Implementor( IMPL::Class::Property::Direct->new({ExportField => 1}) );
16 return $prop_info; 18 return $prop_info;
17 } 19 }
18 20
19 my $access_private = "die new IMPL::Exception('Can\\'t access the private member',\$name,\$class,scalar caller) unless caller eq \$class;";
20 my $access_protected = "die new IMPL::Exception('Can\\'t access the protected member',\$name,\$class,scalar caller) unless caller eq \$class;";
21 21
22 my $accessor_get_no = 'die new IMPL::Exception(\'The property is write only\',$name,$class) unless $get;'; 22 sub GenerateGet {
23 my $accessor_set_no = 'die new IMPL::Exception(\'The property is read only\',$name,$class) unless $set;'; 23 'return ($this->{$field});';
24 my $accessor_set = 'return( $this->{$field} = @_ == 1 ? $_[0] : [@_] );'; 24 }
25 my $accessor_get = 'return( $this->{$field} );';
26 my $list_accessor_set = 'return(
27 wantarray ?
28 @{ $this->{$field} = IMPL::Object::List->new(
29 (@_ == 1 and UNIVERSAL::isa($_[0], \'ARRAY\') ) ? $_[0] : [@_]
30 )} :
31 ($this->{$field} = IMPL::Object::List->new(
32 (@_ == 1 and UNIVERSAL::isa($_[0], \'ARRAY\') ) ? $_[0] : [@_]
33 ))
34 );';
35 my $list_accessor_get = 'return(
36 wantarray ?
37 @{ $this->{$field} ?
38 $this->{$field} :
39 ( $this->{$field} = IMPL::Object::List->new() )
40 } :
41 ( $this->{$field} ?
42 $this->{$field} :
43 ( $this->{$field} = IMPL::Object::List->new() )
44 )
45 );';
46 my $custom_accessor_get = 'unshift @_, $this and goto &$get;';
47 my $custom_accessor_set = 'unshift @_, $this and goto &$set;';
48 25
49 my %accessor_cache; 26 sub GenerateSet {
50 sub mk_acessor { 27 'return ($this->{$field} = $_[0])';
51 my ($virtual,$access,$class,$name,$mutators,$field,$validator) = @_;
52
53 my ($get,$set) = ref $mutators ? ( $mutators->{get}, $mutators->{set}) : ($mutators & prop_get, $mutators & prop_set);
54 my $key = join '',$virtual,$access,$get ? 1 : 0,$set ? 1 : 0, (ref $mutators ? 'c' : ($mutators & prop_list() ? 'l' : 's')), $validator ? 1 : 0 ;
55 my $factory = $accessor_cache{$key};
56 if (not $factory) {
57 my $code =
58 <<BEGIN;
59 sub {
60 my (\$class,\$name,\$set,\$get,\$field) = \@_;
61 my \$accessor;
62 \$accessor = sub {
63 my \$this = shift;
64 BEGIN
65 $code .= <<VCALL if $virtual;
66 my \$method = \$this->can(\$name);
67 return \$this->\$method(\@_) unless \$method == \$accessor or caller->isa(\$class);
68 VCALL
69 $code .= ' 'x8 . "$access_private\n" if $access == IMPL::Class::Member::MOD_PRIVATE;
70 $code .= ' 'x8 . "$access_protected\n" if $access == IMPL::Class::Member::MOD_PROTECTED;
71 $code .= ' 'x8 . '$this->$validator(@_);'."\n" if $validator;
72
73 my ($codeGet,$codeSet);
74 if (ref $mutators) {
75 $codeGet = $get ? $custom_accessor_get : $accessor_get_no;
76 $codeSet = $set ? $custom_accessor_set : $accessor_set_no;
77 } else {
78 if ($mutators & prop_list) {
79 $codeGet = $get ? $list_accessor_get : $accessor_get_no;
80 $codeSet = $set ? $list_accessor_set : $accessor_set_no;
81 } else {
82 $codeGet = $get ? $accessor_get : $accessor_get_no;
83 $codeSet = $set ? $accessor_set : $accessor_set_no;
84 }
85 }
86 $code .=
87 <<END;
88 if (\@_) {
89 $codeSet
90 } else {
91 $codeGet
92 }
93 }
94 } 28 }
95 END 29
96 warn $code; 30 sub GenerateSetList {
97 $factory = eval $code; 31 'return(
98 if (not $factory) { 32 wantarray ?
99 my $err = $@; 33 @{ $this->{$field} = IMPL::Object::List->new(
100 die new IMPL::Exception('Failed to generate the accessor factory',$err); 34 (@_ == 1 and UNIVERSAL::isa($_[0], \'ARRAY\') ) ? $_[0] : [@_]
101 } 35 )} :
102 $accessor_cache{$key} = $factory; 36 ($this->{$field} = IMPL::Object::List->new(
103 } 37 (@_ == 1 and UNIVERSAL::isa($_[0], \'ARRAY\') ) ? $_[0] : [@_]
104 38 ))
105 die new IMPL::Exception('Can\'t find the specified validator',$class,$validator) if $validator and ref $validator ne 'CODE' and not $class->can($validator); 39 );';
106 40 }
107 return $factory->($class,$name,$set,$get, $field, $validator); 41
42 sub GenerateGetList {
43 'return(
44 wantarray ?
45 @{ $this->{$field} ?
46 $this->{$field} :
47 ( $this->{$field} = IMPL::Object::List->new() )
48 } :
49 ( $this->{$field} ?
50 $this->{$field} :
51 ( $this->{$field} = IMPL::Object::List->new() )
52 )
53 );';
54 }
55
56 sub RemapFactoryParams {
57 my ($self,$propInfo) = @_;
58
59 return $self->SUPER::RemapFactoryParams($propInfo),$self->FieldName($propInfo);
108 } 60 }
109 61
110 sub Make { 62 sub Make {
111 my ($self,$propInfo) = @_; 63 my ($self,$propInfo) = @_;
112 64
113 my $isExportField = ref $self ? ($self->ExportField || 0) : 0; 65 $self->SUPER::Make($propInfo);
114 my ($class,$name,$virt,$access,$mutators,$attr) = $propInfo->get qw(Class Name Virtual Access Mutators Attributes); 66
115 (my $field = "${class}_$name") =~ s/::/_/g; 67 {
116 68 no strict 'refs';
117 my $propGlob = $class.'::'.$name; 69 if (ref $self and $self->ExportField) {
118 70 my $field = $self->FieldName($propInfo);
119 no strict 'refs'; 71 *{$propInfo->Class.'::'.$propInfo->Name} = \$field;
120 *$propGlob = mk_acessor($virt,$access,$class,$name,$mutators,$field,$attr->{validator}); 72 }
121 *$propGlob = \$field if $isExportField; 73 }
122
123 if (ref $mutators) {
124 $propInfo->canGet( $mutators->{get} ? 1 : 0);
125 $propInfo->canSet( $mutators->{set} ? 1 : 0);
126 } else {
127 $propInfo->canGet( ($mutators & prop_get) ? 1 : 0);
128 $propInfo->canSet( ($mutators & prop_set) ? 1 : 0);
129 }
130 } 74 }
131 75
132 sub FieldName { 76 sub FieldName {
133 my ($self,$propInfo) = @_; 77 my ($self,$propInfo) = @_;
134 78