/[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.2 - (hide 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 joko 1.1 ##############################################
2     #
3 joko 1.2 # $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 joko 1.1 #
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 joko 1.2 our @EXPORT_OK = qw(
23     &var_NumericalHashToArray
24     &var_deref
25     &var_mixin
26     &object2hash
27     &hash2object
28     &refexpr2perlref
29 joko 1.1 );
30 joko 1.2 # &getStructSlotByStringyAddress
31 joko 1.1
32     use attributes;
33 joko 1.2 use Data::Dumper;
34 joko 1.1
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 joko 1.2 # TODO: "} elsif (ref $obj eq 'HASH') { [...] } else { croak 'could not deref blah'; }" ???
75 joko 1.1 } 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 joko 1.2 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 joko 1.1 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 joko 1.2 }
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 joko 1.1 }
347    
348     1;

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