File Coverage

blib/lib/Module/CoreList/More.pm
Criterion Covered Total %
statement 40 41 97.5
branch 10 14 71.4
condition 6 18 33.3
subroutine 11 11 100.0
pod 6 6 100.0
total 73 90 81.1


line stmt bran cond sub pod time code
1             package Module::CoreList::More;
2              
3             our $DATE = '2015-05-06'; # DATE
4             our $VERSION = '0.06'; # VERSION
5              
6 2     2   77199 use 5.010001;
  2         8  
  2         83  
7 2     2   8 use strict;
  2         2  
  2         51  
8 2     2   7 use warnings;
  2         1  
  2         47  
9              
10 2     2   5 use Module::CoreList;
  2         2  
  2         8  
11              
12             sub _firstidx {
13 22     22   27 my ($item, $ary) = @_;
14 22         61 for (0..@$ary-1) {
15 968 100       1121 return $_ if $ary->[$_] eq $item;
16             }
17 0         0 -1;
18             }
19              
20             # construct our own %delta from Module::CoreList's %delta. our version is a
21             # linear "linked list" (e.g. %delta{5.017} is a delta against %delta{5.016003}
22             # instead of %delta{5.016}. also, version numbers are cleaned (some versions in
23             # Module::CoreList has trailing whitespaces or alphas)
24              
25             # the same for our own %released (version numbers in keys are canonicalized)
26              
27             our %delta;
28             our %released;
29             my %rel_orig_formats;
30             {
31             # first let's only stored the canonical format of release versions
32             # (Module::Core stores "5.01" as well as "5.010000"), for less headache
33             # let's just store "5.010000"
34             my %releases;
35             for (sort keys %Module::CoreList::delta) {
36             my $canonical = sprintf "%.6f", $_;
37             next if $releases{$canonical};
38             $releases{$canonical} = $Module::CoreList::delta{$_};
39             $released{$canonical} = $Module::CoreList::released{$_};
40             $rel_orig_formats{$canonical} = $_;
41             }
42             my @releases = sort keys %releases;
43              
44             for my $i (0..@releases-1) {
45             my $reldelta = $releases{$releases[$i]};
46             my $delta_from = $reldelta->{delta_from};
47             my $changed = {};
48             my $removed = {};
49             # make sure that %delta will be linear "linked list" by release versions
50             if ($delta_from && $delta_from != $releases[$i-1]) {
51             $delta_from = sprintf "%.6f", $delta_from;
52             my $i0 = _firstidx($delta_from, \@releases);
53             #say "D: delta_from jumps from $delta_from (#$i0) -> $releases[$i] (#$i)";
54             # accumulate changes between delta at releases #($i0+1) and #($i-1),
55             # subtract them from delta at #($i)
56             my $changed_between = {};
57             my $removed_between = {};
58             for my $j ($i0+1 .. $i-1) {
59             my $reldelta_between = $releases{$releases[$j]};
60             for (keys %{$reldelta_between->{changed}}) {
61             $changed_between->{$_} = $reldelta_between->{changed}{$_};
62             delete $removed_between->{$_};
63             }
64             for (keys %{$reldelta_between->{removed}}) {
65             $removed_between->{$_} = $reldelta_between->{removed}{$_};
66             }
67             }
68             for (keys %{$reldelta->{changed}}) {
69             next if exists($changed_between->{$_}) &&
70             !defined($changed_between->{$_}) && !defined($reldelta->{changed}{$_}) || # both undef
71             defined ($changed_between->{$_}) && defined ($reldelta->{changed}{$_}) && $changed_between->{$_} eq $reldelta->{changed}{$_}; # both defined & equal
72             $changed->{$_} = $reldelta->{changed}{$_};
73             }
74             for (keys %{$reldelta->{removed}}) {
75             next if $removed_between->{$_};
76             $removed->{$_} = $reldelta->{removed}{$_};
77             }
78             } else {
79             $changed = { %{$reldelta->{changed}} };
80             $removed = { %{$reldelta->{removed} // {}} };
81             }
82              
83             # clean version numbers
84             for my $k (keys %$changed) {
85             for ($changed->{$k}) {
86             next unless defined;
87             s/\s+$//; # eliminate trailing space
88             # for "alpha" version, turn trailing junk such as letters to _
89             # plus a number based on the first junk char
90             s/([^.0-9_])[^.0-9_]*$/'_'.sprintf('%03d',ord $1)/e;
91             }
92             }
93             $delta{$releases[$i]} = {
94             changed => $changed,
95             removed => $removed,
96             };
97             }
98             }
99              
100             sub first_release {
101 4     4 1 1492 my $module = shift;
102 4 50 33     6 $module = shift if eval { $module->isa(__PACKAGE__) } && @_ > 0 && defined($_[0]) && $_[0] =~ /^\w/;
  4   33     68  
      33        
103              
104 4         6 my $ans;
105             RELEASE:
106 4         179 for my $rel (sort keys %delta) {
107 136         373 my $delta = $delta{$rel};
108              
109             # we haven't found the first release where module is included
110 136 100       312 if (exists $delta->{changed}{$module}) {
111 3         7 $ans = $rel_orig_formats{$rel};
112 3         6 last;
113             }
114             }
115              
116 4 50       50 return wantarray ? ($ans) : $ans;
117             }
118              
119             sub first_release_by_date {
120 4     4 1 2558 my $module = shift;
121 4 50 33     6 $module = shift if eval { $module->isa(__PACKAGE__) } && @_ > 0 && defined($_[0]) && $_[0] =~ /^\w/;
  4   33     63  
      33        
122              
123 4         7 my $ans;
124 2664         2081 RELEASE:
125 4         72 for my $rel (sort {$released{$a} cmp $released{$b}} keys %delta) {
126 136         876 my $delta = $delta{$rel};
127              
128             # we haven't found the first release where module is included
129 136 100       263 if (exists $delta->{changed}{$module}) {
130 3         6 $ans = $rel_orig_formats{$rel};
131 3         4 last;
132             }
133             }
134              
135 4 50       45 return wantarray ? ($ans) : $ans;
136             };
137              
138             # Use a private coderef to eliminate code duplication
139              
140             my $is_core = sub {
141             my $all = shift;
142             my $module = shift;
143             $module = shift if eval { $module->isa(__PACKAGE__) } && @_ > 0 && defined($_[0]) && $_[0] =~ /^\w/;
144             my ($module_version, $perl_version);
145              
146             $module_version = shift if @_ > 0;
147             $perl_version = @_ > 0 ? shift : $];
148              
149             my $mod_exists = 0;
150             my $mod_ver; # module version at each perl release, -1 means doesn't exist
151              
152             RELEASE:
153             for my $rel (sort keys %delta) {
154             last if $all && $rel > $perl_version; # this is the difference with is_still_core()
155              
156             my $reldelta = $delta{$rel};
157              
158             if ($rel > $perl_version) {
159             if ($reldelta->{removed}{$module}) {
160             $mod_exists = 0;
161             } else {
162             next;
163             }
164             }
165              
166             if (exists $reldelta->{changed}{$module}) {
167             $mod_exists = 1;
168             $mod_ver = $reldelta->{changed}{$module};
169             } elsif ($reldelta->{removed}{$module}) {
170             $mod_exists = 0;
171             }
172             }
173              
174             if ($mod_exists) {
175             if (defined $module_version) {
176             return 0 unless defined $mod_ver;
177             return version->parse($mod_ver) >= version->parse($module_version) ? 1:0;
178             }
179             return 1;
180             } else {
181             return 0;
182             }
183             };
184              
185              
186             my $list_core_modules = sub {
187             my $all = shift;
188             my $class = shift if @_ && eval { $_[0]->isa(__PACKAGE__) };
189             my $perl_version = @_ ? shift : $];
190              
191             my %added;
192             my %removed;
193              
194             RELEASE:
195             for my $rel (sort keys %delta) {
196             last if $all && $rel > $perl_version; # this is the difference with list_still_core_modules()
197              
198             my $delta = $delta{$rel};
199              
200             next unless $delta->{changed};
201             for my $mod (keys %{$delta->{changed}}) {
202             # module has been removed between perl_version..latest, skip
203             next if $removed{$mod};
204              
205             if (exists $added{$mod}) {
206             # module has been added in a previous version, update first
207             # version
208             $added{$mod} = $delta->{changed}{$mod} if $rel <= $perl_version;
209             } else {
210             # module is first added after perl_version, skip
211             next if $rel > $perl_version;
212              
213             $added{$mod} = $delta->{changed}{$mod};
214             }
215             }
216             next unless $delta->{removed};
217             for my $mod (keys %{$delta->{removed}}) {
218             delete $added{$mod};
219             # module has been removed between perl_version..latest, mark it
220             $removed{$mod}++ if $rel >= $perl_version;
221             }
222              
223             }
224             %added;
225             };
226              
227 858     858 1 1423362 sub is_core { $is_core->(1,@_) }
228              
229 858     858 1 180994 sub is_still_core { $is_core->(0,@_) }
230              
231 4     4 1 4285 sub list_core_modules { $list_core_modules->(1,@_) }
232              
233 3     3 1 1249 sub list_still_core_modules { $list_core_modules->(0,@_) }
234              
235             1;
236              
237             # ABSTRACT: More functions for Module::CoreList
238              
239             __END__