/[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.3 - (show annotations)
Tue Dec 3 05:34:55 2002 UTC (21 years, 7 months ago) by joko
Branch: MAIN
Changes since 1.2: +7 -2 lines
+ bugfix: now utilizing var_utf2iso from Data::Transform::Encode

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

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