/[cvs]/nfo/perl/libs/Data/Mungle/Transform/Deep.pm
ViewVC logotype

Contents of /nfo/perl/libs/Data/Mungle/Transform/Deep.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.2 - (show annotations)
Sun Dec 1 04:44:07 2002 UTC (21 years, 7 months ago) by joko
Branch: MAIN
Changes since 1.1: +208 -7 lines
+ code from Data::Transform::OO

1 ##############################################
2 #
3 # $Id: Deep.pm,v 1.1 2002/11/29 04:49:20 joko Exp $
4 #
5 # $Log: Deep.pm,v $
6 # Revision 1.1 2002/11/29 04:49:20 joko
7 # + initial check-in
8 #
9 # Revision 1.1 2002/10/10 03:26:00 cvsjoko
10 # + new
11 #
12 ##############################################
13
14
15 package Data::Transform::Deep;
16
17 use strict;
18 use warnings;
19
20 require Exporter;
21 our @ISA = qw( Exporter );
22 our @EXPORT_OK = qw(
23 &var_NumericalHashToArray
24 &var_deref
25 &var_mixin
26 &object2hash
27 &hash2object
28 &refexpr2perlref
29 );
30 # &getStructSlotByStringyAddress
31
32 use attributes;
33 use Data::Dumper;
34
35
36 sub var_NumericalHashToArray {
37 my $vref = shift;
38 #my $context = shift;
39 if (ref $vref eq 'HASH') {
40 foreach (keys %{$vref}) {
41 # if ((ref $vref->{$_}) =~ m/HASH/) {
42 if ((ref $vref->{$_}) =~ m/HASH/) {
43 if ($vref->{$_}{0}) { # might be a numerical-indexed array
44 #print "000\n";
45 #print "context: $context\n";
46 my @arr;
47 foreach my $key_numeric (sort keys %{$vref->{$_}}) {
48 push @arr, $vref->{$_}{$key_numeric};
49 }
50 $vref->{$_} = \@arr;
51 }
52 var_NumericalHashToArray($vref->{$_});
53 }
54 # } else {
55 # #$vref->{$_} = scalar2iso($vref->{$_});
56 # }
57 }
58 }
59 }
60
61
62 sub var_deref {
63 my $obj = shift;
64 my $result;
65 if ((ref $obj) eq 'ARRAY') {
66 foreach (@{$obj}) {
67 my $ref = ref $_;
68 if ($ref) {
69 push(@{$result}, var_deref($_));
70 } else {
71 push(@{$result}, $_);
72 }
73 }
74 # TODO: "} elsif (ref $obj eq 'HASH') { [...] } else { croak 'could not deref blah'; }" ???
75 } else {
76 foreach (keys %{$obj}) {
77 my $key = $_;
78 my $ref = ref $obj->{$_};
79 if ($ref) {
80 $result->{$_} = var_deref($obj->{$_});
81 } else {
82 $result->{$_} = $obj->{$_};
83 }
84 }
85 }
86 return $result;
87 }
88
89
90
91
92 my @indexstack;
93 sub var_traverse_mixin_update {
94 my $obj = shift;
95 my $data = shift;
96 my $bool_recursion = shift;
97 if (!$bool_recursion) {
98 @indexstack = ();
99 }
100 my $result;
101
102 # 'ARRAY' does not work!
103 if ((ref $obj) eq 'ARRAY') {
104 #print "ARRAY\n";
105 my $i = 0;
106 foreach (@{$obj}) {
107 push @indexstack, $i;
108 my $ref = ref $_;
109 if ($ref) {
110 #$obj->[$i] = var_mixin($_, $data, 1);
111 var_traverse_mixin_update($_, $data, 1);
112 } else {
113 $obj->[$i] = $_;
114 }
115 pop @indexstack;
116 $i++;
117 }
118 } else {
119 foreach (keys %{$obj}) {
120 push @indexstack, $_;
121 my $ref = ref $obj->{$_};
122 if ($ref) {
123 #$obj->{$_} = var_mixin($obj->{$_}, $data, 1);
124 var_traverse_mixin_update($obj->{$_}, $data, 1);
125 } else {
126 #$obj->{$_} = $obj->{$_};
127 my $evstring = getSlot($data);
128 $obj->{$_} = $evstring;
129
130 }
131 pop @indexstack;
132 }
133 }
134 #return $result;
135 }
136
137 sub object2hash {
138 my $object = shift;
139 my $options = shift;
140 my $deref = var_deref($object);
141 var2utf8($deref) if ($options->{utf8});
142 return $deref;
143 }
144
145 # todo: maybe do diff(s) here sometimes!?
146 sub hash2object {
147 my $object = shift;
148 my $data = shift;
149 my $options = shift;
150
151 # "patch" needed 'cause php passes numerical-indexed-arrays as hash-tables,
152 # this method corrects this
153 var_NumericalHashToArray($data) if ($options->{php});
154
155 # utf8-conversion/-encoding (essential for I18N)
156 var_utf2iso($data) if ($options->{utf8});
157
158 # get fresh object from database
159 # todo:
160 # - handle "locked" objects !!!
161 # - check if already another update occoured (object-revisioning needed!)
162 #my $obj = $self->getObject($oid);
163
164 # mix changes into fresh object and save it back
165 hash2object_traverse_mixin($object, $data);
166
167 # done in core mixin function?
168 #$self->{storage}->update($obj);
169
170 # we should "undef" some objects here to destroy them in memory and enforce reloading when used next time
171 # simulate:
172 #$self->{storage}->disconnect();
173
174 }
175
176 # ------------------------------------
177 # core mixin function
178 # TODO-FEATURE: make this possible in a reverse way: object is empty (no fields) and gets filled up by mixin-data
179
180 # remember keys of structures we are traversing
181 # this is a HACK:
182 # - don't (!!!) "packageglobal" @indexstack
183 # - it will lead to problems with parallelism!
184
185 #my @indexstack;
186
187 # traverse a deeply nested structure, mix in values from given hash, update underlying tangram-object
188 sub hash2object_traverse_mixin {
189 my $object = shift;
190 my $data = shift;
191 my $bool_recursion = shift;
192
193 # clear our key - stack if we are called from user-code (non-recursively)
194 @indexstack = () if (!$bool_recursion);
195
196 my $classname = ref $object;
197 # if ($classname) {
198 # print STDERR "*****************", Dumper(Class::Tangram::attribute_types($classname)), "\n";
199 # }
200
201 # parser: detected OBJECT (a Tangram one?) (reftype == HASH) (assume)
202 # what's exactly done here? hmmm.... it works ;)
203 # maybe a HACK: please try not to use "IntrHash"es, maybe this cannot handle them!!!
204 # extend! check!
205 if ((attributes::reftype($object) eq 'HASH') && (ref($object) ne 'HASH') && (ref($object) ne 'ARRAY')) {
206
207 # print STDERR "===", "reftype: ", attributes::reftype($obj), "\n";
208
209 # loop through fields of object (Tangram-object)
210 foreach (keys %{$object}) {
211 push @indexstack, $_;
212
213 # determine type of object
214 my $ref = ref $object->{$_};
215 # print STDERR "attrname: $_ ATTRref: $ref", "\n";
216 if ($ref) {
217 hash2object_traverse_mixin($object->{$_}, $data, 1);
218 } else {
219 my $val = getStructSlotByStringyAddress($data, \@indexstack);
220 $object->{$_} = $val;
221 }
222 pop @indexstack;
223 }
224
225 # save object to database ...
226 # ... do an update if it already exists, do an insert if it doesn't
227 # my $objectId = $self->{storage}->id($obj);
228 # $logger->debug( __PACKAGE__ . "->saveObjectFromHash_traverse_mixin_update( object $obj objectId $objectId )" );
229 # if ($objectId) {
230 # $self->{storage}->update($obj);
231
232 #print __PACKAGE__ . ":", "\n";
233 #print Dumper($object);
234
235 # } else {
236 # $self->{storage}->insert($obj);
237 # }
238
239 }
240
241 #&& ( ref($obj) ne 'HASH' )
242
243 # loop through entries of array (IntrArray, isn't it?)
244 if ((ref $object) eq 'ARRAY') {
245 # print STDERR "===", "refttype ", attributes::reftype($obj), "\n";
246 my $i = 0;
247 foreach (@{$object}) {
248 push @indexstack, $i;
249 my $ref = ref $_;
250 # print STDERR "attrname: $_ ATTRref: $ref", "\n";
251 if ($ref && $_) {
252 hash2object_traverse_mixin($_, $data, 1);
253 } else {
254 $object->[$i] = $_;
255 }
256 pop @indexstack;
257 $i++;
258 }
259 }
260
261 }
262
263
264 # this function seems to do similar stuff like these below (refexpr2perlref & co.)
265 sub getStructSlotByStringyAddress {
266 my $var = shift;
267 my $indexstack_ref = shift;
268 my @indexstack = @{$indexstack_ref};
269 my $joiner = '->';
270 my @evlist;
271 foreach (@indexstack) {
272 my $elem;
273 if ($_ =~ m/\d+/) { $elem = "[$_]"; }
274 if ($_ =~ m/\D+/) { $elem = "{$_}"; }
275 push @evlist, $elem;
276 }
277 my $evstring = join($joiner, @evlist);
278 $evstring = 'return $var->' . $evstring . ';';
279 #print "ev: $evstring\n";
280 return eval($evstring);
281 }
282
283
284 sub refexpr2perlref {
285
286 my $obj = shift;
287 my $expr = shift;
288 my $callbackMap = shift;
289
290 my $value;
291 # detect for callback (code-reference)
292 if (ref($expr) eq 'CODE') {
293 $value = &$expr($obj);
294
295 } elsif ($expr =~ m/->/) {
296 # use expr as complex object reference declaration (obj->subObj->subSubObj->0->attribute)
297 (my $objPerlRefString, my $parts) = refexpr2perlref_parts($expr);
298 #print "\n", "expr: $expr";
299 #print "\n", "objPerlRefString: $objPerlRefString";
300 $value = eval('$obj' . '->' . $objPerlRefString);
301
302 # if value isn't set, try to "fallback" to callbackMap
303 # callbacks are applied this way:
304 # take the last element of the expression parts and check if this string exists as a key in the callback-map
305 if (!$value && $callbackMap) {
306 #print Dumper($callbackMap);
307
308 # prepare needle
309 my @parts = @$parts;
310 my $count = $#parts;
311 my $needle = $parts[$count];
312
313 # prepare haystack
314 my @haystack = keys %$callbackMap;
315 if (grep($needle, @haystack)) {
316 $value = $callbackMap->{$needle}->();
317 #print "value: ", $value, "\n";
318 }
319 }
320
321 } else {
322 # use expr as simple scalar key (attributename)
323 $value = $obj->{$expr};
324 }
325
326 return $value;
327
328 }
329
330
331 sub refexpr2perlref_parts {
332 my $expr = shift;
333
334 # split expression by dereference operators first
335 my @parts_pure = split(/->/, $expr);
336
337 # wrap []'s around each part, if it consists of numeric characters only (=> numeric = array-index),
338 # use {}'s, if there are word-characters in it (=> alphanumeric = hash-key)
339 my @parts_capsule = @parts_pure;
340 map {
341 m/^\d+$/ && ($_ = "[$_]") || ($_ = "{$_}");
342 } @parts_capsule;
343
344 # join parts with dereference operators together again and return built string
345 return (join('->', @parts_capsule), \@parts_pure);
346 }
347
348 1;

MailToCvsAdmin">MailToCvsAdmin
ViewVC Help
Powered by ViewVC 1.1.26 RSS 2.0 feed