/[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.18 - (show annotations)
Fri Mar 28 03:07:26 2003 UTC (21 years, 3 months ago) by jonen
Branch: MAIN
Changes since 1.17: +6 -3 lines
+ minor changes

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

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