/[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.21 - (hide annotations)
Wed Apr 9 07:21:56 2003 UTC (21 years, 3 months ago) by joko
Branch: MAIN
Changes since 1.20: +7 -23 lines
childObj2string now inside Encode.pm, renamed to 'twingle_reference'

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