File Coverage

blib/lib/Toolforge/MixNMatch/Diff.pm
Criterion Covered Total %
statement 65 84 77.3
branch 14 30 46.6
condition 1 5 20.0
subroutine 10 10 100.0
pod 1 1 100.0
total 91 130 70.0


line stmt bran cond sub pod time code
1             package Toolforge::MixNMatch::Diff;
2              
3 3     3   237632 use strict;
  3         25  
  3         89  
4 3     3   17 use warnings;
  3         6  
  3         84  
5              
6 3     3   1499 use Error::Pure qw(err);
  3         35806  
  3         62  
7 3     3   1821 use Toolforge::MixNMatch::Object::Catalog;
  3         15706  
  3         109  
8 3     3   1488 use Toolforge::MixNMatch::Object::User;
  3         1758  
  3         87  
9 3     3   1458 use Toolforge::MixNMatch::Object::YearMonth;
  3         1769  
  3         2556  
10              
11             our $VERSION = 0.02;
12              
13             sub diff {
14 4     4 1 3680 my ($catalog1, $catalog2, $warn) = @_;
15              
16 4   50     25 $warn //= 0;
17              
18 4 50       12 if ($catalog1->type ne $catalog2->type) {
19 0         0 _warn('Different type of catalogs.', $warn);
20             }
21              
22 4 50       56 if ($catalog1->count != $catalog2->count) {
23 0         0 _warn('Count values of catalogs are different.', $warn);
24             }
25              
26 4         46 my ($new_cat, $old_cat) = _which_catalog_is_new($catalog1, $catalog2, $warn);
27              
28             # Diff of users.
29 4         7 my $users_ar = [];
30 4         6 foreach my $new_cat_user (@{$new_cat->users}) {
  4         9  
31 3         23 my $old_cat_user;
32 3         4 foreach my $user_iter (@{$old_cat->users}) {
  3         7  
33 1 50       9 if ($user_iter->username eq $new_cat_user->username) {
34              
35 1 50       13 if ($user_iter->uid ne $new_cat_user->uid) {
36 0         0 err 'Something wrong with uids in catalogs.';
37             }
38 1         12 $old_cat_user = $user_iter;
39 1         3 last;
40             }
41             }
42 3 100       21 my $count = defined $old_cat_user ?
43             ($new_cat_user->count - $old_cat_user->count)
44             : $new_cat_user->count;
45 3 50       22 if ($count) {
46 3         5 push @{$users_ar}, Toolforge::MixNMatch::Object::User->new(
  3         9  
47             'count' => $count,
48             'uid' => $new_cat_user->uid,
49             'username' => $new_cat_user->username,
50             );
51             }
52             }
53              
54             # Diff of dates.
55 4         198 my $year_months_ar = [];
56 4 0       8 foreach my $new_cat_year_month (sort { $a->year <=> $b->year || $a->month <=> $b->month }
  0         0  
57 4         9 @{$new_cat->year_months}) {
58              
59 0         0 my $old_cat_year_month;
60 0         0 foreach my $year_month_iter (@{$old_cat->year_months}) {
  0         0  
61 0 0 0     0 if ($year_month_iter->year eq $new_cat_year_month->year
62             && $year_month_iter->month eq $new_cat_year_month->month) {
63              
64 0         0 $old_cat_year_month = $year_month_iter;
65 0         0 last;
66             }
67             }
68 0 0       0 my $count = defined $old_cat_year_month ?
69             ($new_cat_year_month->count - $old_cat_year_month->count)
70             : $new_cat_year_month->count;
71 0 0       0 if ($count) {
72 0         0 push @{$year_months_ar}, Toolforge::MixNMatch::Object::YearMonth->new(
  0         0  
73             'year' => $new_cat_year_month->year,
74             'month' => $new_cat_year_month->month,
75             'count' => $count,
76             );
77             }
78             }
79              
80 4         44 my $catalog_diff = Toolforge::MixNMatch::Object::Catalog->new(
81             'count' => $new_cat->count,
82             'type' => $new_cat->type,
83             'users' => $users_ar,
84             'year_months' => $year_months_ar,
85             );
86              
87 4         352 return $catalog_diff;
88             }
89              
90             sub _compute_users_count {
91 8     8   12 my $catalog = shift;
92              
93 8         13 my $count = 0;
94 8         12 foreach my $user (@{$catalog->users}) {
  8         17  
95 4         44 $count += $user->count;
96             }
97              
98 8         68 return $count;
99             }
100              
101             sub _warn {
102 1     1   14 my ($mess, $warn) = @_;
103              
104 1 50       5 if ($warn) {
105 0         0 print "WARNING: $mess\n";
106             }
107              
108 1         2 return;
109             }
110              
111             sub _which_catalog_is_new {
112 4     4   10 my ($catalog1, $catalog2, $warn) = @_;
113              
114 4         6 my ($new_cat, $old_cat);
115              
116             # Different total counts.
117 4 50       9 if ($catalog1->count > $catalog2->count) {
    50          
118 0         0 $new_cat = $catalog1;
119 0         0 $old_cat = $catalog2;
120             } elsif ($catalog2->count > $catalog1->count) {
121 0         0 $new_cat = $catalog2;
122 0         0 $old_cat = $catalog1;
123              
124             # Total counts are same.
125             } else {
126 4         73 my $users_count1 = _compute_users_count($catalog1);
127 4         10 my $users_count2 = _compute_users_count($catalog2);
128 4 100       12 if ($users_count1 > $users_count2) {
    100          
129 1         2 $new_cat = $catalog1;
130 1         3 $old_cat = $catalog2;
131             } elsif ($users_count2 > $users_count1) {
132 2         4 $new_cat = $catalog2;
133 2         3 $old_cat = $catalog1;
134              
135             # All counts are same.
136             } else {
137 1         4 _warn('Catalogs are same in counts.', $warn);
138 1         2 $new_cat = $catalog2;
139 1         2 $old_cat = $catalog1;
140             }
141             }
142              
143 4         12 return ($new_cat, $old_cat);
144             }
145              
146             1;
147              
148             __END__
149              
150             =pod
151              
152             =encoding utf8
153              
154             =head1 NAME
155              
156             Toolforge::MixNMatch::Diff - Mix'n'match catalogs diff.
157              
158             =head1 SYNOPSIS
159              
160             use Toolforge::MixNMatch::Diff;
161              
162             my $diff_cat = Toolforge::MixNMatch::Diff::diff($cat1, $cat2, $warn);
163              
164             =head1 SUBRUTINES
165              
166             =head2 C<diff>
167              
168             my $diff_cat = Toolforge::MixNMatch::Diff::diff($cat1, $cat2, $warn);
169              
170             Creates diff between two catalogs.
171             C<$warn> is boolean variable which turn on/off warnings (default is off).
172              
173             Returns instance of Toolforge::MixNMatch::Object::Catalog.
174              
175             =head1 ERRORS
176              
177             diff():
178             Something wrong with uids in catalogs.
179              
180             =head1 EXAMPLE
181              
182             use strict;
183             use warnings;
184              
185             use Toolforge::MixNMatch::Diff;
186             use Toolforge::MixNMatch::Object::Catalog;
187             use Toolforge::MixNMatch::Object::User;
188             use Toolforge::MixNMatch::Object::YearMonth;
189             use Toolforge::MixNMatch::Print::Catalog;
190              
191             # Catalogs.
192             my $cat1 = Toolforge::MixNMatch::Object::Catalog->new(
193             'count' => 10,
194             'type' => 'Q5',
195             'users' => [
196             Toolforge::MixNMatch::Object::User->new(
197             'count' => 2,
198             'uid' => 1,
199             'username' => 'Skim',
200             ),
201             Toolforge::MixNMatch::Object::User->new(
202             'count' => 1,
203             'uid' => 2,
204             'username' => 'Foo',
205             ),
206             ],
207             'year_months' => [
208             Toolforge::MixNMatch::Object::YearMonth->new(
209             'count' => 3,
210             'month' => 9,
211             'year' => 2020,
212             ),
213             ],
214             );
215             my $cat2 = Toolforge::MixNMatch::Object::Catalog->new(
216             'count' => 10,
217             'type' => 'Q5',
218             'users' => [
219             Toolforge::MixNMatch::Object::User->new(
220             'count' => 3,
221             'uid' => 1,
222             'username' => 'Skim',
223             ),
224             Toolforge::MixNMatch::Object::User->new(
225             'count' => 2,
226             'uid' => 2,
227             'username' => 'Foo',
228             ),
229             ],
230             'year_months' => [
231             Toolforge::MixNMatch::Object::YearMonth->new(
232             'count' => 3,
233             'month' => 9,
234             'year' => 2020,
235             ),
236             Toolforge::MixNMatch::Object::YearMonth->new(
237             'count' => 2,
238             'month' => 10,
239             'year' => 2020,
240             ),
241             ],
242             );
243              
244             my $diff_cat = Toolforge::MixNMatch::Diff::diff($cat1, $cat2);
245              
246             # Print out.
247             print "Catalog #1:\n";
248             print Toolforge::MixNMatch::Print::Catalog::print($cat1)."\n\n";
249             print "Catalog #2:\n";
250             print Toolforge::MixNMatch::Print::Catalog::print($cat2)."\n\n";
251             print "Diff catalog:\n";
252             print Toolforge::MixNMatch::Print::Catalog::print($diff_cat)."\n";
253              
254             # Output:
255             # Catalog #1:
256             # Type: Q5
257             # Count: 10
258             # Year/months:
259             # 2020/9: 3
260             # Users:
261             # Skim (1): 2
262             # Foo (2): 1
263             #
264             # Catalog #2:
265             # Type: Q5
266             # Count: 10
267             # Year/months:
268             # 2020/9: 3
269             # 2020/10: 2
270             # Users:
271             # Skim (1): 3
272             # Foo (2): 2
273             #
274             # Diff catalog:
275             # Type: Q5
276             # Count: 10
277             # Year/months:
278             # 2020/10: 2
279             # Users:
280             # Foo (2): 1
281             # Skim (1): 1
282              
283             =head1 DEPENDENCIES
284              
285             L<Error::Pure>,
286             L<Toolforge::MixNMatch::Object::Catalog>,
287             L<Toolforge::MixNMatch::Object::User>,
288             L<Toolforge::MixNMatch::Object::YearMonth>.
289              
290             =head1 REPOSITORY
291              
292             L<https://github.com/michal-josef-spacek/Toolforge-MixNMatch-Diff>
293              
294             =head1 AUTHOR
295              
296             Michal Josef Špaček L<mailto:skim@cpan.org>
297              
298             L<http://skim.cz>
299              
300             =head1 LICENSE AND COPYRIGHT
301              
302             © Michal Josef Špaček 2020
303              
304             BSD 2-Clause License
305              
306             =head1 VERSION
307              
308             0.04
309              
310             =cut