/[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.12 - (hide annotations)
Thu Feb 20 22:45:19 2003 UTC (21 years, 4 months ago) by joko
Branch: MAIN
Changes since 1.11: +7 -2 lines
fix regarding new deep_copy

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

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