/[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.17 - (hide annotations)
Thu Mar 27 15:17:07 2003 UTC (21 years, 3 months ago) by joko
Branch: MAIN
Changes since 1.16: +7 -4 lines
namespace fixes for Data::Mungle::*

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

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