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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (hide 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 joko 1.1 ##############################################
2     #
3 joko 1.3 # $Id: Deep.pm,v 1.2 2002/12/01 04:44:07 joko Exp $
4 joko 1.2 #
5     # $Log: Deep.pm,v $
6 joko 1.3 # Revision 1.2 2002/12/01 04:44:07 joko
7     # + code from Data::Transform::OO
8     #
9 joko 1.2 # Revision 1.1 2002/11/29 04:49:20 joko
10     # + initial check-in
11 joko 1.1 #
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 joko 1.2 our @EXPORT_OK = qw(
26     &var_NumericalHashToArray
27     &var_deref
28     &var_mixin
29     &object2hash
30     &hash2object
31     &refexpr2perlref
32 joko 1.1 );
33 joko 1.2 # &getStructSlotByStringyAddress
34 joko 1.1
35     use attributes;
36 joko 1.2 use Data::Dumper;
37 joko 1.3 use Data::Transform::Encode qw( var_utf2iso );
38 joko 1.1
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 joko 1.2 # TODO: "} elsif (ref $obj eq 'HASH') { [...] } else { croak 'could not deref blah'; }" ???
78 joko 1.1 } 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 joko 1.2 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 joko 1.3 #print "hash2object", "\n";
155    
156 joko 1.2 # "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 joko 1.1 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 joko 1.2 }
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 joko 1.1 }
352    
353     1;

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