/[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.20 - (hide annotations)
Fri Apr 4 17:31:23 2003 UTC (21 years, 3 months ago) by joko
Branch: MAIN
Changes since 1.19: +15 -6 lines
minor update to 'childObj2string'

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

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