/[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.19 - (hide annotations)
Fri Mar 28 03:11:25 2003 UTC (21 years, 3 months ago) by jonen
Branch: MAIN
Changes since 1.18: +6 -2 lines
+ bugfix

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

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