Commit | Line | Data |
---|---|---|
342e4710 | 1 | use strict; |
35df902d | 2 | package Parse::CPAN::Meta; |
342e4710 | 3 | # ABSTRACT: Parse META.yml and META.json CPAN metadata files |
7d7e3722 | 4 | our $VERSION = '1.4409'; # VERSION |
35df902d | 5 | |
35df902d DM |
6 | use Carp 'croak'; |
7 | ||
8 | # UTF Support? | |
9 | sub HAVE_UTF8 () { $] >= 5.007003 } | |
a4a5e2bf | 10 | sub IO_LAYER () { $] >= 5.008001 ? ":utf8" : "" } |
34d5bd5d | 11 | |
35df902d DM |
12 | BEGIN { |
13 | if ( HAVE_UTF8 ) { | |
14 | # The string eval helps hide this from Test::MinimumVersion | |
15 | eval "require utf8;"; | |
16 | die "Failed to load UTF-8 support" if $@; | |
17 | } | |
18 | ||
19 | # Class structure | |
20 | require 5.004; | |
21 | require Exporter; | |
35df902d DM |
22 | @Parse::CPAN::Meta::ISA = qw{ Exporter }; |
23 | @Parse::CPAN::Meta::EXPORT_OK = qw{ Load LoadFile }; | |
24 | } | |
25 | ||
34d5bd5d DG |
26 | sub load_file { |
27 | my ($class, $filename) = @_; | |
35df902d | 28 | |
34d5bd5d DG |
29 | if ($filename =~ /\.ya?ml$/) { |
30 | return $class->load_yaml_string(_slurp($filename)); | |
31 | } | |
35df902d | 32 | |
34d5bd5d DG |
33 | if ($filename =~ /\.json$/) { |
34 | return $class->load_json_string(_slurp($filename)); | |
35 | } | |
35df902d | 36 | |
34d5bd5d DG |
37 | croak("file type cannot be determined by filename"); |
38 | } | |
35df902d | 39 | |
34d5bd5d DG |
40 | sub load_yaml_string { |
41 | my ($class, $string) = @_; | |
42 | my $backend = $class->yaml_backend(); | |
43 | my $data = eval { no strict 'refs'; &{"$backend\::Load"}($string) }; | |
a4a5e2bf | 44 | if ( $@ ) { |
34d5bd5d DG |
45 | croak $backend->can('errstr') ? $backend->errstr : $@ |
46 | } | |
47 | return $data || {}; # in case document was valid but empty | |
48 | } | |
49 | ||
50 | sub load_json_string { | |
51 | my ($class, $string) = @_; | |
52 | return $class->json_backend()->new->decode($string); | |
53 | } | |
54 | ||
55 | sub yaml_backend { | |
56 | local $Module::Load::Conditional::CHECK_INC_HASH = 1; | |
57 | if (! defined $ENV{PERL_YAML_BACKEND} ) { | |
58 | _can_load( 'CPAN::Meta::YAML', 0.002 ) | |
59 | or croak "CPAN::Meta::YAML 0.002 is not available\n"; | |
60 | return "CPAN::Meta::YAML"; | |
61 | } | |
62 | else { | |
63 | my $backend = $ENV{PERL_YAML_BACKEND}; | |
64 | _can_load( $backend ) | |
65 | or croak "Could not load PERL_YAML_BACKEND '$backend'\n"; | |
66 | $backend->can("Load") | |
67 | or croak "PERL_YAML_BACKEND '$backend' does not implement Load()\n"; | |
68 | return $backend; | |
69 | } | |
70 | } | |
71 | ||
72 | sub json_backend { | |
73 | local $Module::Load::Conditional::CHECK_INC_HASH = 1; | |
74 | if (! $ENV{PERL_JSON_BACKEND} or $ENV{PERL_JSON_BACKEND} eq 'JSON::PP') { | |
75 | _can_load( 'JSON::PP' => 2.27103 ) | |
76 | or croak "JSON::PP 2.27103 is not available\n"; | |
77 | return 'JSON::PP'; | |
78 | } | |
79 | else { | |
80 | _can_load( 'JSON' => 2.5 ) | |
81 | or croak "JSON 2.5 is required for " . | |
82 | "\$ENV{PERL_JSON_BACKEND} = '$ENV{PERL_JSON_BACKEND}'\n"; | |
83 | return "JSON"; | |
84 | } | |
85 | } | |
35df902d | 86 | |
34d5bd5d DG |
87 | sub _slurp { |
88 | open my $fh, "<" . IO_LAYER, "$_[0]" | |
89 | or die "can't open $_[0] for reading: $!"; | |
90 | return do { local $/; <$fh> }; | |
91 | } | |
a4a5e2bf | 92 | |
34d5bd5d DG |
93 | sub _can_load { |
94 | my ($module, $version) = @_; | |
95 | (my $file = $module) =~ s{::}{/}g; | |
96 | $file .= ".pm"; | |
97 | return 1 if $INC{$file}; | |
98 | return 0 if exists $INC{$file}; # prior load failed | |
99 | eval { require $file; 1 } | |
100 | or return 0; | |
101 | if ( defined $version ) { | |
102 | eval { $module->VERSION($version); 1 } | |
103 | or return 0; | |
104 | } | |
105 | return 1; | |
106 | } | |
35df902d | 107 | |
34d5bd5d | 108 | # Kept for backwards compatibility only |
35df902d DM |
109 | # Create an object from a file |
110 | sub LoadFile ($) { | |
34d5bd5d | 111 | require CPAN::Meta::YAML; |
342e4710 | 112 | my $object = CPAN::Meta::YAML::LoadFile(shift) |
34d5bd5d | 113 | or die CPAN::Meta::YAML->errstr; |
342e4710 | 114 | return $object; |
35df902d DM |
115 | } |
116 | ||
117 | # Parse a document from a string. | |
35df902d | 118 | sub Load ($) { |
34d5bd5d | 119 | require CPAN::Meta::YAML; |
342e4710 | 120 | my $object = CPAN::Meta::YAML::Load(shift) |
34d5bd5d | 121 | or die CPAN::Meta::YAML->errstr; |
342e4710 | 122 | return $object; |
34d5bd5d | 123 | } |
35df902d | 124 | |
34d5bd5d | 125 | 1; |
35df902d | 126 | |
34d5bd5d | 127 | __END__ |
35df902d | 128 | |
34d5bd5d | 129 | =pod |
35df902d | 130 | |
342e4710 CBW |
131 | =encoding utf-8 |
132 | ||
34d5bd5d | 133 | =head1 NAME |
35df902d | 134 | |
34d5bd5d | 135 | Parse::CPAN::Meta - Parse META.yml and META.json CPAN metadata files |
35df902d | 136 | |
342e4710 CBW |
137 | =head1 VERSION |
138 | ||
7d7e3722 | 139 | version 1.4409 |
342e4710 | 140 | |
34d5bd5d | 141 | =head1 SYNOPSIS |
35df902d | 142 | |
34d5bd5d DG |
143 | ############################################# |
144 | # In your file | |
a4a5e2bf | 145 | |
34d5bd5d DG |
146 | --- |
147 | name: My-Distribution | |
148 | version: 1.23 | |
149 | resources: | |
150 | homepage: "http://example.com/dist/My-Distribution" | |
a4a5e2bf CBW |
151 | |
152 | ||
34d5bd5d DG |
153 | ############################################# |
154 | # In your program | |
a4a5e2bf | 155 | |
34d5bd5d | 156 | use Parse::CPAN::Meta; |
a4a5e2bf | 157 | |
34d5bd5d | 158 | my $distmeta = Parse::CPAN::Meta->load_file('META.yml'); |
a4a5e2bf | 159 | |
34d5bd5d DG |
160 | # Reading properties |
161 | my $name = $distmeta->{name}; | |
162 | my $version = $distmeta->{version}; | |
163 | my $homepage = $distmeta->{resources}{homepage}; | |
35df902d | 164 | |
34d5bd5d | 165 | =head1 DESCRIPTION |
35df902d | 166 | |
34d5bd5d DG |
167 | B<Parse::CPAN::Meta> is a parser for F<META.json> and F<META.yml> files, using |
168 | L<JSON::PP> and/or L<CPAN::Meta::YAML>. | |
35df902d | 169 | |
34d5bd5d DG |
170 | B<Parse::CPAN::Meta> provides three methods: C<load_file>, C<load_json_string>, |
171 | and C<load_yaml_string>. These will read and deserialize CPAN metafiles, and | |
172 | are described below in detail. | |
35df902d | 173 | |
34d5bd5d DG |
174 | B<Parse::CPAN::Meta> provides a legacy API of only two functions, |
175 | based on the YAML functions of the same name. Wherever possible, | |
176 | identical calling semantics are used. These may only be used with YAML sources. | |
35df902d | 177 | |
34d5bd5d | 178 | All error reporting is done with exceptions (die'ing). |
35df902d | 179 | |
34d5bd5d DG |
180 | Note that META files are expected to be in UTF-8 encoding, only. When |
181 | converted string data, it must first be decoded from UTF-8. | |
35df902d | 182 | |
342e4710 CBW |
183 | =for Pod::Coverage HAVE_UTF8 IO_LAYER |
184 | ||
34d5bd5d | 185 | =head1 METHODS |
35df902d | 186 | |
34d5bd5d | 187 | =head2 load_file |
35df902d | 188 | |
34d5bd5d | 189 | my $metadata_structure = Parse::CPAN::Meta->load_file('META.json'); |
35df902d | 190 | |
34d5bd5d | 191 | my $metadata_structure = Parse::CPAN::Meta->load_file('META.yml'); |
35df902d | 192 | |
34d5bd5d DG |
193 | This method will read the named file and deserialize it to a data structure, |
194 | determining whether it should be JSON or YAML based on the filename. On | |
195 | Perl 5.8.1 or later, the file will be read using the ":utf8" IO layer. | |
35df902d | 196 | |
34d5bd5d | 197 | =head2 load_yaml_string |
35df902d | 198 | |
34d5bd5d | 199 | my $metadata_structure = Parse::CPAN::Meta->load_yaml_string($yaml_string); |
35df902d | 200 | |
34d5bd5d DG |
201 | This method deserializes the given string of YAML and returns the first |
202 | document in it. (CPAN metadata files should always have only one document.) | |
203 | If the source was UTF-8 encoded, the string must be decoded before calling | |
204 | C<load_yaml_string>. | |
35df902d | 205 | |
34d5bd5d | 206 | =head2 load_json_string |
35df902d | 207 | |
34d5bd5d | 208 | my $metadata_structure = Parse::CPAN::Meta->load_json_string($json_string); |
35df902d | 209 | |
a4a5e2bf | 210 | This method deserializes the given string of JSON and the result. |
34d5bd5d DG |
211 | If the source was UTF-8 encoded, the string must be decoded before calling |
212 | C<load_json_string>. | |
35df902d | 213 | |
34d5bd5d | 214 | =head2 yaml_backend |
35df902d | 215 | |
34d5bd5d DG |
216 | my $backend = Parse::CPAN::Meta->yaml_backend; |
217 | ||
218 | Returns the module name of the YAML serializer. See L</ENVIRONMENT> | |
219 | for details. | |
220 | ||
221 | =head2 json_backend | |
222 | ||
223 | my $backend = Parse::CPAN::Meta->json_backend; | |
224 | ||
225 | Returns the module name of the JSON serializer. This will either | |
226 | be L<JSON::PP> or L<JSON>. Even if C<PERL_JSON_BACKEND> is set, | |
227 | this will return L<JSON> as further delegation is handled by | |
228 | the L<JSON> module. See L</ENVIRONMENT> for details. | |
35df902d DM |
229 | |
230 | =head1 FUNCTIONS | |
231 | ||
34d5bd5d DG |
232 | For maintenance clarity, no functions are exported. These functions are |
233 | available for backwards compatibility only and are best avoided in favor of | |
234 | C<load_file>. | |
35df902d DM |
235 | |
236 | =head2 Load | |
237 | ||
34d5bd5d | 238 | my @yaml = Parse::CPAN::Meta::Load( $string ); |
35df902d DM |
239 | |
240 | Parses a string containing a valid YAML stream into a list of Perl data | |
241 | structures. | |
242 | ||
243 | =head2 LoadFile | |
244 | ||
34d5bd5d | 245 | my @yaml = Parse::CPAN::Meta::LoadFile( 'META.yml' ); |
35df902d DM |
246 | |
247 | Reads the YAML stream from a file instead of a string. | |
248 | ||
34d5bd5d DG |
249 | =head1 ENVIRONMENT |
250 | ||
251 | =head2 PERL_JSON_BACKEND | |
252 | ||
253 | By default, L<JSON::PP> will be used for deserializing JSON data. If the | |
254 | C<PERL_JSON_BACKEND> environment variable exists, is true and is not | |
255 | "JSON::PP", then the L<JSON> module (version 2.5 or greater) will be loaded and | |
256 | used to interpret C<PERL_JSON_BACKEND>. If L<JSON> is not installed or is too | |
257 | old, an exception will be thrown. | |
258 | ||
259 | =head2 PERL_YAML_BACKEND | |
260 | ||
261 | By default, L<CPAN::Meta::YAML> will be used for deserializing YAML data. If | |
342e4710 | 262 | the C<PERL_YAML_BACKEND> environment variable is defined, then it is interpreted |
34d5bd5d DG |
263 | as a module to use for deserialization. The given module must be installed, |
264 | must load correctly and must implement the C<Load()> function or an exception | |
265 | will be thrown. | |
266 | ||
342e4710 CBW |
267 | =for :stopwords cpan testmatrix url annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan |
268 | ||
35df902d DM |
269 | =head1 SUPPORT |
270 | ||
342e4710 CBW |
271 | =head2 Bugs / Feature Requests |
272 | ||
273 | Please report any bugs or feature requests through the issue tracker | |
545c8cda | 274 | at L<http://rt.cpan.org/Public/Dist/Display.html?Name=Parse-CPAN-Meta>. |
342e4710 CBW |
275 | You will be notified automatically of any progress on your issue. |
276 | ||
277 | =head2 Source Code | |
278 | ||
279 | This is open source software. The code repository is available for | |
280 | public review and contribution under the terms of the license. | |
281 | ||
545c8cda | 282 | L<https://github.com/Perl-Toolchain-Gang/Parse-CPAN-Meta> |
35df902d | 283 | |
545c8cda | 284 | git clone https://github.com/Perl-Toolchain-Gang/Parse-CPAN-Meta.git |
35df902d | 285 | |
545c8cda SH |
286 | =head1 AUTHORS |
287 | ||
288 | =over 4 | |
289 | ||
290 | =item * | |
35df902d | 291 | |
342e4710 CBW |
292 | Adam Kennedy <adamk@cpan.org> |
293 | ||
545c8cda SH |
294 | =item * |
295 | ||
296 | David Golden <dagolden@cpan.org> | |
297 | ||
298 | =back | |
299 | ||
342e4710 CBW |
300 | =head1 CONTRIBUTORS |
301 | ||
302 | =over 4 | |
303 | ||
304 | =item * | |
305 | ||
545c8cda | 306 | Joshua ben Jore <jjore@cpan.org> |
342e4710 CBW |
307 | |
308 | =item * | |
309 | ||
545c8cda | 310 | Neil Bowers <neil@bowers.com> |
342e4710 CBW |
311 | |
312 | =item * | |
313 | ||
7d7e3722 | 314 | Ricardo Signes <rjbs@cpan.org> |
342e4710 CBW |
315 | |
316 | =item * | |
317 | ||
7d7e3722 | 318 | Steffen Mueller <smueller@cpan.org> |
35df902d | 319 | |
342e4710 | 320 | =back |
35df902d | 321 | |
342e4710 | 322 | =head1 COPYRIGHT AND LICENSE |
35df902d | 323 | |
342e4710 | 324 | This software is copyright (c) 2013 by Adam Kennedy and Contributors. |
35df902d | 325 | |
342e4710 CBW |
326 | This is free software; you can redistribute it and/or modify it under |
327 | the same terms as the Perl 5 programming language system itself. | |
35df902d DM |
328 | |
329 | =cut |