File Coverage

blib/lib/perlrocks.pm
Criterion Covered Total %
statement 30 71 42.2
branch 3 30 10.0
condition 0 12 0.0
subroutine 8 15 53.3
pod 0 4 0.0
total 41 132 31.0


line stmt bran cond sub pod time code
1             package perlrocks;
2 1     1   545 use strict;
  1         2  
  1         32  
3 1     1   6 use warnings;
  1         1  
  1         52  
4             our $VERSION = '0.02';
5              
6             =head1 NAME
7              
8             perlrocks - CPAN installation management
9              
10             =head1 VERSION
11              
12             0.02
13              
14             =head1 SYNOPSIS
15              
16             A command 'perlrocks' is installed to install cpan distributions:
17              
18             > perlrocks search Moose
19              
20             # Install multiple vesion of Moose
21             > perlrocks install -v 2.0009 Moose
22             > perlrocks install -v 1.13 Moose
23              
24             # Uninstall is possible
25             > rock uninstall Moose-1.14
26              
27             Modify your program a little bit to make it effective.
28              
29             # Put this in the very beginning of your program.
30             use perlrocks;
31              
32             # Using the latest version of intsalled Moose
33             use Moose;
34              
35             # Using exactly the version 2.0008 of Moose.
36             use Moose-2.0008
37              
38             =head1 DESCRIPTION
39              
40             This `perlrocks` things provides a mechanism to install multiple
41             versions of CPAN distributions, and use specific one in programs.
42              
43             In Perl5, the statement C or C means to load
44             Foo.pm and check if C<$Foo::VERSION> is at least 1.0. perlrocks alters
45             that behavior to load exactly Foo 1.0. If only higher versions of Foo
46             are found, it dies.
47              
48             In order to do that, `perlrocks` makes perl search libs in a different
49             way. Therefore, you need to install CPAN distributions differently.
50             To do so, you must use the C command:
51              
52             perlrocks install -v 2.0008 Moose
53             perlrocks install -v 2.0009 Moose
54              
55             Also notice here in the document, the term "distribution" is used to
56             refer to "the thing that gets uploaded to CPAN". Not "module", not
57             "package". For example, To install MooseX::Struct module, you'll need
58             to figure out the distribution name that provides it, in this case
59             it's "MooseX-Struct":
60              
61             perlrocks install MooseX-Struct
62              
63             Since one CPAN distribution can contain as many modules as needed, each
64             with different versions, it is ambiguous to state the command to install
65             "Foo::Bar" module, with the version number refering to the "Foo" distribution.
66              
67             Be aware of that C tweaks your C<%INC>, and it maybe
68             significantly slower. Use it at your own risk.
69              
70             =head1 METHODS
71              
72             =cut
73              
74 1     1   5 use File::Find ();
  1         10  
  1         14  
75 1     1   4 use File::Spec;
  1         2  
  1         57  
76 1     1   788 use File::ShareDir qw(dist_dir);
  1         7016  
  1         507  
77              
78             my $PERLROCKS_WITH_B_HOOKS_PARSER = 0;
79              
80             eval "require B::Hooks::Parser";
81             if (!$@) {
82             B::Hooks::Parser->import;
83             $PERLROCKS_WITH_B_HOOKS_PARSER = 1;
84             }
85              
86             # The one, and only, rock.
87             my $rock = bless {}, __PACKAGE__;
88              
89             sub home() {
90 0   0 0 0 0 return $rock->{home} ||= ($ENV{PERLROCKS_HOME} || dist_dir('perlrocks'));
      0        
91             }
92              
93             sub parse_use_line($) {
94 5     5 0 48 my ($code) = @_;
95 5         5 my ($name, $version, $auth);
96              
97             # Perl6 syntax
98 5         8 my $ident = '[a-zA-Z0-9]+';
99 5 100       88 if ($code =~ /^use\s+( (?:${ident}::)* ${ident} ):(?:auth\(Any\):)?(?:ver)?<(v?[\d+ '.']*\d+)>;$/x) {
100 3         22 return ($1, $2, undef);
101             }
102              
103             # Perl 5 syntax
104 2 50       12 if ($code =~ /^use\s+(\S+?)(?:-|\s+)([0-9._]+).*;$/) {
    0          
105 2         6 $name = $1;
106 2         6 $version = $2;
107             }
108             elsif ($code =~ /^use\s(\S+)\s*;$/) {
109 0         0 $name = $1;
110             }
111              
112 2         25 return ($name, $version, $auth);
113             }
114              
115             sub search {
116 0     0 0   my ($self, $file, $name, $version, $auth) = @_;
117              
118 0           my @candidates;
119             File::Find::find sub {
120 0 0   0     return unless $_ eq $file;
121 0 0 0       return unless (!$version || $version && $File::Find::name =~ /${name}-${version}\/lib/);
      0        
122 0           push @candidates, $File::Find::name;
123 0           }, $self->home;
124              
125 0 0         return unless @candidates;
126              
127 0 0         if ($version) {
128 0           my $version_matched;
129 0           for (@candidates) {
130 0 0         if (/\Q${name}-${version}\E\/lib/) {
131 0           return $_;
132             }
133             }
134              
135 0           die "ERROR: ${name}-${version} not found.\n";
136             }
137              
138             ## A version-less `use` statement.
139             ## Pick the highest versioned from candidates.
140              
141 0           @candidates = map {
142 0           $_->[0]
143             } sort {
144 0           $b->[1] <=> $a->[1];
145             } map {
146 0           my $v = 0;
147 0 0         if (/$name-([0-9\.]+)\/lib\//) {
148 0           $v = $1;
149             }
150              
151 0           [$_, $v];
152             } @candidates;
153              
154 0           return $candidates[0];
155             }
156              
157             {
158 1     1   8 no strict 'refs';
  1         2  
  1         25  
159 1     1   4 no warnings 'redefine';
  1         10  
  1         453  
160             sub get_current_line;
161              
162             if ($PERLROCKS_WITH_B_HOOKS_PARSER) {
163             *{__PACKAGE__ . '::get_current_line'} = sub {
164 0     0     B::Hooks::Parser::get_linestr();
165             }
166             }
167             else {
168             *{__PACKAGE__ . '::get_current_line'} = sub {
169             my (undef, $file, $lineno) = caller(2);
170             open my $fh, "<", $file;
171             my $line;
172             my $i = 0;
173             while ($i < $lineno) {
174             $line = <$fh>;
175             $i++;
176             }
177             close($fh);
178             return $line;
179             }
180             }
181             }
182              
183             ## It goes here when people says something like `use Foo;` or `use Foo-1.0;`
184             sub perlrocks::INC {
185 0     0 0   my ($self, $module_path) = @_;
186 0           my $code = get_current_line();
187 0 0         return unless $code;
188              
189 0           my ($name, $version, $auth) = parse_use_line($code);
190 0 0         return unless $name;
191              
192 0 0         if (my $path = $self->search($module_path, $name, $version, $auth)) {
193 0 0         open my $fh, $path or die "Can't open $path for input\n";
194 0           $INC{$module_path} = $path;
195 0           return $fh;
196             }
197             }
198              
199             ## It goes here when people says `use perlrock;`
200             sub import {
201 0     0     my ($class, $perlrocks_home) = @_;;
202 0 0         if ($PERLROCKS_WITH_B_HOOKS_PARSER) {
203 0           $rock->{__parser_hook} = B::Hooks::Parser::setup();
204             }
205              
206 0           $rock->{home} = $perlrocks_home;
207 0           unshift @INC, $rock;
208             }
209              
210             sub unimport {
211 0 0   0     if ($rock->{__parser_hook}) {
212 0           B::Hooks::Parser::teardown($rock->{__parser_hook});
213 0           delete $rock->{__parser_hook};
214             }
215             }
216              
217             1;
218              
219             =head1 SEE ALSO
220              
221             L, L
222              
223             =head1 AUTHOR
224              
225             Kang-min Liu C<< >>
226              
227             =head1 COPYRIGHT
228              
229             Copyright (c) 2011 Kang-min Liu C<< >>.
230              
231             =head1 LICENCE
232              
233             CC0 L
234              
235             =head1 CONTRIBUTORS
236              
237             See L
238              
239             =head1 DISCLAIMER OF WARRANTY
240              
241             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
242             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
243             OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
244             PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
245             EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
246             WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
247             ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
248             YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
249             NECESSARY SERVICING, REPAIR, OR CORRECTION.
250              
251             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
252             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
253             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
254             LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
255             OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
256             THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
257             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
258             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
259             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
260             SUCH DAMAGES.
261              
262             =cut