File Coverage

blib/lib/WE_Content/Tools.pm
Criterion Covered Total %
statement 6 70 8.5
branch 0 24 0.0
condition 0 9 0.0
subroutine 2 10 20.0
pod 0 4 0.0
total 8 117 6.8


line stmt bran cond sub pod time code
1             # -*- perl -*-
2              
3             #
4             # $Id: Tools.pm,v 1.7 2004/04/13 21:48:50 eserte Exp $
5             # Author: Slaven Rezic
6             #
7             # Copyright (C) 2001 Online Office Berlin. All rights reserved.
8             # Copyright (C) 2002 Slaven Rezic.
9             # This is free software; you can redistribute it and/or modify it under the
10             # terms of the GNU General Public License, see the file COPYING.
11              
12             #
13             # Mail: slaven@rezic.de
14             # WWW: http://we-framework.sourceforge.net
15             #
16              
17             package WE_Content::Tools;
18              
19 2     2   1885 use strict;
  2         4  
  2         74  
20 2     2   10 use vars qw($VERSION);
  2         11  
  2         2362  
21             $VERSION = sprintf("%d.%02d", q$Revision: 1.7 $ =~ /(\d+)\.(\d+)/);
22              
23             package WE_Content::Base;
24              
25             =head1 NAME
26              
27             WE_Content::Tools - tools for content objects
28              
29             =head1 SYNOPSIS
30              
31             use WE_Content::Tools;
32             $content_object->find(sub { ... });
33              
34             =head1 DESCRIPTION
35              
36             =head2 METHODS
37              
38             =over 4
39              
40             =item get_structure_diffs($template)
41              
42             Return a list of differences against a template object. Only language
43             data is compared. See L for the output format.
44              
45             =cut
46              
47             sub get_structure_diffs {
48 0     0 0   my($self, $template) = @_;
49 0 0         die "Template should be a template" if !$template->{Type} eq 'template';
50 0           require Algorithm::Diff;
51 0           require Data::Dumper;
52              
53 0           my %ret;
54              
55 0           while(my($lang, $langval) = each %{ $self->{Object}->{'data'} }) {
  0            
56 0 0 0       next unless (UNIVERSAL::isa($langval, 'HASH') &&
57             exists $langval->{'ct'});
58 0           my $ct = $langval->{'ct'};
59 0           my $template_ct = $template->{Object}{'ct'};
60             my(@diffs) = Algorithm::Diff::diff
61             ($template_ct, $ct,
62 0     0     sub { Data::Dumper->new([shift],['n'])->Sortkeys(1)->Dump }
63 0           );
64              
65 0           $ret{$lang} = \@diffs;
66             }
67              
68 0           %ret;
69             }
70              
71             =item upgrade($template)
72              
73             Upgrade the content file to the current $template.
74              
75             =cut
76              
77             sub upgrade {
78 0     0 0   my($self, $template) = @_;
79 0 0         die "Template should be a template" if !$template->{Type} eq 'template';
80              
81 0           require Storable;
82              
83             my $_upgrade = sub {
84 0     0     my($ct, $template_ct) = @_;
85 0           for my $i (0 .. $#$ct) {
86 0           my $ct_node = $ct->[$i];
87 0           my $tct_node = $template_ct->[$i];
88 0 0 0       if ($ct_node->{type} eq $tct_node->{type} &&
89             $ct_node->{name} eq $tct_node->{name}
90             ) {
91 0           my $ct_cancontain = join("|", $ct_node->{cancontain});
92 0           my $tct_cancontain = join("|", $tct_node->{cancontain});
93 0 0         if ($ct_cancontain ne $tct_cancontain) {
94 0           $ct_node->{cancontain} = Storable::dclone($tct_node->{cancontain});
95             }
96             }
97             }
98 0           };
99              
100 0           while(my($lang, $langval) = each %{ $self->{Object}->{'data'} }) {
  0            
101 0 0 0       next unless (UNIVERSAL::isa($langval, 'HASH') &&
102             exists $langval->{'ct'});
103 0           my $ct = $langval->{'ct'};
104 0           my $template_ct = $template->{Object}{'ct'};
105 0           $_upgrade->($ct, $template_ct);
106             }
107             }
108              
109             sub simple_diff {
110 0     0 0   my($self, $self2) = @_;
111 0           require Algorithm::Diff;
112 0           my(@ret) = Algorithm::Diff::diff([$self->{Object}], [$self2->{Object}], \&_diff_key);
113 0           @ret;
114             }
115              
116             sub _diff_key {
117 0     0     my($o) = @_;
118 0 0         if (ref $o eq 'HASH') {
    0          
119 0           my @s;
120 0           foreach my $key (sort keys %$o) {
121 0           push @s, $key, _diff_key($o->{$key});
122             }
123 0           "{".join("|", @s)."}"; # XXX may fail if there are "|" in the keys
124             } elsif (ref $o eq 'ARRAY') {
125 0           "[".join("|", map { _diff_key($_) } @$o)."]";
  0            
126             } else {
127 0           $o;
128             }
129             }
130              
131             =item find($callback)
132              
133             Traverses the content object and calls C<$callback> for each node in
134             the content tree. The following arguments will be supplied to the
135             callback:
136              
137             =over
138              
139             =item $object
140              
141             C<$object> is aa reference to the current object. A change to this
142             reference will also manipulate the original object.
143              
144             =item -parents => [$parent1, $parent2, ...]
145              
146             A list of parent objects. The root object is not in the list.
147             Descendants are appended to the right, that is, too find the parent
148             use C<[-1]> as index, the grandfather is C<[-2]> and Adam is C<[0]>.
149              
150             =item -path => $pathstring
151              
152             The C<$pathstring> can be evaluated to access the node. Example:
153              
154             ->{'data'}->[0]->{'type'}
155              
156             =item -dotted => $dotstring
157              
158             Same as C<-path>, but use a dot notation. Example:
159              
160             data.0.type
161              
162             =item -key => $key
163              
164             Only for hash items: C<$keys> is the current key. The value is in
165             C<$object>.
166              
167             =back
168              
169             TODO:
170              
171             implement prune
172             suggest to add something similar to Data::Walker
173              
174             =cut
175              
176             sub find {
177 0     0 0   my($self, $wanted) = @_;
178 0           $self->_find($self->{Object}, $wanted,
179             -parents => [], -path => "", -dotted => "");
180             }
181              
182             sub _find {
183 0     0     my($self, $o, $wanted, %args) = @_;
184 0           $wanted->($o, %args);
185              
186 0           my %extra_args;
187 0           $extra_args{-parents} = [@{ $args{-parents} }, $o];
  0            
188 0 0         if (ref $o eq 'ARRAY') {
    0          
189 0           my $ii = 0;
190 0 0         my $parent_dotted = $args{-dotted} ne "" ? "$args{-dotted}." : "";
191 0           foreach my $i (@$o) {
192 0           $self->_find($i, $wanted,
193             -path => $args{-path}."->[$ii]",
194             -dotted => $parent_dotted.$ii,
195             %extra_args);
196 0           $ii++;
197             }
198             } elsif (ref $o eq 'HASH') {
199 0           my @keys = keys %$o;
200 0 0         my $parent_dotted = $args{-dotted} ne "" ? "$args{-dotted}." : "";
201 0           foreach my $k (@keys) {
202 0           my $v = $o->{$k};
203 0           $self->_find($v, $wanted,
204             -key => $k,
205             -path => $args{-path}."->{'$k'}", # XXX quote?
206             -dotted => $parent_dotted.$k,
207             %extra_args);
208             }
209             }
210             }
211              
212             1;
213              
214             __END__