/[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.18 - (hide annotations)
Fri Mar 28 03:07:26 2003 UTC (21 years, 3 months ago) by jonen
Branch: MAIN
Changes since 1.17: +6 -3 lines
+ minor changes

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

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