/[cvs]/nfo/perl/libs/Data/Mungle/Transform/Deep.pm
ViewVC logotype

Contents of /nfo/perl/libs/Data/Mungle/Transform/Deep.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.15 - (show 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 ## ---------------------------------------------------------------------------
2 ## $Id: Deep.pm,v 1.14 2003/02/22 17:13:55 jonen Exp $
3 ## ---------------------------------------------------------------------------
4 ## $Log: Deep.pm,v $
5 ## 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 ## Revision 1.13 2003/02/21 01:48:50 joko
10 ## renamed core function
11 ##
12 ## Revision 1.12 2003/02/20 22:45:19 joko
13 ## fix regarding new deep_copy
14 ##
15 ## 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 ## 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 ## Revision 1.9 2003/02/18 19:35:56 joko
23 ## +- modified 'sub refexpr2perlref': now can get the $delimiter passed, too
24 ##
25 ## Revision 1.8 2003/02/09 05:10:56 joko
26 ## + minor update
27 ##
28 ## 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 ## 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
55
56 package Data::Transform::Deep;
57
58 use strict;
59 use warnings;
60
61 require Exporter;
62 our @ISA = qw( Exporter );
63 our @EXPORT_OK = qw(
64 &expand
65 &deep_copy
66 &merge_to
67 );
68
69
70 use attributes;
71 use Data::Dumper;
72 use Iterate;
73
74 use Pitonyak::DeepCopy;
75 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
78 sub numhash2list {
79 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 numhash2list($vref->{$_});
95 }
96 # } else {
97 # #$vref->{$_} = scalar2iso($vref->{$_});
98 # }
99 }
100 }
101 }
102
103
104 # 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 sub _var_deref_test {
108 my $obj = shift;
109 my $options = shift;
110 my $result;
111 if ((ref $obj) eq 'ARRAY') {
112 foreach (@{$obj}) {
113 my $ref = ref $_;
114 if ($ref) {
115 push(@{$result}, var_deref($_, $options));
116 #undef $_;
117 } else {
118 #push(@{$result}, $_);
119 push(@{$result}, deep_copy($_));
120 }
121 #undef $_ if $options->{destroy};
122 #$options->{destroy}->($_) if $options->{destroy};
123 }
124 # TODO: "} elsif (ref $obj eq 'HASH') { [...] } else { croak 'could not deref blah'; }" ???
125 } else {
126 foreach (keys %{$obj}) {
127 my $key = $_;
128 my $ref = ref $obj->{$_};
129 if ($ref) {
130 $result->{$_} = var_deref($obj->{$_}, $options);
131 #undef $obj->{$_};
132 } else {
133 #$result->{$_} = $obj->{$_};
134 $result->{$_} = deep_copy($obj->{$_});
135 }
136 #undef $obj->{$_} if $options->{destroy};
137 #$options->{destroy}->($obj->{$_}) if $options->{destroy};
138 }
139 }
140 #undef $obj if $options->{destroy};
141 $options->{cb_destroy}->($obj) if $options->{cb_destroy};
142 return $result;
143 }
144
145
146 # 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 sub expand {
149
150 my $obj = shift;
151 my $options = shift;
152 my $result;
153
154 #print "ref: ", ref $obj, "\n";
155
156 if (ref $obj eq 'ARRAY') {
157
158 IterArray @$obj, sub {
159 my $item;
160 # if current item is a reference ...
161 if (ref $_[0]) {
162 $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 # 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 $item = latin_to_utf8_scalar($item) if ($item && $options->{utf8});
180 $item = utf8_to_latin_scalar($item) if ($item && $options->{to_latin});
181 }
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 } elsif (ref $obj eq 'CODE') {
188 #print Dumper($obj);
189 #exit;
190
191 # TODO: "} elsif (ref $obj eq 'HASH') { [...] } else { croak 'could not deref blah'; }" ???
192 } elsif (ref $obj) {
193
194 IterHash %$obj, sub {
195 my $item;
196
197 # if current item is a reference ...
198 if (ref $_[1]) {
199 $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 # 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 $item = latin_to_utf8_scalar($item) if ($item && $options->{utf8});
217 $item = utf8_to_latin_scalar($item) if ($item && $options->{to_latin});
218 }
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 } else {
224 #die ("not a reference!");
225 $result = $obj;
226
227 }
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 # latin_to_utf8($result) if ($options->{utf8});
232
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
242
243 my @indexstack;
244 sub _var_traverse_mixin_update_old {
245 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 sub merge_to {
289 _hash2object(@_);
290 # TODO:
291 # re-implement using CPAN's "Iterate".
292 }
293
294
295 # todo: maybe do diff(s) here sometimes!?
296 sub _hash2object {
297 my $object = shift;
298 my $data = shift;
299 my $options = shift;
300
301 #print "hash2object", "\n";
302
303 # "patch" needed 'cause php passes numerical-indexed-arrays as hash-tables,
304 # this method corrects this
305 numhash2list($data) if ($options->{php});
306
307 # utf8-conversion/-encoding (essential for I18N)
308 utf8_to_latin($data) if ($options->{utf8});
309
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 _hash2object_traverse_mixin($object, $data, 0, $options);
318
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 sub _hash2object_traverse_mixin {
341 my $object = shift;
342 my $data = shift;
343 my $bool_recursion = shift;
344 my $options = shift;
345
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
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
368 # print STDERR "===", "reftype: ", attributes::reftype($obj), "\n";
369
370 my @fields;
371 # loop through fields of object (Tangram-object)
372 @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 # @fields = keys %{$data} if $options->{mixin};
377
378 foreach (@fields) {
379 my $field = $_;
380 push @indexstack, $field;
381
382 # determine type of object
383 my $ref = ref $object->{$field};
384 # print STDERR "attrname: $_ ATTRref: $ref", "\n";
385 if ($ref) {
386 _hash2object_traverse_mixin($object->{$field}, $data, 1, $options);
387 } else {
388 my $val = ref_slot($data, \@indexstack);
389
390 #print Dumper($options);
391 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 }
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 # if ($ref && $_) {
430 if ($ref) {
431 _hash2object_traverse_mixin($_, $data, 1, $options);
432 } else {
433 $object->[$i] = $_ if defined $_;
434 }
435 pop @indexstack;
436 $i++;
437 }
438
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 }
448
449 }
450
451
452 # 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 }
470
471 # 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 sub deep_copy {
475 Pitonyak::DeepCopy::deep_copy(@_);
476 }
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 }
489
490
491 1;
492 __END__

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