annotate lib/IMPL/Config/Bag.pm @ 419:bbc4739c4d48 ref20150831

working on IMPL::Config::Container
author cin
date Sun, 29 Jan 2017 10:30:20 +0300
parents 3ed0c58e9da3
children b0481c071bea
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
412
30e8c6a74937 working on di container (role based registrations)
cin
parents:
diff changeset
1 package IMPL::Config::Bag;
30e8c6a74937 working on di container (role based registrations)
cin
parents:
diff changeset
2 use strict;
30e8c6a74937 working on di container (role based registrations)
cin
parents:
diff changeset
3
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
4 use IMPL::lang qw(:base);
412
30e8c6a74937 working on di container (role based registrations)
cin
parents:
diff changeset
5 use IMPL::declare {
413
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
6 base => [
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
7 'IMPL::Object' => undef
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
8 ],
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
9 props => [
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
10 _parents => '*rw', # array of parent bags
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
11 _parentRev => '*rw', # the timestamp of the parent
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
12 _sealed => '*rw', # the bag has descendants
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
13 _cache => '*rw', # own or cached entries
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
14 _timestamp => '*rw',
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
15 _entries => '*rw', # each entry is represented by hash
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
16 # { isa => linear_isa_hash, owner => owner_of_the_entry, value => value }
413
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
17 ]
412
30e8c6a74937 working on di container (role based registrations)
cin
parents:
diff changeset
18 };
30e8c6a74937 working on di container (role based registrations)
cin
parents:
diff changeset
19
413
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
20 sub CTOR {
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
21 my ( $this, $p ) = @_;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
22
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
23 if ($p) {
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
24 $p->_Seal();
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
25 my @parents;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
26 push @parents, @{ $p->{$_parents} } if $p->{$_parents};
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
27 push @parents, $p;
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
28 $this->{$_parents} = \@parents;
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
29 $this->{$_parentRev} = $p->{$_timestamp};
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
30 }
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
31
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
32 $this->{$_timestamp} = 0;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
33 $this->{$_cache} = {};
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
34 $this->{$_entries} = [];
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
35 }
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
36
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
37 sub GetParent {
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
38 my ($this) = @_;
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
39
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
40 $this->{$_parents} && $this->{$_parents}[ @{ $this->{$_parents} } - 1 ];
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
41 }
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
42
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
43 sub _Seal {
417
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
44 unless ( $_[0]->{$_sealed} ) {
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
45 $_[0]->{$_sealed} = 1;
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
46 $_[0]->{$_timestamp} = 0; # from now the timestamp is important
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
47 }
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
48 }
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
49
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
50 sub _Validate {
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
51 my ($this) = @_;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
52
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
53 my $chain = $this->{$_parents}
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
54 or return 1;
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
55
417
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
56 my $rev = 0; # rev 0 means that parent was never modified
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
57 # this allows to made more efficient checks
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
58 my $flush;
417
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
59
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
60 foreach my $bag ( @$chain, $this ) {
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
61
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
62 # we need to updated all bags after the first change was detected;
417
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
63 if ( $flush ||= $rev and $bag->{$_parentRev} != $rev ) {
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
64 $bag->{$_cache} = {};
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
65 $bag->{$_parentRev} = $rev;
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
66 }
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
67 $rev = $bag->{$_timestamp};
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
68 }
417
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
69
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
70 return $flush ? 0 : 1;
413
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
71 }
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
72
412
30e8c6a74937 working on di container (role based registrations)
cin
parents:
diff changeset
73 sub Resolve {
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
74 my ( $this, $role ) = @_;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
75
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
76 die IMPL::InvalidArgumentException->new('role')
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
77 unless defined $role;
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
78
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
79 if ( my $d = $this->_GetDescriptor($role) ) {
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
80 return $d->{value};
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
81 }
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
82 else {
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
83 return;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
84 }
413
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
85 }
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
86
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
87 sub _GetDescriptor {
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
88 my ( $this, $role ) = @_;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
89
413
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
90 my $d = $this->{$_cache}{$role};
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
91
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
92 # return descriptor if this is own descriptor and its level is 1 (i.e. it can't be overriden by the parent cache)
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
93 # otherwise the cache must be validated
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
94 return $d
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
95 if $d
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
96 and ( ( $d->{owner} == $this and $d->{isa}{$role} == 1 )
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
97 or $this->_Validate() );
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
98
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
99 # if there were no descriptor in cache we need to ensure that the cache
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
100 # chain is valid before reolving starts
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
101 $this->_Validate() unless $d;
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
102
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
103 # the cache chain is valid
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
104 # $d is not a valid descriptor
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
105
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
106 $d = undef;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
107 my $prev;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
108
417
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
109 my $parents = $this->{$_parents};
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
110 my @bags = $parents ? ( @$parents, $this ) : ($this);
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
111
417
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
112 foreach my $bag (@bags) {
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
113
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
114 # check the cache;
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
115 unless ( my $t = $bag->{$_cache}{$role} ) {
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
116
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
117 # no cached entry this may be due cache flush
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
118 # go through own entries and find better entry than inherited from parents
417
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
119 foreach my $entry ( @{ $bag->{$_entries} } ) {
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
120 my $level = $entry->{isa}{$role};
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
121 if ( $level and ( not($prev) or $level <= $prev ) ) {
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
122 $d = $entry;
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
123 $prev = $level;
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
124 }
417
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
125 }
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
126
417
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
127 #cache it
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
128 $bag->{$_cache}{$role} = $d if $d;
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
129 }
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
130 else {
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
131 $d = $t;
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
132 $prev = $d->{isa}{$role};
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
133 }
413
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
134 }
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
135
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
136 return $d;
413
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
137 }
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
138
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
139 sub ResolveAll {
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
140 my ( $this, $role ) = @_;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
141
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
142 return [
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
143 map $_->{value},
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
144 grep $_->{isa}{$role},
417
3ed0c58e9da3 working on di container, tests
cin
parents: 415
diff changeset
145 map @{ $_->{$_entries} },
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
146 @{ $this->{$_parents} || [] },
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
147 $this
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
148 ];
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
149
413
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
150 }
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
151
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
152 sub Register {
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
153 my ( $this, $isa, $value ) = @_;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
154
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
155 $isa = { $isa, 1 } unless ishash($isa);
413
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
156
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
157 push @{ $this->{$_entries} },
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
158 { owner => $this, isa => $isa, value => $value };
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
159 $this->{$_timestamp}++;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
160
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
161 delete $this->{$_cache}{$_} foreach keys %$isa;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
162
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
163 return $this;
412
30e8c6a74937 working on di container (role based registrations)
cin
parents:
diff changeset
164 }
30e8c6a74937 working on di container (role based registrations)
cin
parents:
diff changeset
165
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
166 1;