/[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.15 - (hide annotations)
Thu Feb 27 14:39:48 2003 UTC (21 years, 4 months ago) by jonen
Branch: MAIN
Changes since 1.14: +6 -2 lines
+ fixed bug at _hash2object()

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

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