File Coverage

blib/lib/Parse/CPAN/Meta.pm
Criterion Covered Total %
statement 82 95 86.3
branch 30 60 50.0
condition 5 10 50.0
subroutine 17 17 100.0
pod 9 9 100.0
total 143 191 74.8


line stmt bran cond sub pod time code
1 22     22   467150 use 5.008001;
  22         90  
2 22     22   137 use strict;
  22         91  
  22         851  
3 22     22   118 use warnings;
  22         46  
  22         3403  
4             package Parse::CPAN::Meta;
5             # ABSTRACT: Parse META.yml and META.json CPAN metadata files
6              
7             our $VERSION = '2.150013';
8              
9 22     22   183 use Exporter;
  22         59  
  22         1551  
10 22     22   163 use Carp 'croak';
  22         46  
  22         11669  
11              
12             our @ISA = qw/Exporter/;
13             our @EXPORT_OK = qw/Load LoadFile/;
14              
15             sub load_file {
16 171     171 1 67205 my ($class, $filename) = @_;
17              
18 171         802 my $meta = _slurp($filename);
19              
20 171 100       1755 if ($filename =~ /\.ya?ml$/) {
    100          
21 103         840 return $class->load_yaml_string($meta);
22             }
23             elsif ($filename =~ /\.json$/) {
24 61         526 return $class->load_json_string($meta);
25             }
26             else {
27 7         100 $class->load_string($meta); # try to detect yaml/json
28             }
29             }
30              
31             sub load_string {
32 8     8 1 28 my ($class, $string) = @_;
33 8 100       91 if ( $string =~ /^---/ ) { # looks like YAML
    100          
34 1         4 return $class->load_yaml_string($string);
35             }
36             elsif ( $string =~ /^\s*\{/ ) { # looks like JSON
37 6         31 return $class->load_json_string($string);
38             }
39             else { # maybe doc-marker-free YAML
40 1         5 return $class->load_yaml_string($string);
41             }
42             }
43              
44             sub load_yaml_string {
45 121     121 1 3674 my ($class, $string) = @_;
46 121         452 my $backend = $class->yaml_backend();
47 22     22   189 my $data = eval { no strict 'refs'; &{"$backend\::Load"}($string) };
  22         54  
  22         30100  
  121         272  
  121         249  
  121         993  
48 121 100       382012 croak $@ if $@;
49 120   50     810 return $data || {}; # in case document was valid but empty
50             }
51              
52             sub load_json_string {
53 76     76 1 5394 my ($class, $string) = @_;
54 76         648 require Encode;
55             # load_json_string takes characters, decode_json expects bytes
56 76         570 my $encoded = Encode::encode('UTF-8', $string, Encode::PERLQQ());
57 76         4685 my $data = eval { $class->json_decoder()->can('decode_json')->($encoded) };
  76         423  
58 76 50       2975140 croak $@ if $@;
59 76   50     759 return $data || {};
60             }
61              
62             sub yaml_backend {
63 129 50 33 129 1 12342 if ($ENV{PERL_CORE} or not defined $ENV{PERL_YAML_BACKEND} ) {
64 129 50       456 _can_load( 'CPAN::Meta::YAML', 0.011 )
65             or croak "CPAN::Meta::YAML 0.011 is not available\n";
66 129         427 return "CPAN::Meta::YAML";
67             }
68             else {
69 0         0 my $backend = $ENV{PERL_YAML_BACKEND};
70 0 0       0 _can_load( $backend )
71             or croak "Could not load PERL_YAML_BACKEND '$backend'\n";
72 0 0       0 $backend->can("Load")
73             or croak "PERL_YAML_BACKEND '$backend' does not implement Load()\n";
74 0         0 return $backend;
75             }
76             }
77              
78             sub json_decoder {
79 77 50   77 1 2962 if ($ENV{PERL_CORE}) {
80 0 0       0 _can_load( 'JSON::PP' => 2.27300 )
81             or croak "JSON::PP 2.27300 is not available\n";
82 0         0 return 'JSON::PP';
83             }
84 77 100       363 if (my $decoder = $ENV{CPAN_META_JSON_DECODER}) {
85 2 50       30 _can_load( $decoder )
86             or croak "Could not load CPAN_META_JSON_DECODER '$decoder'\n";
87 2 50       21 $decoder->can('decode_json')
88             or croak "No decode_json sub provided by CPAN_META_JSON_DECODER '$decoder'\n";
89 2         10 return $decoder;
90             }
91 75         330 return $_[0]->json_backend;
92             }
93              
94             sub json_backend {
95 83 50   83 1 12904 if ($ENV{PERL_CORE}) {
96 0 0       0 _can_load( 'JSON::PP' => 2.27300 )
97             or croak "JSON::PP 2.27300 is not available\n";
98 0         0 return 'JSON::PP';
99             }
100 83 50       318 if (my $backend = $ENV{CPAN_META_JSON_BACKEND}) {
101 0 0       0 _can_load( $backend )
102             or croak "Could not load CPAN_META_JSON_BACKEND '$backend'\n";
103 0 0       0 $backend->can('new')
104             or croak "No constructor provided by CPAN_META_JSON_BACKEND '$backend'\n";
105 0         0 return $backend;
106             }
107 83 50 66     400 if (! $ENV{PERL_JSON_BACKEND} or $ENV{PERL_JSON_BACKEND} eq 'JSON::PP') {
108 83 50       348 _can_load( 'JSON::PP' => 2.27300 )
109             or croak "JSON::PP 2.27300 is not available\n";
110 83         1230 return 'JSON::PP';
111             }
112             else {
113 0 0       0 _can_load( 'JSON' => 2.5 )
114             or croak "JSON 2.5 is required for " .
115             "\$ENV{PERL_JSON_BACKEND} = '$ENV{PERL_JSON_BACKEND}'\n";
116 0         0 return "JSON";
117             }
118             }
119              
120             sub _slurp {
121 172     172   15169 require Encode;
122 172 50       444355 open my $fh, "<:raw", "$_[0]" ## no critic
123             or die "can't open $_[0] for reading: $!";
124 172         551 my $content = do { local $/; <$fh> };
  172         959  
  172         9646  
125 172         2285 $content = Encode::decode('UTF-8', $content, Encode::PERLQQ());
126 172         19069 return $content;
127             }
128              
129             sub _can_load {
130 214     214   639 my ($module, $version) = @_;
131 214         1295 (my $file = $module) =~ s{::}{/}g;
132 214         533 $file .= ".pm";
133 214 100       1311 return 1 if $INC{$file};
134 31 50       130 return 0 if exists $INC{$file}; # prior load failed
135 31 50       71 eval { require $file; 1 }
  31         25023  
  31         577847  
136             or return 0;
137 31 50       174 if ( defined $version ) {
138 31 50       76 eval { $module->VERSION($version); 1 }
  31         782  
  31         233  
139             or return 0;
140             }
141 31         154 return 1;
142             }
143              
144             # Kept for backwards compatibility only
145             # Create an object from a file
146             sub LoadFile ($) { ## no critic
147 1     1 1 4 return Load(_slurp(shift));
148             }
149              
150             # Parse a document from a string.
151             sub Load ($) { ## no critic
152 3     3 1 1100 require CPAN::Meta::YAML;
153 3         9704 my $object = eval { CPAN::Meta::YAML::Load(shift) };
  3         14  
154 3 50       1584 croak $@ if $@;
155 3         12 return $object;
156             }
157              
158             1;
159              
160             __END__