/[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.13 - (hide annotations)
Fri Feb 21 01:48:50 2003 UTC (21 years, 4 months ago) by joko
Branch: MAIN
Changes since 1.12: +7 -2 lines
renamed core function

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

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