/[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.12 - (show 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 ## ---------------------------------------------------------------------------
2 ## $Id: Deep.pm,v 1.11 2003/02/20 21:13:54 joko Exp $
3 ## ---------------------------------------------------------------------------
4 ## $Log: Deep.pm,v $
5 ## 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 ## 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 ## Revision 1.9 2003/02/18 19:35:56 joko
13 ## +- modified 'sub refexpr2perlref': now can get the $delimiter passed, too
14 ##
15 ## Revision 1.8 2003/02/09 05:10:56 joko
16 ## + minor update
17 ##
18 ## 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 ## 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
45
46 package Data::Transform::Deep;
47
48 use strict;
49 use warnings;
50
51 require Exporter;
52 our @ISA = qw( Exporter );
53 our @EXPORT_OK = qw(
54 &expand
55 &deep_copy
56 &merge_to
57 );
58
59
60 use attributes;
61 use Data::Dumper;
62 use Iterate;
63
64 use Pitonyak::DeepCopy;
65 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
68 sub numhash2list {
69 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 numhash2list($vref->{$_});
85 }
86 # } else {
87 # #$vref->{$_} = scalar2iso($vref->{$_});
88 # }
89 }
90 }
91 }
92
93
94 # 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 sub _var_deref_test {
98 my $obj = shift;
99 my $options = shift;
100 my $result;
101 if ((ref $obj) eq 'ARRAY') {
102 foreach (@{$obj}) {
103 my $ref = ref $_;
104 if ($ref) {
105 push(@{$result}, var_deref($_, $options));
106 #undef $_;
107 } else {
108 #push(@{$result}, $_);
109 push(@{$result}, deep_copy($_));
110 }
111 #undef $_ if $options->{destroy};
112 #$options->{destroy}->($_) if $options->{destroy};
113 }
114 # TODO: "} elsif (ref $obj eq 'HASH') { [...] } else { croak 'could not deref blah'; }" ???
115 } else {
116 foreach (keys %{$obj}) {
117 my $key = $_;
118 my $ref = ref $obj->{$_};
119 if ($ref) {
120 $result->{$_} = var_deref($obj->{$_}, $options);
121 #undef $obj->{$_};
122 } else {
123 #$result->{$_} = $obj->{$_};
124 $result->{$_} = deep_copy($obj->{$_});
125 }
126 #undef $obj->{$_} if $options->{destroy};
127 #$options->{destroy}->($obj->{$_}) if $options->{destroy};
128 }
129 }
130 #undef $obj if $options->{destroy};
131 $options->{cb_destroy}->($obj) if $options->{cb_destroy};
132 return $result;
133 }
134
135
136 sub expand {
137
138 my $obj = shift;
139 my $options = shift;
140 my $result;
141
142 #print "ref: ", ref $obj, "\n";
143
144 if (ref $obj eq 'ARRAY') {
145
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 $item = latin_to_utf8_scalar($item) if ($item && $options->{utf8});
161 $item = utf8_to_latin_scalar($item) if ($item && $options->{to_latin});
162 }
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 } elsif (ref $obj eq 'CODE') {
169 #print Dumper($obj);
170 #exit;
171
172 # TODO: "} elsif (ref $obj eq 'HASH') { [...] } else { croak 'could not deref blah'; }" ???
173 } elsif (ref $obj) {
174
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 $item = latin_to_utf8_scalar($item) if ($item && $options->{utf8});
191 $item = utf8_to_latin_scalar($item) if ($item && $options->{to_latin});
192 }
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 } else {
198 #die ("not a reference!");
199 $result = $obj;
200
201 }
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
216
217 my @indexstack;
218 sub _var_traverse_mixin_update_old {
219 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 sub merge_to {
263 _hash2object(@_);
264 # TODO:
265 # re-implement using CPAN's "Iterate".
266 }
267
268
269 # todo: maybe do diff(s) here sometimes!?
270 sub _hash2object {
271 my $object = shift;
272 my $data = shift;
273 my $options = shift;
274
275 #print "hash2object", "\n";
276
277 # "patch" needed 'cause php passes numerical-indexed-arrays as hash-tables,
278 # this method corrects this
279 numhash2list($data) if ($options->{php});
280
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 _hash2object_traverse_mixin($object, $data, 0, $options);
292
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 sub _hash2object_traverse_mixin {
315 my $object = shift;
316 my $data = shift;
317 my $bool_recursion = shift;
318 my $options = shift;
319
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
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
342 # print STDERR "===", "reftype: ", attributes::reftype($obj), "\n";
343
344 my @fields;
345 # loop through fields of object (Tangram-object)
346 @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 # @fields = keys %{$data} if $options->{mixin};
351
352 foreach (@fields) {
353 my $field = $_;
354 push @indexstack, $field;
355
356 # determine type of object
357 my $ref = ref $object->{$field};
358 # print STDERR "attrname: $_ ATTRref: $ref", "\n";
359 if ($ref) {
360 _hash2object_traverse_mixin($object->{$field}, $data, 1, $options);
361 } else {
362 my $val = ref_slot($data, \@indexstack);
363
364 #print Dumper($options);
365 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 }
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 # if ($ref && $_) {
404 if ($ref) {
405 _hash2object_traverse_mixin($_, $data, 1, $options);
406 } else {
407 $object->[$i] = $_ if defined $_;
408 }
409 pop @indexstack;
410 $i++;
411 }
412
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 }
422
423 }
424
425
426 # 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 }
444
445 # 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 sub deep_copy {
449 Pitonyak::DeepCopy::deep_copy(@_);
450 }
451
452
453 1;
454 __END__

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