/[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.11 - (hide annotations)
Thu Feb 20 21:13:54 2003 UTC (21 years, 4 months ago) by joko
Branch: MAIN
Changes since 1.10: +6 -51 lines
- removed implementation of deep_copy2 - get this from the Pitonyak namespace (now cloned to repository)

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

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