File Coverage

blib/lib/RDF/DOAP/Lite.pm
Criterion Covered Total %
statement 21 163 12.8
branch 0 68 0.0
condition 0 6 0.0
subroutine 7 18 38.8
pod 5 11 45.4
total 33 266 12.4


line stmt bran cond sub pod time code
1 1     1   872 use 5.008004;
  1         3  
  1         47  
2 1     1   6 use strict;
  1         2  
  1         35  
3 1     1   15 use warnings;
  1         2  
  1         35  
4 1     1   1099 use utf8;
  1         10  
  1         4  
5              
6             package RDF::DOAP::Lite;
7              
8             our $AUTHORITY = 'cpan:TOBYINK';
9             our $VERSION = '0.002';
10              
11 1     1   1002 use CPAN::Meta 2.110320 qw();
  1         486830  
  1         33  
12 1     1   10 use Scalar::Util 1.24 qw( openhandle );
  1         22  
  1         256  
13              
14             # ============= helper functions =============
15              
16             sub parse_person
17             {
18 0 0   0 0   $_[0] =~ m{ \A \s*
19             (\S.+)
20             (?:
21             \s+ \((\w+)\)
22             )
23             (?:
24             \s+ <(?:mailto\:)?(.+)>
25             )
26             \s* \z }ix and return ($1, $2, $3);
27            
28 0 0         $_[0] =~ m{ \A \s*
29             (\S.+)
30             (?:
31             \s+ <(?:mailto\:)?(.+)>
32             )
33             \s* \z }ix and return ($1, undef, $2);
34            
35 0           return $_[0];
36             }
37              
38             {
39             my %TURTLE = ( "\t" => "\\t", "\n" => "\\n", "\r" => "\\r", "\"" => "\\\"", "\\" => "\\\\" );
40             sub turtle_literal
41             {
42 1     1   6 no warnings 'uninitialized';
  1         1  
  1         5237  
43 0     0 0   local $_ = $_[0];
44 0 0         return q[""] if $_ eq '';
45 0           s{([\t\n\r\"\\])}{$TURTLE{$1}}sg;
46 0           qq("$_");
47             }
48             }
49              
50             sub turtle_person
51             {
52 0     0 0   my ($name, $nick, $mbox) = parse_person @_;
53              
54 0 0 0       unless (defined $nick or defined $mbox)
55             {
56 0 0         return '[ a foaf:Person ]' unless defined $name;
57 0           return sprintf('[ a foaf:Person; rdfs:label %s ]', turtle_literal $name);
58             }
59              
60 0           my $person = '[ a foaf:Person';
61 0 0         $person .= sprintf('; foaf:name %s', turtle_literal $name) if defined $name;
62 0 0         $person .= sprintf('; foaf:nick %s', turtle_literal $nick) if defined $nick;
63 0 0         $person .= sprintf('; foaf:mbox <mailto:%s>', $mbox) if defined $mbox;
64 0           $person .= ' ]';
65             }
66              
67             {
68             my %XML = ('&' => '&amp;', '"' => '&quot;', '<' => '&lt;', '>' => '&gt;');
69             sub xml_literal
70             {
71 0     0 0   local $_ = shift;
72 0           s{([&"<>])}{$XML{$1}}sg;
73 0           return $_;
74             }
75             }
76              
77             sub xml_person
78             {
79 0     0 0   my ($name, $nick, $mbox) = parse_person @_;
80            
81 0 0 0       unless (defined $nick or defined $mbox)
82             {
83 0 0         return '<foaf:Person />' unless defined $name;
84 0           return sprintf('<foaf:Person rdfs:label="%s" />', xml_literal $name);
85             }
86            
87 0           my $person = "<foaf:Person>\n";
88 0 0         $person .= sprintf(" <foaf:name>%s</foaf:name>\n", xml_literal $name) if defined $name;
89 0 0         $person .= sprintf(" <foaf:nick>%s</foaf:nick>\n", xml_literal $nick) if defined $nick;
90 0 0         $person .= sprintf(" <foaf:mbox rdf:resource=\"mailto:%s\" />\n", xml_literal $mbox) if defined $mbox;
91 0           $person .= " </foaf:Person>";
92            
93 0           return $person;
94             }
95              
96             sub rdf_datetype
97             {
98 0 0   0 0   ($_[0] =~ m{ \A [0-9]{4} - [0-9]{2} - [0-9]{2} \z }x) ? 'date' : 'dateTime';
99             }
100              
101             # ============= class definition =============
102              
103 0 0   0 1   sub new { my $c = shift; bless { @_==1 ? %{$_[0]} : @_ }, $c }
  0            
  0            
104 0     0 1   sub meta { $_[0]{meta} }
105 0     0 1   sub changes { $_[0]{changes} }
106              
107             my %LICENSE = qw(
108             agpl_3 http://www.gnu.org/licenses/agpl-3.0.txt
109             apache_1_1 http://www.apache.org/licenses/LICENSE-1.1
110             apache_2_0 http://www.apache.org/licenses/LICENSE-2.0.txt
111             artistic_1 http://www.perlfoundation.org/artistic_license_1_0
112             artistic_2 http://www.perlfoundation.org/artistic_license_2_0
113             bsd http://www.opensource.org/licenses/bsd-license.php
114             freebsd http://www.freebsd.org/copyright/freebsd-license.html
115             gfdl_1_2 http://www.gnu.org/licenses/fdl-1.2.html
116             gfdl_1_3 http://www.gnu.org/licenses/fdl-1.3.html
117             gpl_1 http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt
118             gpl_2 http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
119             gpl_3 http://www.gnu.org/licenses/gpl-3.0.txt
120             lgpl_2_1 http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
121             lgpl_3_0 http://www.gnu.org/licenses/lgpl-3.0.txt
122             mit http://www.opensource.org/licenses/mit-license.php
123             mozilla_1_0 http://www.mozilla.org/MPL/MPL-1.0.txt
124             mozilla_1_1 http://www.mozilla.org/MPL/MPL-1.1.txt
125             openssl http://www.openssl.org/source/license.html
126             perl http://dev.perl.org/licenses/
127             perl_5 http://dev.perl.org/licenses/
128             qpl_1_0 http://trolltech.com/products/qt/licenses/licensing/qpl
129             ssleay http://h71000.www7.hp.com/doc/83final/BA554_90007/apcs02.html
130             sun http://www.openoffice.org/licenses/sissl_license.html
131             zlib http://www.zlib.net/zlib_license.html
132             );
133              
134             my %REPO = qw(
135             cvs CVS
136             git Git
137             hg Hg
138             svn SVN
139             );
140              
141             sub doap_ttl
142             {
143 0     0 1   my $self = shift;
144             my $fh = openhandle($_[0])
145             ? $_[0]
146 0 0         : do { open my $fh, '>', $_[0] or die("Could not open $_[0]: $!"); $fh };
  0 0          
  0            
147            
148 0           print {$fh} <<' HEADER', "\n";
  0            
149             @prefix : <http://usefulinc.com/ns/doap#>.
150             @prefix dc: <http://purl.org/dc/terms/>.
151             @prefix foaf: <http://xmlns.com/foaf/0.1/>.
152             @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
153             @prefix xsd: <http://www.w3.org/2001/XMLSchema#>.
154             HEADER
155            
156 0 0         my $meta = $self->meta or die("no meta!");
157 0           my $res = $meta->resources;
158 0 0         my $uri = $res->{X_identifier} ? "<$res->{X_identifier}>" : '[]';
159            
160 0           printf {$fh} "$uri\n";
  0            
161 0           printf {$fh} " a :Project;\n";
  0            
162 0           printf {$fh} " :name %s;\n", turtle_literal($_) for grep defined, $meta->name;
  0            
163 0           printf {$fh} " :shortdesc %s;\n", turtle_literal($_) for grep defined, $meta->abstract;
  0            
164 0           printf {$fh} " :description %s;\n", turtle_literal($_) for grep defined, $meta->description;
  0            
165 0           printf {$fh} " :category [ rdfs:label %s ];\n", turtle_literal($_) for grep defined, $meta->keywords;
  0            
166 0           printf {$fh} " :developer %s;\n", turtle_person($_) for grep defined, $meta->authors;
  0            
167 0 0         printf {$fh} " :helper %s;\n", turtle_person($_) for grep defined, @{ $meta->{x_contributors} || [] };
  0            
  0            
168 0 0         printf {$fh} " :license <%s>;\n", $_ for map { $LICENSE{$_} || () } $meta->licenses;
  0            
  0            
169 0           printf {$fh} " :homepage <%s>;\n", $_ for grep defined, $res->{homepage};
  0            
170 0           printf {$fh} " :bug-database <%s>;\n", $_ for grep defined, $res->{bugtracker}{web};
  0            
171 0 0         if (my $repo = $res->{repository})
172             {
173 0           printf {$fh} " :repository [\n";
  0            
174 0 0         printf {$fh} " a :%sRepository;\n", $_ for map { $REPO{$_} || '' } $repo->{type};
  0            
  0            
175 0           printf {$fh} " :browse <%s>;\n", $_ for grep defined, $repo->{web};
  0            
176 0           printf {$fh} " :location <%s>;\n", $_ for grep defined, $repo->{url};
  0            
177 0           printf {$fh} " ];\n";
  0            
178             }
179 0           for my $r (map $_->releases, grep defined, $self->changes)
180             {
181 0           $r->date
182 0           ? printf {$fh} " :release [ a :Version; :revision %s^^xsd:string; dc:issued %s^^xsd:%s ];\n", turtle_literal($r->version), turtle_literal($r->date), rdf_datetype($r->date)
183 0 0         : printf {$fh} " :release [ a :Version; :revision %s^^xsd:string ];\n", turtle_literal($r->version)
184             }
185 0           printf {$fh} " :programming-language %s.\n", turtle_literal("Perl");
  0            
186             }
187              
188             sub doap_xml
189             {
190 0     0 1   my $self = shift;
191             my $fh = openhandle($_[0])
192             ? $_[0]
193 0 0         : do { open my $fh, '>', $_[0] or die("Could not open $_[0]: $!"); $fh };
  0 0          
  0            
194            
195 0           print {$fh} <<' HEADER';
  0            
196             <?xml version="1.0" encoding="UTF-8" ?>
197             <Project
198             xmlns="http://usefulinc.com/ns/doap#"
199             xmlns:dc="http://purl.org/dc/terms/"
200             xmlns:foaf="http://xmlns.com/foaf/0.1/"
201             xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
202             xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
203             HEADER
204            
205 0 0         my $meta = $self->meta or die("no meta!");
206 0           my $res = $meta->resources;
207            
208 0 0         if ($res->{X_identifier})
209             {
210 0           printf {$fh} " rdf:about=\"%s\">\n", xml_literal($res->{X_identifier});
  0            
211             }
212             else
213             {
214 0           printf {$fh} " >\n";
  0            
215             }
216            
217 0           printf {$fh} " <name>%s</name>\n", xml_literal($_) for grep defined, $meta->name;
  0            
218 0           printf {$fh} " <shortdesc>%s</shortdesc>\n", xml_literal($_) for grep defined, $meta->abstract;
  0            
219 0           printf {$fh} " <description>%s</description>\n", xml_literal($_) for grep defined, $meta->description;
  0            
220 0           printf {$fh} " <category rdfs:label=\"%s\" />\n", xml_literal($_) for grep defined, $meta->keywords;
  0            
221 0           printf {$fh} " <developer>\n %s\n </developer>\n", xml_person($_) for grep defined, $meta->authors;
  0            
222 0 0         printf {$fh} " <helper>\n %s\n </helper>\n", xml_person($_) for grep defined, @{ $meta->{x_contributors} || [] };
  0            
  0            
223 0 0         printf {$fh} " <license rdf:resource=\"%s\" />\n", xml_literal($_) for map { $LICENSE{$_} || () } $meta->licenses;
  0            
  0            
224 0           printf {$fh} " <homepage rdf:resource=\"%s\" />\n", xml_literal($_) for grep defined, $res->{homepage};
  0            
225 0           printf {$fh} " <bug-database rdf:resource=\"%s\" />\n", xml_literal($_) for grep defined, $res->{bugtracker}{web};
  0            
226 0 0         if (my $repo = $res->{repository})
227             {
228 0           printf {$fh} " <repository>\n";
  0            
229 0 0         printf {$fh} " <%sRepository>\n", $_ for map { $REPO{$_} || '' } $repo->{type};
  0            
  0            
230 0           printf {$fh} " <browse rdf:resource=\"%s\" />\n", xml_literal($_) for grep defined, $repo->{web};
  0            
231 0           printf {$fh} " <location rdf:resource=\"%s\" />\n", xml_literal($_) for grep defined, $repo->{url};
  0            
232 0 0         printf {$fh} " </%sRepository>\n", $_ for map { $REPO{$_} || '' } $repo->{type};
  0            
  0            
233 0           printf {$fh} " </repository>\n";
  0            
234             }
235 0           for my $r (map $_->releases, grep defined, $self->changes)
236             {
237 0           $r->date
238 0           ? printf {$fh} " <release>\n <Version>\n <revision rdf:datatype=\"http://www.w3.org/2001/XMLSchema#string\">%s</revision>\n <dc:issued rdf:datatype=\"http://www.w3.org/2001/XMLSchema#%s\">%s</dc:issued>\n </Version>\n </release>\n", xml_literal($r->version), rdf_datetype($r->date), xml_literal($r->date)
239 0 0         : printf {$fh} " <release>\n <Version>\n <revision rdf:datatype=\"http://www.w3.org/2001/XMLSchema#string\">%s</revision>\n </Version>\n </release>\n", xml_literal($r->version)
240             }
241 0           printf {$fh} " <programming-language>%s</programming-language>\n", xml_literal("Perl");
  0            
242 0           printf {$fh} "</Project>\n";
  0            
243             }
244              
245             1;
246              
247             __END__
248              
249             =pod
250              
251             =encoding utf-8
252              
253             =head1 NAME
254              
255             RDF::DOAP::Lite - write DOAP data quickly and easily
256              
257             =head1 SYNOPSIS
258              
259             use CPAN::Changes;
260             use CPAN::Meta;
261             use RDF::DOAP::Lite;
262            
263             my $changes = CPAN::Changes->load('Changes');
264             my $meta = CPAN::Meta->load_file('META.json');
265             my $doap = RDF::DOAP::Lite->new(meta => $meta, changes => $changes);
266            
267             $doap->doap_ttl('doap.ttl');
268             $doap->doap_xml('doap.xml');
269              
270             =head1 DESCRIPTION
271              
272             This is a small companion module to L<RDF::DOAP>, enabling you to
273             output DOAP data easily from standard CPAN distribution files.
274              
275             =head2 The Straight DOAP
276              
277             So what is DOAP? This explanation is lifted from
278             L<Wikipedia|http://en.wikipedia.org/wiki/DOAP>.
279              
280             I<< DOAP (Description of a Project) is an RDF Schema and XML vocabulary
281             to describe software projects, in particular free and open source
282             software. >>
283              
284             I<< It was created and initially developed by Edd Dumbill to convey
285             semantic information associated with open source software projects. >>
286              
287             I<< It is currently used in the Mozilla Foundation's project page and
288             in several other software repositories, notably the Python Package
289             Index. >>
290              
291             =head2 Constructor
292              
293             =over
294              
295             =item C<< new(%attributes) >>
296              
297             Moose-style constructor (though this module does not use L<Moose>).
298              
299             =back
300              
301             =head2 Attributes
302              
303             =over
304              
305             =item C<< meta >>
306              
307             This is a required attribute; a L<CPAN::Meta> object.
308              
309             =item C<< changes >>
310              
311             This is an optional attribute; a L<CPAN::Changes> object.
312              
313             =back
314              
315             =head2 Methods
316              
317             =over
318              
319             =item C<< doap_ttl($file) >>
320              
321             Writes DOAP data in the Turtle serialization to the file. The file may
322             be provided as a filename (string) or a file handle.
323              
324             =item C<< doap_xml($file) >>
325              
326             Writes DOAP data in the RDF/XML serialization to the file. The file may
327             be provided as a filename (string) or a file handle.
328              
329             =back
330              
331             =head1 BUGS
332              
333             Please report any bugs to
334             L<http://rt.cpan.org/Dist/Display.html?Queue=RDF-DOAP-Lite>.
335              
336             =head1 SEE ALSO
337              
338             This module comes with a bundled command-line tool, L<cpan2doap>.
339              
340             For parsing DOAP data, see L<RDF::DOAP>.
341              
342             For general RDF processing, use L<RDF::Trine> and L<RDF::Query>.
343              
344             =head1 AUTHOR
345              
346             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
347              
348             =head1 COPYRIGHT AND LICENCE
349              
350             This software is copyright (c) 2013-2014 by Toby Inkster.
351              
352             This is free software; you can redistribute it and/or modify it under
353             the same terms as the Perl 5 programming language system itself.
354              
355             =head1 DISCLAIMER OF WARRANTIES
356              
357             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
358             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
359             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
360