/[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.16 - (hide annotations)
Thu Mar 27 15:04:52 2003 UTC (21 years, 3 months ago) by joko
Branch: MAIN
Changes since 1.15: +5 -2 lines
minor update: comment

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

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