/[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.22 - (hide annotations)
Sat May 10 17:09:18 2003 UTC (21 years, 2 months ago) by jonen
Branch: MAIN
Changes since 1.21: +18 -4 lines
+ added keep of empty arrays/hashes if 'expand' for php

1 joko 1.7 ## ---------------------------------------------------------------------------
2 jonen 1.22 ## $Id: Deep.pm,v 1.21 2003/04/09 07:21:56 joko Exp $
3 joko 1.7 ## ---------------------------------------------------------------------------
4 joko 1.8 ## $Log: Deep.pm,v $
5 jonen 1.22 ## Revision 1.21 2003/04/09 07:21:56 joko
6     ## childObj2string now inside Encode.pm, renamed to 'twingle_reference'
7     ##
8 joko 1.21 ## Revision 1.20 2003/04/04 17:31:23 joko
9     ## minor update to 'childObj2string'
10     ##
11 joko 1.20 ## Revision 1.19 2003/03/28 03:11:25 jonen
12     ## + bugfix
13     ##
14 jonen 1.19 ## Revision 1.18 2003/03/28 03:07:26 jonen
15     ## + minor changes
16     ##
17 jonen 1.18 ## Revision 1.17 2003/03/27 15:17:07 joko
18     ## namespace fixes for Data::Mungle::*
19     ##
20 joko 1.17 ## Revision 1.16 2003/03/27 15:04:52 joko
21     ## minor update: comment
22     ##
23 joko 1.16 ## Revision 1.15 2003/02/27 14:39:48 jonen
24     ## + fixed bug at _hash2object()
25     ##
26 jonen 1.15 ## Revision 1.14 2003/02/22 17:13:55 jonen
27     ## + added function 'childObject2string()' to encode 'child'-references to option related string
28     ## + use new option at 'expand()' for replacing 'childObject2string'
29     ##
30 jonen 1.14 ## Revision 1.13 2003/02/21 01:48:50 joko
31     ## renamed core function
32     ##
33 joko 1.13 ## Revision 1.12 2003/02/20 22:45:19 joko
34     ## fix regarding new deep_copy
35     ##
36 joko 1.12 ## Revision 1.11 2003/02/20 21:13:54 joko
37     ## - removed implementation of deep_copy2 - get this from the Pitonyak namespace (now cloned to repository)
38     ##
39 joko 1.11 ## Revision 1.10 2003/02/20 20:48:00 joko
40     ## - refactored lots of code to Data::Code::Ref
41     ## + alternative 'deep_copy' implementation
42     ##
43 joko 1.10 ## Revision 1.9 2003/02/18 19:35:56 joko
44     ## +- modified 'sub refexpr2perlref': now can get the $delimiter passed, too
45     ##
46 joko 1.9 ## Revision 1.8 2003/02/09 05:10:56 joko
47     ## + minor update
48     ##
49 joko 1.8 ## Revision 1.7 2003/01/19 03:26:59 joko
50     ## + added 'sub deep_copy' - refactored from libp
51     ## + add 'sub merge' - exported from CPAN's 'Hash::Merge'
52     ##
53 joko 1.7 ## Revision 1.6 2002/12/23 11:27:53 jonen
54     ## + changed behavior WATCH!
55     ##
56     ## Revision 1.5 2002/12/16 19:57:54 joko
57     ## + option 'init'
58     ##
59     ## Revision 1.4 2002/12/05 13:56:49 joko
60     ## - var_deref
61     ## + expand - more sophisticated dereferencing with callbacks using Iterate
62     ##
63     ## Revision 1.3 2002/12/03 05:34:55 joko
64     ## + bugfix: now utilizing var_utf2iso from Data::Transform::Encode
65     ##
66     ## Revision 1.2 2002/12/01 04:44:07 joko
67     ## + code from Data::Transform::OO
68     ##
69     ## Revision 1.1 2002/11/29 04:49:20 joko
70     ## + initial check-in
71     ##
72     ## Revision 1.1 2002/10/10 03:26:00 cvsjoko
73     ## + new
74     ## ---------------------------------------------------------------------------
75 joko 1.1
76    
77 joko 1.17 package Data::Mungle::Transform::Deep;
78 joko 1.1
79     use strict;
80     use warnings;
81    
82     require Exporter;
83     our @ISA = qw( Exporter );
84 joko 1.2 our @EXPORT_OK = qw(
85 joko 1.4 &expand
86 joko 1.7 &deep_copy
87 joko 1.10 &merge_to
88 joko 1.1 );
89 joko 1.10
90 joko 1.1
91     use attributes;
92 joko 1.2 use Data::Dumper;
93 joko 1.10 use Iterate;
94 joko 1.7
95 joko 1.12 use Pitonyak::DeepCopy;
96 joko 1.21 use Data::Mungle::Transform::Encode qw( latin_to_utf8 latin_to_utf8_scalar utf8_to_latin utf8_to_latin_scalar twingle_reference );
97 joko 1.17 use Data::Mungle::Code::Ref qw( ref_slot );
98 joko 1.1
99 joko 1.10 sub numhash2list {
100 joko 1.1 my $vref = shift;
101     #my $context = shift;
102     if (ref $vref eq 'HASH') {
103     foreach (keys %{$vref}) {
104     # if ((ref $vref->{$_}) =~ m/HASH/) {
105     if ((ref $vref->{$_}) =~ m/HASH/) {
106     if ($vref->{$_}{0}) { # might be a numerical-indexed array
107     #print "000\n";
108     #print "context: $context\n";
109     my @arr;
110     foreach my $key_numeric (sort keys %{$vref->{$_}}) {
111     push @arr, $vref->{$_}{$key_numeric};
112     }
113     $vref->{$_} = \@arr;
114     }
115 joko 1.10 numhash2list($vref->{$_});
116 joko 1.1 }
117     # } else {
118     # #$vref->{$_} = scalar2iso($vref->{$_});
119     # }
120     }
121     }
122     }
123    
124    
125 joko 1.9 # FIXME: could this be refactored using expand?
126     # btw: "expand": look at scripts@CPAN (System Administration):
127     # there is a perl make with perl
128 joko 1.10 sub _var_deref_test {
129 joko 1.1 my $obj = shift;
130 joko 1.4 my $options = shift;
131 joko 1.1 my $result;
132     if ((ref $obj) eq 'ARRAY') {
133     foreach (@{$obj}) {
134     my $ref = ref $_;
135     if ($ref) {
136 joko 1.4 push(@{$result}, var_deref($_, $options));
137     #undef $_;
138 joko 1.1 } else {
139 joko 1.4 #push(@{$result}, $_);
140     push(@{$result}, deep_copy($_));
141 joko 1.1 }
142 joko 1.4 #undef $_ if $options->{destroy};
143     #$options->{destroy}->($_) if $options->{destroy};
144 joko 1.1 }
145 joko 1.2 # TODO: "} elsif (ref $obj eq 'HASH') { [...] } else { croak 'could not deref blah'; }" ???
146 joko 1.1 } else {
147     foreach (keys %{$obj}) {
148     my $key = $_;
149     my $ref = ref $obj->{$_};
150     if ($ref) {
151 joko 1.4 $result->{$_} = var_deref($obj->{$_}, $options);
152     #undef $obj->{$_};
153 joko 1.1 } else {
154 joko 1.4 #$result->{$_} = $obj->{$_};
155     $result->{$_} = deep_copy($obj->{$_});
156 joko 1.1 }
157 joko 1.4 #undef $obj->{$_} if $options->{destroy};
158     #$options->{destroy}->($obj->{$_}) if $options->{destroy};
159 joko 1.1 }
160     }
161 joko 1.4 #undef $obj if $options->{destroy};
162     $options->{cb_destroy}->($obj) if $options->{cb_destroy};
163 joko 1.1 return $result;
164     }
165    
166    
167 joko 1.13 # convert values in hash to utf8 (and back) to be ready for (e.g.) encapsulation in XML
168     # but still using the known latin locale stuff
169 joko 1.4 sub expand {
170    
171     my $obj = shift;
172     my $options = shift;
173     my $result;
174    
175 joko 1.10 #print "ref: ", ref $obj, "\n";
176    
177     if (ref $obj eq 'ARRAY') {
178 jonen 1.22
179     # if we expand for php, keep empty ARRAY
180     if($#$obj == -1 && $options->{childObj2string}) {
181     $result = $obj;
182     } else {
183 joko 1.4 IterArray @$obj, sub {
184     my $item;
185     # if current item is a reference ...
186     if (ref $_[0]) {
187 jonen 1.14 $item = $_[0];
188     # if $options->{childObj2string} is TRUE or STRING don't expand referenced object,
189     # instead replace it by per option choosed string (default: o_<classname>_<ref type>_<guid> )
190     if ($item && $options->{childObj2string}) {
191 joko 1.21 $item = twingle_reference($item);
192 jonen 1.14 } else {
193     # ... expand structure recursively
194     $item = expand($_[0], $options);
195     }
196 joko 1.4 # destroy item via seperate callback method (a POST) if requested
197     #$options->{cb}->{destroy}->($_[0]) if $options->{destroy};
198    
199     # ... assume plain scalar
200     } else {
201     #$item = deep_copy($_[0]);
202     $item = $_[0];
203     # conversions/encodings
204 joko 1.10 $item = latin_to_utf8_scalar($item) if ($item && $options->{utf8});
205     $item = utf8_to_latin_scalar($item) if ($item && $options->{to_latin});
206 joko 1.4 }
207     #push(@{$result}, $item) if $item; # use item only if not undef (TODO: make configurable via $options)
208     push(@{$result}, $item); # use item in any case
209    
210     }
211 jonen 1.22 }
212 joko 1.4
213 joko 1.10 } elsif (ref $obj eq 'CODE') {
214     #print Dumper($obj);
215     #exit;
216    
217 joko 1.4 # TODO: "} elsif (ref $obj eq 'HASH') { [...] } else { croak 'could not deref blah'; }" ???
218 joko 1.10 } elsif (ref $obj) {
219 jonen 1.22
220     # if we expand for php, keep empty HASH
221     my @tmp = keys %$obj;
222     if($#tmp == -1 && $options->{childObj2string}) {
223     $result = $obj;
224     } else {
225 joko 1.4 IterHash %$obj, sub {
226     my $item;
227    
228     # if current item is a reference ...
229     if (ref $_[1]) {
230 jonen 1.14 $item = $_[1];
231     # if $options->{childObj2string} is TRUE or STRING don't expand referenced object,
232     # instead replace it by per option choosed string (default: o_<classname>_<ref type>_<guid> )
233 jonen 1.22 if ($item && $options->{childObj2string} && !(ref $_[1] eq "ARRAY") && !(ref $_[1] eq "HASH") && !(ref $_[1] eq "Set::Object")) {
234 joko 1.21 $item = twingle_reference($item);
235 jonen 1.14 } else {
236     # ... expand structure recursively
237     $item = expand($_[1], $options);
238     }
239 joko 1.4 # destroy item via seperate callback method (a POST) if requested
240     #$options->{cb}->{destroy}->($_[1]) if $options->{destroy};
241    
242     # ... assume plain scalar
243     } else {
244     #$item = deep_copy($_[1]);
245     $item = $_[1];
246     # conversions/encodings
247 joko 1.10 $item = latin_to_utf8_scalar($item) if ($item && $options->{utf8});
248     $item = utf8_to_latin_scalar($item) if ($item && $options->{to_latin});
249 joko 1.4 }
250     #$result->{$_[0]} = $item if $item; # use item only if not undef (TODO: make configurable via $options)
251     $result->{$_[0]} = $item; # use item in any case
252     }
253 jonen 1.22 }
254 joko 1.4
255 joko 1.10 } else {
256     #die ("not a reference!");
257     $result = $obj;
258    
259 joko 1.4 }
260    
261     # convert all values to utf8 (inside complex struct)
262     # now done in core-item-callbacks via Greg London's "Iterate" from CPAN
263 joko 1.13 # latin_to_utf8($result) if ($options->{utf8});
264 joko 1.4
265     # destroy persistent object from memory to be sure to get a fresh one next time
266     #undef $obj if $options->{destroy};
267     #$options->{cb_destroy}->($obj) if $options->{cb_destroy};
268     #$options->{cb}->{destroy}->($obj) if $options->{destroy};
269    
270     return $result;
271     }
272    
273 joko 1.1
274    
275     my @indexstack;
276 joko 1.10 sub _var_traverse_mixin_update_old {
277 joko 1.1 my $obj = shift;
278     my $data = shift;
279     my $bool_recursion = shift;
280     if (!$bool_recursion) {
281     @indexstack = ();
282     }
283     my $result;
284    
285     # 'ARRAY' does not work!
286     if ((ref $obj) eq 'ARRAY') {
287     #print "ARRAY\n";
288     my $i = 0;
289     foreach (@{$obj}) {
290     push @indexstack, $i;
291     my $ref = ref $_;
292     if ($ref) {
293     #$obj->[$i] = var_mixin($_, $data, 1);
294     var_traverse_mixin_update($_, $data, 1);
295     } else {
296     $obj->[$i] = $_;
297     }
298     pop @indexstack;
299     $i++;
300     }
301     } else {
302     foreach (keys %{$obj}) {
303     push @indexstack, $_;
304     my $ref = ref $obj->{$_};
305     if ($ref) {
306     #$obj->{$_} = var_mixin($obj->{$_}, $data, 1);
307     var_traverse_mixin_update($obj->{$_}, $data, 1);
308     } else {
309     #$obj->{$_} = $obj->{$_};
310     my $evstring = getSlot($data);
311     $obj->{$_} = $evstring;
312    
313     }
314     pop @indexstack;
315     }
316     }
317     #return $result;
318     }
319    
320 joko 1.10 sub merge_to {
321     _hash2object(@_);
322     # TODO:
323 joko 1.16 # re-implement using CPAN's "Iterate" and/or a modified Hash::Merge.
324 joko 1.2 }
325    
326 joko 1.10
327 joko 1.2 # todo: maybe do diff(s) here sometimes!?
328 joko 1.10 sub _hash2object {
329 joko 1.2 my $object = shift;
330     my $data = shift;
331     my $options = shift;
332    
333 joko 1.3 #print "hash2object", "\n";
334    
335 joko 1.2 # "patch" needed 'cause php passes numerical-indexed-arrays as hash-tables,
336     # this method corrects this
337 joko 1.10 numhash2list($data) if ($options->{php});
338 joko 1.2
339     # utf8-conversion/-encoding (essential for I18N)
340 jonen 1.15 utf8_to_latin($data) if ($options->{utf8});
341 joko 1.2
342     # get fresh object from database
343     # todo:
344     # - handle "locked" objects !!!
345     # - check if already another update occoured (object-revisioning needed!)
346     #my $obj = $self->getObject($oid);
347    
348     # mix changes into fresh object and save it back
349 joko 1.10 _hash2object_traverse_mixin($object, $data, 0, $options);
350 joko 1.2
351     # done in core mixin function?
352     #$self->{storage}->update($obj);
353    
354     # we should "undef" some objects here to destroy them in memory and enforce reloading when used next time
355     # simulate:
356     #$self->{storage}->disconnect();
357    
358     }
359    
360     # ------------------------------------
361     # core mixin function
362     # TODO-FEATURE: make this possible in a reverse way: object is empty (no fields) and gets filled up by mixin-data
363    
364     # remember keys of structures we are traversing
365     # this is a HACK:
366     # - don't (!!!) "packageglobal" @indexstack
367     # - it will lead to problems with parallelism!
368    
369     #my @indexstack;
370    
371     # traverse a deeply nested structure, mix in values from given hash, update underlying tangram-object
372 joko 1.10 sub _hash2object_traverse_mixin {
373 joko 1.2 my $object = shift;
374     my $data = shift;
375     my $bool_recursion = shift;
376 joko 1.5 my $options = shift;
377 joko 1.2
378     # clear our key - stack if we are called from user-code (non-recursively)
379     @indexstack = () if (!$bool_recursion);
380    
381     my $classname = ref $object;
382     # if ($classname) {
383     # print STDERR "*****************", Dumper(Class::Tangram::attribute_types($classname)), "\n";
384     # }
385    
386     # parser: detected OBJECT (a Tangram one?) (reftype == HASH) (assume)
387     # what's exactly done here? hmmm.... it works ;)
388     # maybe a HACK: please try not to use "IntrHash"es, maybe this cannot handle them!!!
389     # extend! check!
390 joko 1.10
391     #print attributes::reftype($object), "\n";
392    
393     # V1
394     #if ((attributes::reftype($object) eq 'HASH') && (ref($object) ne 'HASH') && (ref($object) ne 'ARRAY')) {
395     # V2
396     my $reftype = attributes::reftype($object);
397     #print "reftype: '$reftype'", "\n";
398     if ($reftype eq 'HASH') {
399 joko 1.2
400     # print STDERR "===", "reftype: ", attributes::reftype($obj), "\n";
401    
402 joko 1.5 my @fields;
403 joko 1.2 # loop through fields of object (Tangram-object)
404 joko 1.5 @fields = keys %{$object};
405    
406     # loop through fields of to.be.injected-data (arbitrary Perl-data-structure)
407     @fields = keys %{$data} if $options->{init};
408 jonen 1.6 # @fields = keys %{$data} if $options->{mixin};
409 joko 1.5
410     foreach (@fields) {
411 joko 1.7 my $field = $_;
412     push @indexstack, $field;
413 joko 1.2
414     # determine type of object
415 joko 1.7 my $ref = ref $object->{$field};
416 joko 1.2 # print STDERR "attrname: $_ ATTRref: $ref", "\n";
417     if ($ref) {
418 joko 1.10 _hash2object_traverse_mixin($object->{$field}, $data, 1, $options);
419 joko 1.2 } else {
420 joko 1.10 my $val = ref_slot($data, \@indexstack);
421 joko 1.7
422 joko 1.8 #print Dumper($options);
423 joko 1.7 my $field_target = $field;
424     if (my $pattern = $options->{pattern_strip_key}) {
425     print "pattern: $pattern", "\n";
426     $field_target =~ s/$pattern//;
427     print "field: $field_target", "\n";
428     }
429    
430     $object->{$field_target} = $val if defined $val;
431 joko 1.2 }
432     pop @indexstack;
433     }
434    
435     # save object to database ...
436     # ... do an update if it already exists, do an insert if it doesn't
437     # my $objectId = $self->{storage}->id($obj);
438     # $logger->debug( __PACKAGE__ . "->saveObjectFromHash_traverse_mixin_update( object $obj objectId $objectId )" );
439     # if ($objectId) {
440     # $self->{storage}->update($obj);
441    
442     #print __PACKAGE__ . ":", "\n";
443     #print Dumper($object);
444    
445     # } else {
446     # $self->{storage}->insert($obj);
447     # }
448    
449     }
450    
451     #&& ( ref($obj) ne 'HASH' )
452    
453     # loop through entries of array (IntrArray, isn't it?)
454     if ((ref $object) eq 'ARRAY') {
455     # print STDERR "===", "refttype ", attributes::reftype($obj), "\n";
456     my $i = 0;
457     foreach (@{$object}) {
458     push @indexstack, $i;
459     my $ref = ref $_;
460     # print STDERR "attrname: $_ ATTRref: $ref", "\n";
461 jonen 1.6 # if ($ref && $_) {
462     if ($ref) {
463 joko 1.10 _hash2object_traverse_mixin($_, $data, 1, $options);
464 joko 1.2 } else {
465 jonen 1.6 $object->[$i] = $_ if defined $_;
466 joko 1.2 }
467     pop @indexstack;
468     $i++;
469     }
470 joko 1.10
471     =pod
472     # object?
473     } else {
474     print "reference: ", ref $object, "\n";
475     print "reftype: ", $reftype, "\n";
476     die(__PACKAGE__ . "->_hash2object_traverse_mixin: can not handle this!");
477     =cut
478    
479 joko 1.2 }
480    
481     }
482    
483    
484 joko 1.10 # ACK's go to Randal L. Schwartz <merlyn@stonehenge.com>
485     # on the website:
486     # This text is copyright by Miller-Freeman, Inc., and is used with their permission.
487     # Further distribution or use is not permitted.
488     # please visit http://www.stonehenge.com/merlyn/UnixReview/col30.html
489     sub deep_copy1 {
490     my $this = shift;
491     if (not ref $this) {
492     $this;
493     } elsif (ref $this eq "ARRAY") {
494     [map deep_copy1($_), @$this];
495     } elsif (ref $this eq "HASH") {
496     +{map { $_ => deep_copy1($this->{$_}) } keys %$this};
497     } elsif (ref $this eq "CODE") {
498     $this;
499     } else { die "deep_copy1 asks: what type is $this?" }
500     #} else { print "deep_copy asks: what type is $this?", "\n"; }
501 joko 1.2 }
502    
503 joko 1.10 # ACK's go to Andrew Pitonyak
504     # Copyright 2002, Andrew Pitonyak (perlboy@pitonyak.org)
505     # please visit: http://www.pitonyak.org/code/perl/Pitonyak/DeepCopy.pm.html
506 joko 1.7 sub deep_copy {
507 joko 1.12 Pitonyak::DeepCopy::deep_copy(@_);
508 joko 1.1 }
509 joko 1.12
510 joko 1.1
511     1;
512 joko 1.10 __END__

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