/[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.14 - (hide annotations)
Sat Feb 22 17:13:55 2003 UTC (21 years, 4 months ago) by jonen
Branch: MAIN
Changes since 1.13: +34 -5 lines
+ added function 'childObject2string()' to encode 'child'-references to option related string
+ use new option at 'expand()' for replacing 'childObject2string'

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

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