MetaCPAN-Client-2.023000/0000755000175000017500000000000013232713623014032 5ustar mickeymickeyMetaCPAN-Client-2.023000/MANIFEST0000644000175000017500000000364013232713623015166 0ustar mickeymickey# This file was automatically generated by Dist::Zilla::Plugin::Manifest v6.008. Changes LICENSE MANIFEST MANIFEST.SKIP META.json META.yml Makefile.PL README cpanfile dist.ini examples/agg.pl examples/author-country.pl examples/author.pl examples/author_releases.pl examples/authors_blogs.pl examples/autocomplete.pl examples/autocomplete_suggest.pl examples/changes.pl examples/complex-either-and.pl examples/complex-either-not.pl examples/complex-nested-either-and.pl examples/complex.pl examples/contributors.pl examples/distribution.pl examples/download_url.pl examples/es_filter.pl examples/fields-filter.pl examples/metacpan_url.pl examples/mirror.pl examples/module.pl examples/package.pl examples/permission.pl examples/pod.pl examples/rating.pl examples/recent.pl examples/recent_today.pl examples/release.pl examples/rev_deps-recursive.pl examples/rev_deps.pl examples/totals.pl lib/MetaCPAN/Client.pm lib/MetaCPAN/Client/Author.pm lib/MetaCPAN/Client/Distribution.pm lib/MetaCPAN/Client/DownloadURL.pm lib/MetaCPAN/Client/Favorite.pm lib/MetaCPAN/Client/File.pm lib/MetaCPAN/Client/Mirror.pm lib/MetaCPAN/Client/Module.pm lib/MetaCPAN/Client/Package.pm lib/MetaCPAN/Client/Permission.pm lib/MetaCPAN/Client/Pod.pm lib/MetaCPAN/Client/Rating.pm lib/MetaCPAN/Client/Release.pm lib/MetaCPAN/Client/Request.pm lib/MetaCPAN/Client/ResultSet.pm lib/MetaCPAN/Client/Role/Entity.pm lib/MetaCPAN/Client/Role/HasUA.pm lib/MetaCPAN/Client/Scroll.pm lib/MetaCPAN/Client/Types.pm t/00-report-prereqs.dd t/00-report-prereqs.t t/api/_get.t t/api/_get_or_search.t t/api/_search.t t/api/author.t t/api/distribution.t t/api/download_url.t t/api/favorite.t t/api/file.t t/api/module.t t/api/package.t t/api/permission.t t/api/pod.t t/api/rating.t t/api/release.t t/api/reverse-dependencies.t t/entity.t t/lib/Functions.pm t/request.t t/result_custom.t t/resultset.t t/scroll.t t/ua_trap.t xt/author/00-compile.t xt/author/pod-coverage.t xt/author/pod-syntax.t MetaCPAN-Client-2.023000/xt/0000755000175000017500000000000013232713623014465 5ustar mickeymickeyMetaCPAN-Client-2.023000/xt/author/0000755000175000017500000000000013232713623015767 5ustar mickeymickeyMetaCPAN-Client-2.023000/xt/author/pod-coverage.t0000644000175000017500000000033413232713623020527 0ustar mickeymickey#!perl # This file was automatically generated by Dist::Zilla::Plugin::PodCoverageTests. use Test::Pod::Coverage 1.08; use Pod::Coverage::TrustPod; all_pod_coverage_ok({ coverage_class => 'Pod::Coverage::TrustPod' }); MetaCPAN-Client-2.023000/xt/author/00-compile.t0000644000175000017500000000342013232713623020020 0ustar mickeymickeyuse 5.006; use strict; use warnings; # this test was generated with Dist::Zilla::Plugin::Test::Compile 2.054 use Test::More; plan tests => 20; my @module_files = ( 'MetaCPAN/Client.pm', 'MetaCPAN/Client/Author.pm', 'MetaCPAN/Client/Distribution.pm', 'MetaCPAN/Client/DownloadURL.pm', 'MetaCPAN/Client/Favorite.pm', 'MetaCPAN/Client/File.pm', 'MetaCPAN/Client/Mirror.pm', 'MetaCPAN/Client/Module.pm', 'MetaCPAN/Client/Package.pm', 'MetaCPAN/Client/Permission.pm', 'MetaCPAN/Client/Pod.pm', 'MetaCPAN/Client/Rating.pm', 'MetaCPAN/Client/Release.pm', 'MetaCPAN/Client/Request.pm', 'MetaCPAN/Client/ResultSet.pm', 'MetaCPAN/Client/Role/Entity.pm', 'MetaCPAN/Client/Role/HasUA.pm', 'MetaCPAN/Client/Scroll.pm', 'MetaCPAN/Client/Types.pm' ); # no fake home requested my $inc_switch = -d 'blib' ? '-Mblib' : '-Ilib'; use File::Spec; use IPC::Open3; use IO::Handle; open my $stdin, '<', File::Spec->devnull or die "can't open devnull: $!"; my @warnings; for my $lib (@module_files) { # see L my $stderr = IO::Handle->new; my $pid = open3($stdin, '>&STDERR', $stderr, $^X, $inc_switch, '-e', "require q[$lib]"); binmode $stderr, ':crlf' if $^O eq 'MSWin32'; my @_warnings = <$stderr>; waitpid($pid, 0); is($?, 0, "$lib loaded ok"); shift @_warnings if @_warnings and $_warnings[0] =~ /^Using .*\bblib/ and not eval { require blib; blib->VERSION('1.01') }; if (@_warnings) { warn @_warnings; push @warnings, @_warnings; } } is(scalar(@warnings), 0, 'no warnings found') or diag 'got warnings: ', ( Test::More->can('explain') ? Test::More::explain(\@warnings) : join("\n", '', @warnings) ); MetaCPAN-Client-2.023000/xt/author/pod-syntax.t0000644000175000017500000000025213232713623020261 0ustar mickeymickey#!perl # This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests. use strict; use warnings; use Test::More; use Test::Pod 1.41; all_pod_files_ok(); MetaCPAN-Client-2.023000/examples/0000755000175000017500000000000013232713623015650 5ustar mickeymickeyMetaCPAN-Client-2.023000/examples/author-country.pl0000644000175000017500000000056713232713623021220 0ustar mickeymickey # examples/author-country.pl use strict; use warnings; use Data::Printer; use MetaCPAN::Client; my @countries = qw; my %cc2authors; for my $cc ( @countries ) { my $authors = MetaCPAN::Client->new->author({ country => $cc }); $cc2authors{$cc} = $authors->total; } p %cc2authors; MetaCPAN-Client-2.023000/examples/agg.pl0000644000175000017500000000060713232713623016746 0ustar mickeymickey # examples/agg.pl use strict; use warnings; use Data::Printer; use MetaCPAN::Client; my $author = MetaCPAN::Client->new()->all( 'authors', { aggregations => { aggs => { terms => { field => "country" } } } } ); p $author->aggregations; MetaCPAN-Client-2.023000/examples/pod.pl0000644000175000017500000000021113232713623016761 0ustar mickeymickey # examples/pod.pl use strict; use warnings; use MetaCPAN::Client; my $pod = MetaCPAN::Client->new->pod('Moo'); print $pod->html; MetaCPAN-Client-2.023000/examples/complex-either-not.pl0000644000175000017500000000064613232713623021736 0ustar mickeymickey # examples/complex-either-not.pl use strict; use warnings; use Data::Printer; use MetaCPAN::Client; my $authors = MetaCPAN::Client->new->author({ either => [ { name => 'Dave *' }, { name => 'David *' }, ], not => [ { name => 'Dave C*' }, { name => 'David M*' }, ] }); print "\n"; my %out = ( TOTAL => $authors->total ); p %out; MetaCPAN-Client-2.023000/examples/distribution.pl0000644000175000017500000000043713232713623020730 0ustar mickeymickey # examples/distribution.pl use strict; use warnings; use Data::Printer; use MetaCPAN::Client; my $mcpan = MetaCPAN::Client->new(); my $dist = $mcpan->distribution('Moose'); my %output = ( NAME => $dist->name, BUGS => $dist->bugs, RIVER => $dist->river, ); p %output; MetaCPAN-Client-2.023000/examples/metacpan_url.pl0000644000175000017500000000120113232713623020651 0ustar mickeymickeyuse strict; use warnings; use MetaCPAN::Client; my $mcpan = MetaCPAN::Client->new(); my $auth = $mcpan->author('HAARG'); my $mod = $mcpan->module('Moo'); my $file = $mcpan->file('HAARG/Moo-2.003001/lib/Moo.pm'); my $dist = $mcpan->distribution('Moo'); my $rel = $mcpan->release({ all => [ { distribution => 'Moo' }, { version => '2.002005' }, ] }); printf "AUTHOR : %s\n", $auth->metacpan_url; printf "RELEASE : %s\n", $rel->next->metacpan_url; printf "MODULE : %s\n", $mod->metacpan_url; printf "FILE : %s\n", $file->metacpan_url; printf "DISTRIBUTION : %s\n", $dist->metacpan_url; 1; MetaCPAN-Client-2.023000/examples/recent.pl0000644000175000017500000000054113232713623017465 0ustar mickeymickey # examples/recent.pl use strict; use warnings; use Data::Printer; use MetaCPAN::Client; my $recent = MetaCPAN::Client->new->recent(3); while ( my $rel = $recent->next ) { my %output = ( NAME => $rel->name, AUTHOR => $rel->author, DATE => $rel->date, VERSION => $rel->version, ); p %output; } MetaCPAN-Client-2.023000/examples/recent_today.pl0000644000175000017500000000052013232713623020662 0ustar mickeymickeyuse strict; use warnings; use Data::Printer; use MetaCPAN::Client; my $recent = MetaCPAN::Client->new->recent('today'); while ( my $rel = $recent->next ) { my %output = ( NAME => $rel->name, AUTHOR => $rel->author, DATE => $rel->date, VERSION => $rel->version, ); p %output; } MetaCPAN-Client-2.023000/examples/changes.pl0000644000175000017500000000025513232713623017617 0ustar mickeymickeyuse strict; use warnings; use MetaCPAN::Client; my $dist = shift || 'Moose'; my $mcpan = MetaCPAN::Client->new(); my $rel = $mcpan->release($dist); print $rel->changes; MetaCPAN-Client-2.023000/examples/authors_blogs.pl0000644000175000017500000000100413232713623021053 0ustar mickeymickeyuse strict; use warnings; use MetaCPAN::Client; use Ref::Util qw< is_arrayref >; my $mcpan = MetaCPAN::Client->new; my $all_authors = $mcpan->all('authors'); AUTHOR: while ( my $author = $all_authors->next ) { BLOG: for my $blog ( @{ $author->blog || [] } ) { $blog and exists $blog->{url} or next BLOG; my $url = $blog->{url}; my $blogs_csv = is_arrayref($url) ? join q{,} => @$url : $url; printf "%-10s: %s\n", $author->pauseid, $blogs_csv; } } MetaCPAN-Client-2.023000/examples/fields-filter.pl0000644000175000017500000000035013232713623020734 0ustar mickeymickey # examples/fields-filter.pl use strict; use warnings; use DDP; use MetaCPAN::Client; my $module = MetaCPAN::Client->new->module('Moose', { fields => [ qw/ author version / ] }); p $module; MetaCPAN-Client-2.023000/examples/contributors.pl0000644000175000017500000000045713232713623020750 0ustar mickeymickeyuse strict; use warnings; use MetaCPAN::Client; use Data::Printer; my $mcpan = MetaCPAN::Client->new(); my $release = $mcpan->release({ all => [ { distribution => 'Moose' }, { version => '2.2005' }, ] })->next; my $contributors = $release->contributors; p $contributors; 1; MetaCPAN-Client-2.023000/examples/permission.pl0000644000175000017500000000045213232713623020376 0ustar mickeymickey# examples/permission.pl use strict; use warnings; use Data::Printer; use MetaCPAN::Client; my $mcpan = MetaCPAN::Client->new(); my $perm = $mcpan->permission('MooseX::Types'); p $perm; 1; __END__ Alternatively: my $module = $mcpan->module('MooseX::Types'); my $perm = $module->permission; MetaCPAN-Client-2.023000/examples/author.pl0000644000175000017500000000064313232713623017512 0ustar mickeymickey # examples/author.pl use strict; use warnings; use Data::Printer; use MetaCPAN::Client; my $author = MetaCPAN::Client->new()->author('XSAWYERX'); my %output = ( NAME => $author->name, EMAILS => $author->email, COUNTRY => $author->country, CITY => $author->city, PROFILE => $author->profile, LINKS => $author->links, RELEASE_COUNTS => $author->release_count, ); p %output; MetaCPAN-Client-2.023000/examples/rating.pl0000644000175000017500000000026213232713623017471 0ustar mickeymickey # examples/rating.pl use strict; use warnings; use DDP; use MetaCPAN::Client; my $rating = MetaCPAN::Client->new->rating({ distribution => "Moose" }); p $rating->next; MetaCPAN-Client-2.023000/examples/rev_deps-recursive.pl0000644000175000017500000000130713232713623022022 0ustar mickeymickey # examples/rev_deps-recursive.pl use strict; use warnings; use Term::ANSIColor; use MetaCPAN::Client; $|=1; my $dist = shift || 'Hijk'; my $mcpan = MetaCPAN::Client->new; print "\n\n", colored( "* $dist", 'green' ), "\n"; dig( $dist, 0 ); sub dig { my $dist = shift; my $level = shift; my $res = $mcpan->reverse_dependencies($dist); while ( my $item = $res->next ) { if ( $level ) { printf "%s%s\n", colored( '....' x $level, 'yellow' ), $item->distribution; } else { printf "\n>> %s\n", colored( $item->distribution, 'blue' ); } dig( $item->distribution, $level + 1 ); } } MetaCPAN-Client-2.023000/examples/totals.pl0000644000175000017500000000077613232713623017525 0ustar mickeymickeyuse strict; use warnings; use Data::Printer; use MetaCPAN::Client; my $mcpan = MetaCPAN::Client->new; my $all_authors = $mcpan->all('authors'); my $all_dists = $mcpan->all('distributions'); my $all_modules = $mcpan->all('modules'); my $all_releases = $mcpan->all('releases'); print "totals:\n"; printf "authors : %d\n", $all_authors->total; printf "distributions : %d\n", $all_dists->total; printf "modules : %d\n", $all_modules->total; printf "releases : %d\n", $all_releases->total; MetaCPAN-Client-2.023000/examples/complex-nested-either-and.pl0000644000175000017500000000102713232713623023152 0ustar mickeymickey # examples/complex-nested-either-and.pl use strict; use warnings; use Data::Printer; use MetaCPAN::Client; my $authors = MetaCPAN::Client->new->author({ either => [ { all => [ { name => 'Dave *' }, { email => '*gmail.com' } ] }, { all => [ { name => 'Sam *' }, { email => '*cpan.org' } ] }, ], }); my %output = ( TOTAL => $authors->total, NAMES => [ map { $authors->next->name } 0 .. 9 ], ); p %output; MetaCPAN-Client-2.023000/examples/es_filter.pl0000644000175000017500000000131313232713623020157 0ustar mickeymickeyuse strict; use warnings; use MetaCPAN::Client; # use raw ES filter on a { match_all => {} } query # find 'latest' status releases with at least 700 failing tests # which consist at least 50% of their overall number of tests. my $release = MetaCPAN::Client->new->all( 'releases', { es_filter => { and => [ { range => { 'tests.fail' => { gte => 700 } } }, { term => { 'status' => 'latest' } } ] }, } ); while ( my $r = $release->next ) { my $fail = $r->tests->{fail}; my $all = 0; $all += $_ for @{ $r->tests }{qw/pass fail na unknown/}; ($fail / $all) >= 0.5 and printf "%4d/%4d: %s\n", $fail, $all, $r->name; } MetaCPAN-Client-2.023000/examples/package.pl0000644000175000017500000000044113232713623017577 0ustar mickeymickey# examples/package.pl use strict; use warnings; use Data::Printer; use MetaCPAN::Client; my $mcpan = MetaCPAN::Client->new(); my $pack = $mcpan->package('MooseX::Types'); p $pack; 1; __END__ Alternatively: my $module = $mcpan->module('MooseX::Types'); my $pack = $module->package; MetaCPAN-Client-2.023000/examples/complex.pl0000644000175000017500000000055513232713623017661 0ustar mickeymickey # examples/complex.pl use strict; use warnings; use Data::Printer; use MetaCPAN::Client; my $authors = MetaCPAN::Client->new->author({ either => [ { name => 'Dave *' }, { name => 'David *' }, ] }); my %output = ( TOTAL => $authors->total, NAMES => [ map { $authors->next->name } 0 .. 9 ], ); p %output; MetaCPAN-Client-2.023000/examples/rev_deps.pl0000644000175000017500000000062413232713623020016 0ustar mickeymickey # examples/rev_deps.pl use strict; use warnings; use Data::Printer; use MetaCPAN::Client; my $module = shift || 'Hijk'; my $deps = MetaCPAN::Client->new->rev_deps($module); my @output; while ( my $rel = $deps->next ) { push @output => { name => $rel->name, author => $rel->author, }; } print "\n"; my $title = "Reverse dependencies for 'Hijk':"; p $title; p @output; MetaCPAN-Client-2.023000/examples/author_releases.pl0000644000175000017500000000040713232713623021373 0ustar mickeymickeyuse strict; use warnings; use Data::Printer; use MetaCPAN::Client; my $mcpan = MetaCPAN::Client->new; my $author = $mcpan->author('XSAWYERX'); my $releases = $author->releases; p $releases->total; while ( my $rel = $releases->next ) { p $rel->name; } MetaCPAN-Client-2.023000/examples/mirror.pl0000644000175000017500000000025113232713623017515 0ustar mickeymickey # examples/mirror.pl use strict; use warnings; use Data::Printer; use MetaCPAN::Client; my $mirrors = MetaCPAN::Client->new->mirror('eutelia.it'); p $mirrors; MetaCPAN-Client-2.023000/examples/autocomplete_suggest.pl0000644000175000017500000000027613232713623022454 0ustar mickeymickey # examples/autocomplete.pl use strict; use warnings; use Data::Printer; use MetaCPAN::Client; my $mcpan = MetaCPAN::Client->new(); my $ac = $mcpan->autocomplete_suggest("Moos"); p $ac; MetaCPAN-Client-2.023000/examples/autocomplete.pl0000644000175000017500000000026613232713623020712 0ustar mickeymickey # examples/autocomplete.pl use strict; use warnings; use Data::Printer; use MetaCPAN::Client; my $mcpan = MetaCPAN::Client->new(); my $ac = $mcpan->autocomplete("Danc"); p $ac; MetaCPAN-Client-2.023000/examples/release.pl0000644000175000017500000000051113232713623017622 0ustar mickeymickeyuse strict; use warnings; use Data::Printer; use MetaCPAN::Client; my $release = MetaCPAN::Client->new->release('Devel-NYTProf'); my %output = ( AUTHOR => $release->author, DATE => $release->date, STATUS => $release->status, VERSION => $release->version, TESTS => $release->tests, ); p %output; MetaCPAN-Client-2.023000/examples/download_url.pl0000644000175000017500000000060013232713623020672 0ustar mickeymickey # examples/download_url.pl use strict; use warnings; use DDP; use MetaCPAN::Client; my $mcpan = MetaCPAN::Client->new(); my $download_url = $mcpan->download_url('Moose'); my %output = ( VERSION => $download_url->version, STATUS => $download_url->status, DATE => $download_url->date, DOWNLOAD_URL => $download_url->download_url, ); p %output; MetaCPAN-Client-2.023000/examples/complex-either-and.pl0000644000175000017500000000064313232713623021675 0ustar mickeymickey # examples/complex-either-and.pl use strict; use warnings; use Data::Printer; use MetaCPAN::Client; my $authors = MetaCPAN::Client->new->author({ either => [ { name => 'Dave *' }, { name => 'David *' }, ], all => { email => '*gmail.com' }, }); my %output = ( TOTAL => $authors->total, NAMES => [ map { $authors->next->name } 0 .. 9 ], ); p %output; MetaCPAN-Client-2.023000/examples/module.pl0000644000175000017500000000061013232713623017467 0ustar mickeymickey # examples/module.pl use strict; use warnings; use DDP; use MetaCPAN::Client; my $module = MetaCPAN::Client->new->module('Moo'); my %output = ( NAME => $module->name, ABSTRACT => $module->abstract, DESCRIPTION => $module->description, RELEASE => $module->release, AUTHOR => $module->author, VERSION => $module->version, ); p %output; MetaCPAN-Client-2.023000/MANIFEST.SKIP0000644000175000017500000000005113232713623015724 0ustar mickeymickeycpanfile.snapshot local MetaCPAN-Client* MetaCPAN-Client-2.023000/LICENSE0000644000175000017500000004364113232713623015047 0ustar mickeymickeyThis software is copyright (c) 2016 by Sawyer X. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. Terms of the Perl programming language system itself a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" --- The GNU General Public License, Version 1, February 1989 --- This software is Copyright (c) 2016 by Sawyer X. This is free software, licensed under: The GNU General Public License, Version 1, February 1989 GNU GENERAL PUBLIC LICENSE Version 1, February 1989 Copyright (C) 1989 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The license agreements of most software companies try to keep users at the mercy of those companies. By contrast, our General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. The General Public License applies to the Free Software Foundation's software and to any other program whose authors commit to using it. You can use it for your programs, too. When we speak of free software, we are referring to freedom, not price. Specifically, the General Public License is designed to make sure that you have the freedom to give away or sell copies of free software, that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of a such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must tell them their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any work containing the Program or a portion of it, either verbatim or with modifications. Each licensee is addressed as "you". 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this General Public License and to the absence of any warranty; and give any other recipients of the Program a copy of this General Public License along with the Program. You may charge a fee for the physical act of transferring a copy. 2. You may modify your copy or copies of the Program or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above, provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains the Program or any part thereof, either with or without modifications, to be licensed at no charge to all third parties under the terms of this General Public License (except that you may choose to grant warranty protection to some or all third parties, at your option). c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the simplest and most usual way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this General Public License. d) You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. Mere aggregation of another independent work with the Program (or its derivative) on a volume of a storage or distribution medium does not bring the other work under the scope of these terms. 3. You may copy and distribute the Program (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 1 and 2 above provided that you also do one of the following: a) accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Paragraphs 1 and 2 above; or, b) accompany it with a written offer, valid for at least three years, to give any third party free (except for a nominal charge for the cost of distribution) a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) Source code for a work means the preferred form of the work for making modifications to it. For an executable file, complete source code means all the source code for all modules it contains; but, as a special exception, it need not include source code for modules which are standard libraries that accompany the operating system on which the executable file runs, or for standard header files or definitions files that accompany that operating system. 4. You may not copy, modify, sublicense, distribute or transfer the Program except as expressly provided under this General Public License. Any attempt otherwise to copy, modify, sublicense, distribute or transfer the Program is void, and will automatically terminate your rights to use the Program under this License. However, parties who have received copies, or rights to use copies, from you under this General Public License will not have their licenses terminated so long as such parties remain in full compliance. 5. By copying, distributing or modifying the Program (or any work based on the Program) you indicate your acceptance of this license to do so, and all its terms and conditions. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. 7. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of the license which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the license, you may choose any version ever published by the Free Software Foundation. 8. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to humanity, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19xx name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (a program to direct compilers to make passes at assemblers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice That's all there is to it! --- The Artistic License 1.0 --- This software is Copyright (c) 2016 by Sawyer X. This is free software, licensed under: The Artistic License 1.0 The Artistic License Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: - "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. - "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. - "Copyright Holder" is whoever is named in the copyright or copyrights for the package. - "You" is you, if you're thinking about copying or distributing this Package. - "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) - "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as ftp.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. 7. C or perl subroutines supplied by you and linked into this Package shall not be considered part of this Package. 8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End MetaCPAN-Client-2.023000/Changes0000644000175000017500000003457213232713623015340 0ustar mickeymickeyRevision history for MetaCPAN-Client (previously MetaCPAN-API) 2.023000 26.1.18 * Support the new 'deprecated' field in File and Release types (Mickey) 2.022000 3.1.18 * Allow user-defined target classes in ResultSet (Kent Fredric, Sawyer) * Added test for reverse dependencies (Sawyer) * Switched ref() checks to Ref::Util::is_ref (Mickey) 2.021000 18.11.17 * Scroller fix for page skipping (Thomas Sibley) * Sorting in scrolled searches (Thomas Sibley) * Type check cleanup (Thomas Sibley) 2.020000 17.11.17 * Added support for /search/autocomplete/suggest (Mickey) 2.019000 16.11.17 * Added 'package' type support for scrolled searches (Mickey) 2.018000 16.10.17 * Fix fetch URL (Mickey, GH#92) * Removed critic author test (Mickey) 2.017000 25.6.17 * reverse_dependencies: update link to new API endpoint (Mickey, GH#89) 2.016000 7.6.17 * Support CSV field list in 'all' requests (Mickey, GH#87) 2.015000 14.5.17 * Added 'main_module' field to the Release object (Mickey) * Updated doc (Matthew Horsfall, GH#85) 2.014000 12.5.17 * Fixed single-value case for expected arrayref (Mickey, GH#84) * Added support for new release/contributors endpoint (Mickey) 2.013001 12.5.17 * Updated endpoint name following API change (Mickey) 2.013000 9.5.17 * Added support for new 'packages' type (Mickey) 2.012000 27.4.17 * Fixed 'email' field handling in Author objects (Mickey, GH#83) 2.011000 18.4.17 * Added support for scroller time/size params (Mickey) * Removed warning of scroller deletion failure (Mickey, GH#81) 2.010000 3.4.17 * Added support for new 'permission' type (Mickey) 2.009001 29.3.17 * Use Test::Needs to force a minimum WWW::Mechanize::Cached version (Olaf Alders, GH#76) 2.009000 24.3.17 * Bump WWW::Mechanize::Cached version to 1.50 (Olaf Alders, GH#76) * Require LWP::Protocol::https in tests (Mickey, GH#79) * Added 'changes' method for Release objects (Mickey, GH#57) * Cleaner URLs - removed redundant slashes and 'v1' (Mickey) * Created a role for user-agent handling for reuse (Mickey) 2.008001 23.3.17 * Fixed a test (Mickey) 2.008000 22.3.17 * Added metacpan_url method to the entity objects (Mickey, #GH69) 2.007000 8.3.17 * Update tests for newer Perl versions, to run without '.' in @INC (Sawyer X, GH#72) 2.006000 24.2.17 * Support '_source' filtering (Mickey, GH#70) * Support debug-mode for detailed error messages (Mickey) 2.005000 13.2.17 * Added the ascii_name and perlmongers fields to the Author object (Dave Rolsky, GH #66) * Fixed Author->dir to actually return something (Dave Rolsky, GH #66) 2.004000 30.12.16 * Speed up own scroller (Mickey) * Fixed rev_deps (Mickey) 2.004000-TRIAL 24.12.16 * Removed dependency: Search::Elasticsearch in favor of an internal scroller (Mickey) * Added Types class for 'isa' checks (Mickey) 2.003000 19.12.16 * Escaped query to autocomplete (Mickey) * Removed dependency: Try::Tiny (Mickey) 2.002000 14.12.16 * Support 'autocomplete' endpoint (Mickey) 2.001000 08.12.16 * Distribution: added 'rt' & 'github' methods (Mickey) * Use Ref::Util for ref checks (Mickey) 2.000000 18.11.16 * Major version: v1 full support - removed support and default settings for v0 - corrected domain, base_url setting, using clientinfo - code/tests updates and cleanup (Mickey, Brad Lhotsky) * Pinned Search::Elasticsearch version to 2.03 (Mickey) * Use @Starter in dist.ini + cpanfile cleanup (Grinnz) 1.028003 23.10.16 * Removed AutoPrereqs from dist.ini (Mickey) 1.028002 23.10.16 * GH #53 a few small dist.ini tweaks (Karen Etheridge) * Even more dist.ini tweaks (Mickey, thanks to Grinnz) 1.028001 22.10.16 * GH #51 Adds eumm_version to dist.ini (Olaf Alders) * GH #52 Stop excluding cpanfile from being copied to build (Olaf Alders) 1.028000 21.10.16 * GH #50 Remove hard-deps for HTTP::Tiny::Mech and WWW::Mechanize::Cached (Paul Howarth) * dist.ini: don't automatically update cpanfile (Mickey) 1.027000 20.10.16 * GH #49 Convert values of JSON::PP::Boolean objects in output so they are not skipped when expeting scalars (Mickey) 1.026001 19.10.16 * Fixed version range for Search::Elasticsearch (Mickey) 1.026000 19.10.16 * Moved distini prereqs to cpanfile (Mickey) * Limit Search::Elasticsearch version to 2.02 (Mickey) * Updated docs (Thomas Sibley) 1.025000 30.8.16 * Added some version requirements to improve SSL over HTTP::Tiny (Mickey) * Added default values for distribution keys with no content (Mickey, per Tux request) 1.024000 28.08.16 * Try to fetch clientinfo from https://clientinfo.metacpan.org to get default production version (Mickey) 1.023000 27.08.16 * Added support for version by env METACPAN_VERSION (Mickey) * Added tests for version argument (Mickey) 1.022003 06.08.16 * Fixed a warning in $file->pod (Mickey) 1.022002 06.08.16 * Added LWP::Protocol::https as test dependency (Mickey) 1.022001 05.08.16 * check user provided UA for 'get' and 'post' methods (Mickey) * document updates (Mickey) 1.022000 04.08.16 * Rework type checking - enforce expected types, inc. single-valued array-ref unwrapping; doesn't break types that are expected to be array-refs (Mickey) 1.021000 27.07.16 * Fix result values in v1 - single valued arrayref in ES result will be turned to a scalar (Mickey) 1.020000 12.07.16 * Added support for Author->release_count & Author->links methods (Mickey) * Added support for url_prefix parameter for Pod (Mickey) 1.019000 06.07.16 * Added missing 'download_url' attribute to file/module result objects (Mickey) 1.018000 06.07.16 * Added support for download_url endpoint (Mickey) * Default domain set by providing 'version' - makes it easy to work with v1 (Mickey) 1.017000 28.06.16 * Fixed nodes list for Search::Elasticsearch (Mickey) * Added support for 'aggregations' (Mickey) 1.016000 27.06.16 * Added support for 'all' filters type 'files' (Mickey) * http -> https (Mickey) 1.015000 02.06.16 * Adding `source` method to MetaCPAN::Client::File (stevan) 1.014000 29.04.16 * Fix warning on missing fields param (Mickey, Sawyer X) * Switch to Search::Elasticsearch 2.0. (Sawyer X) * You can test MetaCPAN::API with a different domain using the environment variable "METACPAN_DOMAIN". (Mickey) 1.013000 25.04.15 * GH #34 Use Travis for CI (oalders) * GH #35 Improve Kwalitee + test improvements (oalders) 1.012000 09.04.15 * GH #33 added Mirror type and support for mirrors search in 'all' queries (mickeyn) * GH #33 support 'ratings' search in 'all' queries (mickeyn) * more example scripts: facets, top favorites, all authors blogs (mickeyn) * cleanup & doc updates (Gabor Szabo, mickeyn) 1.011000 27.01.15 * support 'favorites' type and 'facets' key param in 'all' queries (mickeyn) 1.010000 23.01.15 * support wildcard-only value in complex search (mickeyn) * support raw Elasticsearch filters in 'all' queries (mickeyn) 1.009000 11.01.15 * GH #25 (RT #99499): added support for 'fields' filtering (mickeyn, oalders) 1.008001 01.01.15 * Happy new year! * Correct Meta resources for the repo. * Correct link in POD for the Pod element. (Alex Vandiver) 1.008000 22.11.14 * RT #99498: added API for 'match_all' queries via all($type) (oalders, mickeyn) * GH #21: make 'domain' and 'version' settable via new() (oalders) * RT #94491: document nested queries (neilb, mickeyn) 1.007001 09.10.14 * GH #18: HTTP::Tiny::Mech and WWW::Mechanize::Cached downgraded to being non-essential for tests (kentnl) * GH #19: Include 'metadata' in known_fields for ::Release (kentnl) 1.007000 14.08.14 * Ensure passing user specified ua values to all parts internally, including to Elasticsearch (kentnl) GH #17 RT#95796 * Entity consuming roles now have a 'client' attribute which will lazy build, or reference the MetaCPAN::Client that created them via new_from_request (kentnl) GH #17 1.006000 24.06.14 * Add 'recent' functionality (latest releases) 1.005000 09.06.14 * Add Pod object to allow direct POD fetching (reneeb) * Support single element without wrapping arrayref in structures * Updated documents - basic/complex search links and wording (tsibley) 1.004001 27.05.14 * correct rev_deps query 1.004000 27.05.14 * reworked ResultSet to allow RS in non-scrolled searches. 1.003000 05.05.14 * Add proper POD fetching from module/file objects. * GH #1: Switch from JSON.pm to JSON::MaybeXS. * GH #2: Remove incorrect and unnecessary check for class names. * Provide "ua" attribute in the main object to override user agent. * Add some use-case examples (examples directory). * Add 'releases' method to Author (not official so no docs yet). * GH #4: Use example with hyphen. * Related to GH #4, use Data::Printer instead of shotened name "DDP". 1.002000 24.04.14 * Add 'not' support for complex queries * Add reverse_dependencies method 1.001001 15.04.14 * Fix the reading of scroller result when 'fields' param is passed. 1.001000 09.04.14 * Add support for nested either/all queries * Add tests for complex queries (two levels deep) * Correct documentation on complex queries * Update tests to work on older versions of perl 1.000001 03.04.14 * changed Elasticsearch (deprecated) to Search::Elasticsearch (official) 1.000000 02.04.14 ** Completely rewritten ** MetaCPAN::API has been completely rewritten as MetaCPAN::Client. Other than the different name (to match MetaCPAN itself), the following changes had been made: * MetaCPAN::Client is officially part of MetaCPAN * Semantic Versioning (semver) scheme * Moo as object system * All entities are now objects * Using Elasticsearch.pm for complex queries * Rich syntax for nested queries (AND/OR) * Simple queries return entity objects * Complex queries return resultset objects (with iterator) * Support for scrolled searches * Inline support for Elasticsearch facets * Documentation, tests - all cleaned, rewritten 0.43 05.04.12 * Add example in POD of advanced usage with cache by Kent Fredric. (Gist: https://gist.github.com/1291928) * Sort keys in param join - more predictable result. 0.42 08.01.12 * Corrected documentation in MetaCPAN::API::Source. * Updated Dist::Zilla configuration, added more tests. 0.41 07.01.12 * Use Test::TinyMocker 0.02 syntax in tests to avoid test fails. 0.40 06.01.12 * Fixed JSON encoding so ElasticSearch won't fail. (Christian Walde) * Documentation fixes (Logan - logie17). 0.34 02.10.11 * Added MetaCPAN::API::Source (Renee Baecker). * Fix of HTTP::Tiny content-type in options (Renee Baecker). * Typo fix (Olaf Alders, reported by @doherty). 0.33 24.08.11 * No functional changes. * Skip t::lib in dzil. 0.32 04.08.11 * Use a default agent string for requests. * Use a default agent string for tests. 0.31 02.08.11 * URL updates (thanks to Olaf Alders, OALDERS). * Small mismatched quote in POD example. 0.30 30.07.11 * Add POST query searches (RT #69814, GH #2). (original code by Tim Bunce, thank you!) * More tests. 0.20 28.07.11 * Add complex (manual) searches to author()/release() + docs. * Add file() as a synonym to module(). * Respect content-type. * Allow setting additional params to fetch(). * Allow "pauseid" in author via key. * Better check for content-type. 0.11 24.07.11 * Correct the POD example and tests. * Update to use a different API path. 0.10 24.07.11 * Almost complete rewrite. * Make use of the new beta API. * Remove old API support. * Remove DWIM methods for now. * Include lots of tests. 0.02 13.02.11 (First stable release!) * Add docs (Sawyer X). 0.01_03 10.02.11 * Immutable base_url (Olaf Alders, Sawyer X). 0.01_02 10.02.11 * Make base_url 'rw' (Olaf Alders). * Update module search URL (Olaf Alders). * Refactoring using _http_req method (Sawyer X). * Remove render_result method (Sawyer X). * Remove unnecessary print (Sawyer X). 0.01_01 05.02.11 * Module, Dist, POD, Author and CPANRatings are supported 100%. * Still needs more refactoring, and some methods aren't used yet. MetaCPAN-Client-2.023000/lib/0000755000175000017500000000000013232713623014600 5ustar mickeymickeyMetaCPAN-Client-2.023000/lib/MetaCPAN/0000755000175000017500000000000013232713623016130 5ustar mickeymickeyMetaCPAN-Client-2.023000/lib/MetaCPAN/Client/0000755000175000017500000000000013232713623017346 5ustar mickeymickeyMetaCPAN-Client-2.023000/lib/MetaCPAN/Client/Scroll.pm0000644000175000017500000001006313232713623021142 0ustar mickeymickeyuse strict; use warnings; package MetaCPAN::Client::Scroll; # ABSTRACT: A MetaCPAN::Client scroller $MetaCPAN::Client::Scroll::VERSION = '2.023000'; use Moo; use Carp; use Ref::Util qw< is_hashref >; use JSON::MaybeXS qw< decode_json encode_json >; use MetaCPAN::Client::Types qw< Str Int Time ArrayRef HashRef Bool >; has ua => ( is => 'ro', required => 1, ); has size => ( is => 'ro', isa => Str, ); has time => ( is => 'ro', isa => Time, ); has base_url => ( is => 'ro', isa => Str, required => 1, ); has type => ( is => 'ro', isa => Str, required => 1, ); has body => ( is => 'ro', isa => HashRef, required => 1, ); has _id => ( is => 'ro', isa => Str, ); has _buffer => ( is => 'ro', isa => ArrayRef, default => sub { [] }, ); has _done => ( is => 'rw', isa => Bool, default => sub { 0 }, ); has total => ( is => 'ro', isa => Int, ); has aggregations => ( is => 'ro', isa => HashRef, default => sub { +{} }, ); sub BUILDARGS { my ( $class, %args ) = @_; $args{time} //= '5m'; $args{size} //= '100'; my ( $ua, $base_url, $type, $body, $time, $size ) = @args{qw< ua base_url type body time size >}; # fetch scroller from server my $res = $ua->post( sprintf( '%s/%s/_search?scroll=%s&size=%s', $base_url, $type, $time, $size ), { content => encode_json $body } ); if ( $res->{status} != 200 ) { my $msg = "failed to create a scrolled search"; $args{debug} and $msg .= "\n(" . $res->{content} . ")"; croak $msg; } my $content = decode_json $res->{content}; # read response content --> object params $args{_id} = $content->{_scroll_id}; $args{total} = $content->{hits}{total}; $args{_buffer} = $content->{hits}{hits}; $args{aggregations} = $content->{aggregations} if $content->{aggregations} and is_hashref( $content->{aggregations} ); return \%args; } sub next { my $self = shift; my $buffer = $self->_buffer; # We're exhausted and will do no more. return if $self->_done; # Refill the buffer if it's empty. @$buffer = @{ $self->_fetch_next } unless @$buffer; # Grab the next result from the buffer. If there's no result, then that's # all, folks! my $next = shift @$buffer; $self->_done(1) unless $next; return $next; } sub _fetch_next { my $self = shift; my $res = $self->ua->post( sprintf( '%s/_search/scroll?scroll=%s&size=%s', $self->base_url, $self->time, $self->size ), { content => $self->_id } ); croak "failed to fetch next scolled batch" unless $res->{status} == 200; my $content = decode_json $res->{content}; return $content->{hits}{hits}; } sub DEMOLISH { my $self = shift; $self->ua->delete( sprintf( '%s/_search/scroll?scroll=%s', $self->base_url, $self->time ), { content => $self->_id } ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME MetaCPAN::Client::Scroll - A MetaCPAN::Client scroller =head1 VERSION version 2.023000 =head1 METHODS =head2 next get next matched document. =head2 BUILDARGS =head2 DEMOLISH =head1 ATTRIBUTES =head2 aggregations The returned aggregations structure from agg requests. =head2 base_url The base URL for sending server requests. =head2 body The request body. =head2 size The number of docs to pull from each shard per request. =head2 time The lifetime of the scroller on the server. =head2 total The total number of matches. =head2 type The Elasticsearch type to query. =head2 ua The user agent object for running requests. =head1 AUTHORS =over 4 =item * Sawyer X =item * Mickey Nasriachi =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Sawyer X. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut MetaCPAN-Client-2.023000/lib/MetaCPAN/Client/Favorite.pm0000644000175000017500000000337713232713623021475 0ustar mickeymickeyuse strict; use warnings; package MetaCPAN::Client::Favorite; # ABSTRACT: A Favorite data object $MetaCPAN::Client::Favorite::VERSION = '2.023000'; use Moo; with 'MetaCPAN::Client::Role::Entity'; my %known_fields = ( scalar => [qw< date user release id author distribution >], arrayref => [], hashref => [] ); my @known_fields = map { @{ $known_fields{$_} } } qw< scalar arrayref hashref >; foreach my $field (@known_fields) { has $field => ( is => 'ro', lazy => 1, default => sub { my $self = shift; return $self->data->{$field}; }, ); } sub _known_fields { return \%known_fields } 1; __END__ =pod =encoding UTF-8 =head1 NAME MetaCPAN::Client::Favorite - A Favorite data object =head1 VERSION version 2.023000 =head1 SYNOPSIS my $favorites = $mcpan->favorite( { distribution => 'Moose' } ); while ( my $fav = $favorites->next ) { ... } =head1 DESCRIPTION A MetaCPAN favorite entity object. =head1 ATTRIBUTES =head2 date An ISO8601 datetime string like C<2016-11-19T12:41:46> indicating when the favorite was created. =head2 user The user ID (B PAUSE ID) of the person who favorited the thing in question. =head2 release The release that was favorited. =head2 id The favorite ID. =head2 author The PAUSE ID of the author whose release was favorited. =head2 distribution The distribution that was favorited. =head1 AUTHORS =over 4 =item * Sawyer X =item * Mickey Nasriachi =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Sawyer X. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut MetaCPAN-Client-2.023000/lib/MetaCPAN/Client/Package.pm0000644000175000017500000000331413232713623021240 0ustar mickeymickeyuse strict; use warnings; package MetaCPAN::Client::Package; # ABSTRACT: A package data object (02packages.details entry) $MetaCPAN::Client::Package::VERSION = '2.023000'; use Moo; with 'MetaCPAN::Client::Role::Entity'; my %known_fields = ( scalar => [qw< author distribution dist_version file module_name version >], arrayref => [qw<>], hashref => [], ); my @known_fields = map { @{ $known_fields{$_} } } qw< scalar arrayref hashref >; foreach my $field (@known_fields) { has $field => ( is => 'ro', lazy => 1, default => sub { my $self = shift; return $self->data->{$field}; }, ); } sub _known_fields { return \%known_fields } 1; __END__ =pod =encoding UTF-8 =head1 NAME MetaCPAN::Client::Package - A package data object (02packages.details entry) =head1 VERSION version 2.023000 =head1 SYNOPSIS my $package = $mcpan->package('MooseX::Types'); =head1 DESCRIPTION A MetaCPAN package (02packages.details) entity object. =head1 ATTRIBUTES =head2 module_name Returns the name of the module. =head2 file The file path in CPAN for the module (latest release) =head2 distribution The distribution in which the module exist =head2 version The (latest) version of the module =head2 dist_version The (latest) version of the distribution =head2 author The pauseid of the release author =head1 AUTHORS =over 4 =item * Sawyer X =item * Mickey Nasriachi =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Sawyer X. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut MetaCPAN-Client-2.023000/lib/MetaCPAN/Client/Author.pm0000644000175000017500000001441113232713623021147 0ustar mickeymickeyuse strict; use warnings; package MetaCPAN::Client::Author; # ABSTRACT: An Author data object $MetaCPAN::Client::Author::VERSION = '2.023000'; use Moo; use Ref::Util qw< is_arrayref >; with 'MetaCPAN::Client::Role::Entity'; my %known_fields = ( scalar => [qw< city country gravatar_url name ascii_name pauseid region updated user >], arrayref => [qw< donation email perlmongers profile website >], hashref => [qw< blog extra links release_count >], ); sub BUILDARGS { my ( $class, %args ) = @_; my $email = $args{'email'} || []; $args{'email'} = [ $email ] unless is_arrayref($email); return \%args; } my @known_fields = map { @{ $known_fields{$_} } } qw< scalar arrayref hashref >; foreach my $field ( @known_fields ) { has $field => ( is => 'ro', lazy => 1, default => sub { my $self = shift; return $self->data->{$field}; }, ); } sub _known_fields { \%known_fields } sub releases { my $self = shift; my $id = $self->pauseid; return $self->client->release({ all => [ { author => $id }, { status => 'latest' }, ] }); } sub dir { $_[0]->links->{cpan_directory} } sub metacpan_url { "https://metacpan.org/author/" . $_[0]->pauseid } 1; __END__ =pod =encoding UTF-8 =head1 NAME MetaCPAN::Client::Author - An Author data object =head1 VERSION version 2.023000 =head1 SYNOPSIS my $author = $mcpan->author('MICKEY'); =head1 DESCRIPTION a MetaCPAN author entity object. =head1 ATTRIBUTES =head2 pauseid The author's pause id, which is a string like C or C. =head2 name The author's full name, if they've provided this in their MetaCPAN profile. This may contain Unicode characters. =head2 ascii_name An ASCII-only version of the author's full name, if they've provided this in their MetaCPAN profile. =head2 city The author's city, if they've provided this in their MetaCPAN profile. =head2 region The author's region, if they've provided this in their MetaCPAN profile. =head2 country The author's country, if they've provided this in their MetaCPAN profile. =head2 updated An ISO8601 datetime string like C<2016-11-19T12:41:46> indicating when the author last updated their MetaCPAN profile. This is always provided in UTC. =head2 dir The author's CPAN directory, which is something like C. =head2 gravatar_url The author's gravatar.com user URL, if they have one. This URL is generated using PAUSEID@cpan.org. =head2 user The user's internal MetaCPAN id. =head2 donation This is an arrayref containing zero or more hashrefs. Each hashref contains two keys, C and C. The known names are currently C, C, and C. The id will be an appropriate id or URL for the thing in question. This may be empty if the author has not provided this information in their MetaCPAN profile. For example: [ { "name" => "paypal", "id" => "brian.d.foy@gmail.com" }, { "name" => "wishlist", "id" => "http://amzn.com/w/4O7IX9ZNQJR" }, ], =head2 email This is an arrayref containing zero or more email addresses that the author has added to their MetaCPAN profile. Note that this does I include the C email address that all CPAN authors have. =head2 website This is an arrayref of website URLs provided by the author in their MetaCPAN profile. =head2 profile This is an arrayref containing zero or more hashrefs. Each hashref contains two keys, C and C. The names are things like C or C. The id will be an appropriate id for the site in question. For example: [ { name => "amazon", id => "B002MRC39U" }, { name => "stackoverflow", id => "brian-d-foy" }, ] This may be empty if the author has not provided this information in their MetaCPAN profile. =head2 perlmongers This is an arrayref containing zero or more hashrefs. Each hashref contains two keys, C and C. The names are things like C. This may be empty if the author has not provided this information in their MetaCPAN profile. =head2 links This is a hashref where the keys are a link type, and the values are URLs. The currently known keys are: =over 4 =item * cpan_directory The author's CPAN directory. =item * backpan_directory The author's BackCPAN directory. =item * cpantesters_reports The author's CPAN Testers Reports page. =item * cpantesters_matrix The author's CPAN Testers matrix page. =item * cpants The author's CPANTS page. =item * metacpan_explorer A link to the MetaCPAN explorer site pre-populated with a request for the author's profile. =back =head2 blog This is an arrayref containing zer or more hashrefs. Each hashref contains two keys, C and C. For example: { url => "http://blogs.perl.org/users/brian_d_foy/", feed => "http://blogs.perl.org/users/brian_d_foy/atom.xml", } =head2 release_count This is a hashref containing counts for various types of releases. The known keys are: =over 4 =item * cpan The total number of distribution uplaods the author currently has on CPAN. =item * latest The total number of unique distributions the author currently has on CPAN. =item * backpan-only The number of distribution uploads currently only available via BackPAN. =back =head2 extra Returns a hashref. The contents of this are entirely arbitrary and will vary by author. =head1 METHODS =head2 BUILDARGS Ensures format of the input. =head2 releases my $releases = $author->releases(); This method returns a L of L objects. It includes all of the author's releases with the C status. =head2 metacpan_url Returns a link to the author's page on MetaCPAN. =head1 AUTHORS =over 4 =item * Sawyer X =item * Mickey Nasriachi =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Sawyer X. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut MetaCPAN-Client-2.023000/lib/MetaCPAN/Client/Distribution.pm0000644000175000017500000000605713232713623022373 0ustar mickeymickeyuse strict; use warnings; package MetaCPAN::Client::Distribution; # ABSTRACT: A Distribution data object $MetaCPAN::Client::Distribution::VERSION = '2.023000'; use Moo; with 'MetaCPAN::Client::Role::Entity'; my %known_fields = ( scalar => [qw< name >], arrayref => [], hashref => [qw< bugs river >] ); my %__known_fields_ex = ( map { my $k = $_; $k => +{ map { $_ => 1 } @{ $known_fields{$k} } } } keys %known_fields ); my @known_fields = map { @{ $known_fields{$_} } } keys %known_fields; foreach my $field ( @known_fields ) { has $field => ( is => 'ro', lazy => 1, default => sub { my $self = shift; return ( exists $self->data->{$field} ? $self->data->{$field} : exists $__known_fields_ex{hashref}{$field} ? {} : exists $__known_fields_ex{arrayref}{$field} ? [] : exists $__known_fields_ex{scalar}{$field} ? '' : undef ); }, ); } sub _known_fields { return \%known_fields } sub rt { $_[0]->bugs->{rt} || {} } sub github { $_[0]->bugs->{github} || {} } sub metacpan_url { "https://metacpan.org/release/" . $_[0]->name } 1; __END__ =pod =encoding UTF-8 =head1 NAME MetaCPAN::Client::Distribution - A Distribution data object =head1 VERSION version 2.023000 =head1 SYNOPSIS my $dist = $mcpan->distribution('MetaCPAN-Client'); =head1 DESCRIPTION A MetaCPAN distribution entity object. =head1 ATTRIBUTES =head2 name The distribution's name. =head2 bugs A hashref containing information about bugs reported in various issue trackers. The top-level keys are issue tracker names like C or C. Each value is itself a hashref containing information about the bugs in that tracker. The keys vary between trackers, but this will always contain a C key, which is a URL for the tracker. There may also be keys containing counts such as C, C, etc. =head2 river A hashref containing L<"CPAN River"|http://neilb.org/2015/04/20/river-of-cpan.html> information about the distro. The hashref contains the following keys: =over 4 =item * bucket A positive or zero integer. The higher the number the farther upstream this distribution is. =item * immediate The number of distributions that directly depend on this one. =item * total The number of distributions that depend on this one, directly or indirectly. =back =head1 METHODS =head2 rt Returns the hashref of data for the rt bug tracker. This defaults to an empty hashref. =head2 github Returns the hashref of data for the github bug tracker. This defaults to an empty hashref. =head2 metacpan_url Returns a link to the distribution page on MetaCPAN. =head1 AUTHORS =over 4 =item * Sawyer X =item * Mickey Nasriachi =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Sawyer X. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut MetaCPAN-Client-2.023000/lib/MetaCPAN/Client/Pod.pm0000644000175000017500000000430013232713623020423 0ustar mickeymickeyuse strict; use warnings; package MetaCPAN::Client::Pod; # ABSTRACT: A Pod object $MetaCPAN::Client::Pod::VERSION = '2.023000'; use Moo; use Carp; use MetaCPAN::Client::Types qw< Str >; has request => ( is => 'ro', handles => [qw], required => 1, ); has name => ( is => 'ro', required => 1 ); has url_prefix => ( is => 'ro', isa => Str, ); my @known_formats = qw< html plain x_pod x_markdown >; foreach my $format (@known_formats) { has $format => ( is => 'ro', lazy => 1, default => sub { my $self = shift; return $self->_request( $format ); }, ); } sub _request { my $self = shift; my $ctype = shift || "plain"; $ctype =~ s/_/-/; my $url = 'pod/' . $self->name . '?content-type=text/' . $ctype; $self->url_prefix and $url .= '&url_prefix=' . $self->url_prefix; return $self->request->fetch($url); } 1; __END__ =pod =encoding UTF-8 =head1 NAME MetaCPAN::Client::Pod - A Pod object =head1 VERSION version 2.023000 =head1 SYNOPSIS use strict; use warnings; use MetaCPAN::Client; my $pod = MetaCPAN::Client->new->pod('Moo'); print $pod->html; =head1 DESCRIPTION A MetaCPAN pod entity object. =head1 ATTRIBUTES =head2 request A L object (created in L) =head2 name The name of the module (probably always the value passed to the pod() method) =head2 url_prefix Prefix to be passed through the url_prefix query parameter to the 'pod' endpoint =head2 x_pod The raw pod extracted from the file. =head2 html Formatted as an HTML chunk (No ...) =head2 x_markdown Converted to Markdown. =head2 plain Formatted as plain text. Get the plaintext version of the documentation $pod = MetaCPAN::Client->new->pod( "MetaCPAN::Client" ); print $pod->plain; =head1 AUTHORS =over 4 =item * Sawyer X =item * Mickey Nasriachi =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Sawyer X. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut MetaCPAN-Client-2.023000/lib/MetaCPAN/Client/Release.pm0000644000175000017500000001254113232713623021267 0ustar mickeymickeyuse strict; use warnings; package MetaCPAN::Client::Release; # ABSTRACT: A Release data object $MetaCPAN::Client::Release::VERSION = '2.023000'; use Moo; use Ref::Util qw< is_hashref >; use JSON::MaybeXS qw< decode_json >; with 'MetaCPAN::Client::Role::Entity', 'MetaCPAN::Client::Role::HasUA'; my %known_fields = ( scalar => [qw< abstract archive author authorized date deprecated distribution download_url first id maturity main_module name status version version_numified >], arrayref => [qw< dependency license provides >], hashref => [qw< metadata resources stat tests >], ); my @known_fields = map { @{ $known_fields{$_} } } qw< scalar arrayref hashref >; foreach my $field (@known_fields) { has $field => ( is => 'ro', lazy => 1, default => sub { my $self = shift; return $self->data->{$field}; }, ); } sub _known_fields { return \%known_fields } sub changes { my $self = shift; my $url = sprintf "https://fastapi.metacpan.org/changes/%s/%s", $self->author, $self->name; my $res = $self->ua->get($url); return unless is_hashref($res); my $content = decode_json $res->{'content'}; return $content->{'content'}; } sub metacpan_url { my $self = shift; sprintf( "https://metacpan.org/release/%s/%s", $self->author, $self->name ) } sub contributors { my $self = shift; my $url = sprintf( "https://fastapi.metacpan.org/release/contributors/%s/%s", $self->author, $self->name ); my $res = $self->ua->get($url); return unless is_hashref($res); my $content = decode_json $res->{'content'}; return $content->{'contributors'}; } 1; __END__ =pod =encoding UTF-8 =head1 NAME MetaCPAN::Client::Release - A Release data object =head1 VERSION version 2.023000 =head1 SYNOPSIS my $release = $mcpan->release('Moose'); =head1 DESCRIPTION A MetaCPAN release entity object. =head1 ATTRIBUTES =head2 status The release's status, C, C, or C. =head2 name The release's name, something like C. =head2 date An ISO8601 datetime string like C<2016-11-19T12:41:46> indicating when the release was uploaded. =head2 author The PAUSE ID of the author who uploaded the release. =head2 maturity This will be either C or C. =head2 main_module The release's main module name. =head2 id The release's internal MetaCPAN id. =head2 authorized A boolean indicating whether or not this was an authorized release. =head2 download_url A URL for this release's distribution archive file. =head2 first A boolean indicating whether or not this is the first release of this distribution. =head2 archive The filename of the archive file for this release. =head2 version The release's version. =head2 version_numified The numified form of the release's version. =head2 deprecated The deprecated field value for this release. =head2 distribution The name of the distribution to which this release belongs. =head2 abstract The abstract from this release's metadata. =head2 dependency This is an arrayref of hashrefs. Each hashref contains the following keys: =over 4 =item * phase The phase to which this dependency belongs. This will be one of C, C, C, C, or C. =item * relationship This will be one of C, C, or C. =item * module The name of the module which is depended on. =item * version The required version of the dependency. This may be C<0>, indicating that any version is acceptable. =back =head2 license An arrayref containing the license(s) under which this release has been made available. These licenses are represented by strings like C or C. =head2 provides This an arrayref containing a list of all the modules provided by this distribution. =head2 metadata This is a hashref containing metadata provided by the distribution. The exact contents of this hashref will vary across CPAN, but should largely conform to the spec defined by L. =head2 resources The resources portion of the release's metadata, returned as a hashref. =head2 stat A hashref containing C all information about the release's archive file. The keys are: =over 4 =item * mtime The Unix epoch of the file's last modified time. =item * mode The file's mode (as an integer, not an octal representation). =item * size The file's size in bytes. =back =head2 tests Returns a hashref of information about CPAN testers results for this release. The keys are C, C, C, and C. The values are the count of that particular result on CPAN Testers for this release. =head1 METHODS =head2 changes Returns the Changes text for the release. =head2 metacpan_url Returns a link to the release page on MetaCPAN. =head2 contributors Returns a structure with release contributors info. =head1 AUTHORS =over 4 =item * Sawyer X =item * Mickey Nasriachi =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Sawyer X. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut MetaCPAN-Client-2.023000/lib/MetaCPAN/Client/ResultSet.pm0000644000175000017500000000740713232713623021646 0ustar mickeymickeyuse strict; use warnings; package MetaCPAN::Client::ResultSet; # ABSTRACT: A Result Set $MetaCPAN::Client::ResultSet::VERSION = '2.023000'; use Moo; use Carp; use MetaCPAN::Client::Types qw< ArrayRef >; has type => ( is => 'ro', isa => sub { croak 'Invalid type' unless grep { $_ eq $_[0] } qw; }, lazy => 1, ); # in case we're returning from a scrolled search has scroller => ( is => 'ro', isa => sub { use Safe::Isa; $_[0]->$_isa('MetaCPAN::Client::Scroll') or croak 'scroller must be an MetaCPAN::Client::Scroll object'; }, predicate => 'has_scroller', ); # in case we're returning from a fetch has items => ( is => 'ro', isa => ArrayRef, ); has total => ( is => 'ro', default => sub { my $self = shift; return $self->has_scroller ? $self->scroller->total : scalar @{ $self->items }; }, ); has 'class' => ( is => 'ro', lazy => 1, builder => '_build_class', ); sub BUILDARGS { my ( $class, %args ) = @_; exists $args{scroller} or exists $args{items} or croak 'ResultSet must get either scroller or items'; exists $args{scroller} and exists $args{items} and croak 'ResultSet must get either scroller or items, not both'; exists $args{type} or exists $args{class} or croak 'Must pass either type or target class to ResultSet'; exists $args{type} and exists $args{class} and croak 'Must pass either type or target class to ResultSet, not both'; return \%args; } sub BUILD { my ( $self ) = @_; $self->class; # vifify and validate } sub next { my $self = shift; my $result = $self->has_scroller ? $self->scroller->next : shift @{ $self->items }; defined $result or return; return $self->class->new_from_request( $result->{'_source'} || $result->{'fields'} || $result ); } sub aggregations { my $self = shift; return $self->has_scroller ? $self->scroller->aggregations : {}; } sub _build_class { my $self = shift; return 'MetaCPAN::Client::' . ucfirst $self->type; } 1; __END__ =pod =encoding UTF-8 =head1 NAME MetaCPAN::Client::ResultSet - A Result Set =head1 VERSION version 2.023000 =head1 DESCRIPTION Object representing a result from Elastic Search. This is used for the complex (as in L) queries to MetaCPAN. It provides easy access to the scroller and aggregations. =head1 ATTRIBUTES =head2 scroller An L object. =head2 items An arrayref of items to manually scroll over, instead of a scroller object. =head2 type The entity of the result set. Available types: =over 4 =item * author =item * distribution =item * module =item * release =item * favorite =item * file =back =head2 aggregations The aggregations available in the Elastic Search response. =head1 METHODS =head2 next Iterator call to fetch the next result set object. =head2 total Iterator call to fetch the total amount of objects available in result set. =head2 has_scroller Predicate for ES scroller presence. =head2 BUILDARGS Double checks construction of objects. You should never run this yourself. =head2 BUILD Validates the object. You should never run this yourself. =head1 AUTHORS =over 4 =item * Sawyer X =item * Mickey Nasriachi =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Sawyer X. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut MetaCPAN-Client-2.023000/lib/MetaCPAN/Client/Rating.pm0000644000175000017500000000316213232713623021132 0ustar mickeymickeyuse strict; use warnings; package MetaCPAN::Client::Rating; # ABSTRACT: A Rating data object $MetaCPAN::Client::Rating::VERSION = '2.023000'; use Moo; with 'MetaCPAN::Client::Role::Entity'; my %known_fields = ( scalar => [qw< author date details distribution helpful rating release user >], arrayref => [], hashref => [], ); my @known_fields = map { @{ $known_fields{$_} } } qw< scalar arrayref hashref >; foreach my $field (@known_fields) { has $field => ( is => 'ro', lazy => 1, default => sub { my $self = shift; return $self->data->{$field}; }, ); } sub _known_fields { return \%known_fields } 1; __END__ =pod =encoding UTF-8 =head1 NAME MetaCPAN::Client::Rating - A Rating data object =head1 VERSION version 2.023000 =head1 SYNOPSIS my $ratings = $mcpan->rating({ distribution => "Moo" }); while ( my $rat = $ratings->next ) { ... } =head1 DESCRIPTION A MetaCPAN rating entity object. =head1 ATTRIBUTES =head2 date An ISO8601 datetime string like C<2016-11-19T12:41:46> indicating when the rating was created. =head2 release =head2 author =head2 details =head2 rating =head2 distribution =head2 helpful =head2 user =head1 AUTHORS =over 4 =item * Sawyer X =item * Mickey Nasriachi =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Sawyer X. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut MetaCPAN-Client-2.023000/lib/MetaCPAN/Client/Types.pm0000644000175000017500000000244413232713623021014 0ustar mickeymickeyuse strict; use warnings; package MetaCPAN::Client::Types; # ABSTRACT: type checking helper class $MetaCPAN::Client::Types::VERSION = '2.023000'; use Type::Tiny (); use Types::Standard (); use Ref::Util qw< is_ref >; use parent 'Exporter'; our @EXPORT_OK = qw< Str Int Time ArrayRef HashRef Bool >; sub Str { Types::Standard::Str } sub Int { Types::Standard::Int } sub ArrayRef { Types::Standard::ArrayRef } sub HashRef { Types::Standard::HashRef } sub Bool { Types::Standard::Bool } sub Time { return Type::Tiny->new( name => "Time", constraint => sub { !is_ref($_) and /^[1-9][0-9]*(?:s|m|h)$/ }, message => sub { "$_ is not in time format (e.g. '5m')" }, ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME MetaCPAN::Client::Types - type checking helper class =head1 VERSION version 2.023000 =head1 METHODS =head2 ArrayRef =head2 Bool =head2 HashRef =head2 Int =head2 Str =head2 Time =head1 AUTHORS =over 4 =item * Sawyer X =item * Mickey Nasriachi =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Sawyer X. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut MetaCPAN-Client-2.023000/lib/MetaCPAN/Client/Request.pm0000644000175000017500000001666213232713623021347 0ustar mickeymickeyuse strict; use warnings; package MetaCPAN::Client::Request; # ABSTRACT: Object used for making requests to MetaCPAN $MetaCPAN::Client::Request::VERSION = '2.023000'; use Moo; use Carp; use JSON::MaybeXS qw; use Ref::Util qw< is_arrayref is_hashref is_ref >; use MetaCPAN::Client::Scroll; use MetaCPAN::Client::Types qw< HashRef Int >; with 'MetaCPAN::Client::Role::HasUA'; has _clientinfo => ( is => 'ro', isa => HashRef, lazy => 1, builder => '_build_clientinfo', ); has domain => ( is => 'ro', default => sub { $ENV{METACPAN_DOMAIN} and return $ENV{METACPAN_DOMAIN}; $_[0]->_clientinfo->{production}{domain}; }, ); has base_url => ( is => 'ro', lazy => 1, default => sub { $ENV{METACPAN_DOMAIN} and return $ENV{METACPAN_DOMAIN}; $_[0]->_clientinfo->{production}{url}; }, ); has _is_agg => ( is => 'ro', default => 0, writer => '_set_is_agg' ); has debug => ( is => 'ro', isa => Int, default => 0, ); sub BUILDARGS { my ( $self, %args ) = @_; $args{domain} and $args{base_url} = $args{domain}; return \%args; } sub _build_clientinfo { my $self = shift; my $info; eval { $info = $self->ua->get( 'https://clientinfo.metacpan.org' ); $info = decode_json( $info->{content} ); is_hashref($info) and exists $info->{production} or die; 1; } or $info = +{ production => { url => 'https://fastapi.metacpan.org', # last known production url domain => 'https://fastapi.metacpan.org', # last known production domain } }; return $info; } sub fetch { my $self = shift; my $url = shift or croak 'fetch must be called with a URL parameter'; my $params = shift || {}; $url =~ s{^/}{}; my $req_url = sprintf '%s/%s', $self->base_url, $url; my $ua = $self->ua; my $result = keys %{$params} ? $ua->post( $req_url, { content => encode_json $params } ) : $ua->get($req_url); return $self->_decode_result( $result, $req_url ); } sub ssearch { my $self = shift; my $type = shift; my $args = shift; my $params = shift; my $time = delete $params->{'scroller_time'} || '5m'; my $size = delete $params->{'scroller_size'} || 1000; my $scroller = MetaCPAN::Client::Scroll->new( ua => $self->ua, size => $size, time => $time, base_url => $self->base_url, type => $type, body => $self->_build_body($args, $params), debug => $self->debug, ); return $scroller; } sub _decode_result { my $self = shift; my $result = shift; my $url = shift or croak 'Second argument of a URL must be provided'; is_hashref($result) or croak 'First argument must be hashref'; my $success = $result->{'success'}; defined $success or croak 'Missing success in return value'; $success or croak "Failed to fetch '$url': " . $result->{'reason'}; my $content = $result->{'content'} or croak 'Missing content in return value'; $url =~ m|/pod/| and return $content; $url =~ m|/source/| and return $content; my $decoded_result; eval { $decoded_result = decode_json $content; 1; } or do { croak "Couldn't decode '$content': $@"; }; return $decoded_result; } sub _build_body { my $self = shift; my $args = shift; my $params = shift; my $query = $args->{__MATCH_ALL__} ? { match_all => {} } : _build_query_rec($args); return +{ query => $query, $self->_read_filters($params), $self->_read_fields($params), $self->_read_aggregations($params), $self->_read_sort($params) }; } my %key2es = ( all => 'must', either => 'should', not => 'must_not', ); sub _read_fields { my $self = shift; my $params = shift; my $fields = delete $params->{fields}; my $_source = delete $params->{_source}; my @ret; if ( $fields ) { is_arrayref($fields) or croak "fields must be an arrayref"; push @ret => ( fields => $fields ); } if ( $_source ) { is_arrayref($_source) or !is_ref($_source) or croak "_source must be an arrayref or a string"; push @ret => ( _source => $_source ); } return @ret; } sub _read_aggregations { my $self = shift; my $params = shift; my $aggregations = delete $params->{aggregations}; is_ref($aggregations) or return (); $self->_set_is_agg(1); return ( aggregations => $aggregations ); } sub _read_filters { my $self = shift; my $params = shift; my $filter = delete $params->{es_filter}; is_ref($filter) or return (); return ( filter => $filter ); } sub _read_sort { my $self = shift; my $params = shift; my $sort = delete $params->{sort}; is_ref($sort) or return (); return ( sort => $sort ); } sub _build_query_rec { my $args = shift; is_hashref($args) or croak 'query args must be a hash'; my %query = (); my $basic_element = 1; KEY: for my $k ( qw/ all either not / ) { my $v = delete $args->{$k} || next KEY; is_hashref($v) and $v = [ $v ]; is_arrayref($v) or croak "invalid value for key $k"; undef $basic_element; $query{'bool'}{ $key2es{$k} } = [ map +( _build_query_rec($_) ), @$v ]; $k eq 'either' and $query{'bool'}{'minimum_should_match'} = 1; } $basic_element and %query = %{ _build_query_element($args) }; return \%query; } sub _build_query_element { my $args = shift; scalar keys %{$args} == 1 or croak 'Wrong number of keys in query element'; my ($key) = keys %{$args}; my $val = $args->{$key}; !is_ref($val) and $val =~ /[\w\*]/ or croak 'Wrong type of query arguments'; my $wildcard = $val =~ /[*?]/; my $qtype = $wildcard ? 'wildcard' : 'term'; return +{ $qtype => $args }; } 1; __END__ =pod =encoding UTF-8 =head1 NAME MetaCPAN::Client::Request - Object used for making requests to MetaCPAN =head1 VERSION version 2.023000 =head1 ATTRIBUTES =head2 domain $mcpan = MetaCPAN::Client->new( domain => 'localhost' ); What domain to use for all requests. Default: B. =head2 base_url my $mcpan = MetaCPAN::Client->new( base_url => 'https://localhost:9999/v2', ); Instead of overriding the C, you should override the C. The C will be set appropriately automatically. Default: I. =head2 debug debug-mode for more detailed error messages. =head1 METHODS =head2 BUILDARGS =head2 fetch my $result = $mcpan->fetch('/release/Moose'); # with parameters my $more = $mcpan->fetch( '/release/Moose', { param => 'value' }, ); Fetches a path from MetaCPAN (post or get), and returns the decoded result. =head2 ssearch Calls an Elasticsearch query and returns an L scroller object. =head1 AUTHORS =over 4 =item * Sawyer X =item * Mickey Nasriachi =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Sawyer X. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut MetaCPAN-Client-2.023000/lib/MetaCPAN/Client/Role/0000755000175000017500000000000013232713623020247 5ustar mickeymickeyMetaCPAN-Client-2.023000/lib/MetaCPAN/Client/Role/HasUA.pm0000644000175000017500000000450413232713623021551 0ustar mickeymickeyuse strict; use warnings; package MetaCPAN::Client::Role::HasUA; # ABSTRACT: Role for supporting user-agent attribute $MetaCPAN::Client::Role::HasUA::VERSION = '2.023000'; use Moo::Role; use Carp; use HTTP::Tiny; has _user_ua => ( init_arg => 'ua', is => 'ro', predicate => '_has_user_ua', ); has ua => ( init_arg => undef, is => 'ro', lazy => 1, builder => '_build_ua', ); has ua_args => ( is => 'ro', default => sub { [ agent => 'MetaCPAN::Client/'.($MetaCPAN::Client::VERSION||'xx') ] }, ); sub _build_ua { my $self = shift; # This level of indirection is so that if a user has not specified a custom UA # MetaCPAN::Client will have its own UA's # # But if the user **has** specified a custom UA, that UA is used for both. if ( $self->_has_user_ua ) { my $ua = $self->_user_ua; croak "cannot use given ua (must support 'get' and 'post' methods)" unless $ua->can("get") and $ua->can("post"); return $self->_user_ua; } return HTTP::Tiny->new( @{ $self->ua_args } ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME MetaCPAN::Client::Role::HasUA - Role for supporting user-agent attribute =head1 VERSION version 2.023000 =head1 ATTRIBUTES =head2 ua my $mcpan = MetaCPAN::Client->new( ua => HTTP::Tiny->new(...) ); The user agent object for running requests. It must provide an interface that matches L. Explicitly: =over 4 =item * Implement post() Method C must be available that accepts a request URL and a hashref of options. =item * Implement get() Method C must be available that accepts a request URL. =item * Return result hashref Must return a result hashref which has key C and key C. =back Default: L, =head2 ua_args my $mcpan = MetaCPAN::Client->new( ua_args => [ agent => 'MyAgent' ], ); Arguments sent to the user agent. Default: user agent string: B. =head1 AUTHORS =over 4 =item * Sawyer X =item * Mickey Nasriachi =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Sawyer X. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut MetaCPAN-Client-2.023000/lib/MetaCPAN/Client/Role/Entity.pm0000644000175000017500000000603713232713623022067 0ustar mickeymickeyuse strict; use warnings; package MetaCPAN::Client::Role::Entity; # ABSTRACT: A role for MetaCPAN entities $MetaCPAN::Client::Role::Entity::VERSION = '2.023000'; use Moo::Role; use JSON::PP; use Ref::Util qw< is_ref is_arrayref is_hashref >; has data => ( is => 'ro', required => 1, ); has client => ( is => 'ro', lazy => 1, builder => '_build_client', ); sub _build_client { require MetaCPAN::Client; return MetaCPAN::Client->new(); } sub BUILDARGS { my ( $class, %args ) = @_; my $known_fields = $class->_known_fields; for my $k ( @{ $known_fields->{scalar} } ) { $args{data}{$k} = $args{data}{$k}->[0] if is_arrayref( $args{data}{$k} ) and @{$args{data}{$k}} == 1; if ( JSON::PP::is_bool($args{data}{$k}) ) { $args{data}{$k} = JSON::PP::true == $args{data}{$k} ? 1 : 0; } elsif ( is_ref( $args{data}{$k} ) ) { delete $args{data}{$k}; } } for my $k ( @{ $known_fields->{arrayref} } ) { # fix the case when we expect an array ref but get a scalar because # the result array had one element and we received a scalar if ( defined($args{data}{$k}) and !is_ref($args{data}{$k}) ) { $args{data}{$k} = [ $args{data}{$k} ] } delete $args{data}{$k} unless is_arrayref( $args{data}{$k} ); # warn? } for my $k ( @{ $known_fields->{hashref} } ) { delete $args{data}{$k} unless is_hashref( $args{data}{$k} ); # warn? } return \%args; } sub new_from_request { my ( $class, $request, $client ) = @_; my $known_fields = $class->_known_fields; return $class->new( ( defined $client ? ( client => $client ) : () ), data => { map +( defined $request->{$_} ? ( $_ => $request->{$_} ) : () ), map +( @{ $known_fields->{$_} } ), qw< scalar arrayref hashref > } ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME MetaCPAN::Client::Role::Entity - A role for MetaCPAN entities =head1 VERSION version 2.023000 =head1 DESCRIPTION This is a role to be consumed by all L entities. It provides common attributes and methods. =head1 ATTRIBUTES =head2 data Hash reference containing all the entity data. Entities are usually generated using C which sets the C attribute appropriately by picking the relevant information. Required. =head1 METHODS =head2 new_from_request Create a new entity object using a request hash. The hash represents the information returned from a MetaCPAN request. This also sets the data attribute. =head2 BUILDARGS Perform type checks & conversion for the incoming data. =head1 AUTHORS =over 4 =item * Sawyer X =item * Mickey Nasriachi =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Sawyer X. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut MetaCPAN-Client-2.023000/lib/MetaCPAN/Client/Module.pm0000644000175000017500000000275613232713623021143 0ustar mickeymickeyuse strict; use warnings; package MetaCPAN::Client::Module; # ABSTRACT: A Module data object $MetaCPAN::Client::Module::VERSION = '2.023000'; use Moo; extends 'MetaCPAN::Client::File'; sub metacpan_url { my $self = shift; sprintf("https://metacpan.org/pod/release/%s/%s/%s", $self->author, $self->release, $self->path ); } sub package { my $self = shift; return $self->client->package( $self->documentation ); } sub permission { my $self = shift; return $self->client->permission( $self->documentation ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME MetaCPAN::Client::Module - A Module data object =head1 VERSION version 2.023000 =head1 SYNOPSIS my $module = MetaCPAN::Client->new->module('Moo'); =head1 DESCRIPTION A MetaCPAN module entity object. This is currently the exact same as L. =head1 ATTRIBUTES Whatever L has. =head1 METHODS =head2 metacpan_url Returns a link to the module page on MetaCPAN. =head2 package Returns an L object for the module. =head2 permission Returns an L object for the module. =head1 AUTHORS =over 4 =item * Sawyer X =item * Mickey Nasriachi =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Sawyer X. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut MetaCPAN-Client-2.023000/lib/MetaCPAN/Client/Permission.pm0000644000175000017500000000273413232713623022042 0ustar mickeymickeyuse strict; use warnings; package MetaCPAN::Client::Permission; # ABSTRACT: A Permission data object $MetaCPAN::Client::Permission::VERSION = '2.023000'; use Moo; with 'MetaCPAN::Client::Role::Entity'; my %known_fields = ( scalar => [qw< module_name owner >], arrayref => [qw< co_maintainers >], hashref => [], ); my @known_fields = map { @{ $known_fields{$_} } } qw< scalar arrayref hashref >; foreach my $field (@known_fields) { has $field => ( is => 'ro', lazy => 1, default => sub { my $self = shift; return $self->data->{$field}; }, ); } sub _known_fields { return \%known_fields } 1; __END__ =pod =encoding UTF-8 =head1 NAME MetaCPAN::Client::Permission - A Permission data object =head1 VERSION version 2.023000 =head1 SYNOPSIS my $permission = $mcpan->permission('MooseX::Types'); =head1 DESCRIPTION A MetaCPAN permission entity object. =head1 ATTRIBUTES =head2 module_name Returns the name of the module. =head2 owner The module owner (first-come permissions). =head2 co_maintainers Other maintainers with permissions to this module. =head1 AUTHORS =over 4 =item * Sawyer X =item * Mickey Nasriachi =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Sawyer X. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut MetaCPAN-Client-2.023000/lib/MetaCPAN/Client/DownloadURL.pm0000644000175000017500000000304313232713623022036 0ustar mickeymickeyuse strict; use warnings; package MetaCPAN::Client::DownloadURL; # ABSTRACT: A Download URL data object $MetaCPAN::Client::DownloadURL::VERSION = '2.023000'; use Moo; with 'MetaCPAN::Client::Role::Entity'; my %known_fields = ( scalar => [qw< date download_url status version >], arrayref => [], hashref => [], ); my @known_fields = map { @{ $known_fields{$_} } } qw< scalar arrayref hashref >; foreach my $field (@known_fields) { has $field => ( is => 'ro', lazy => 1, default => sub { my $self = shift; return $self->data->{$field}; }, ); } sub _known_fields { return \%known_fields } 1; __END__ =pod =encoding UTF-8 =head1 NAME MetaCPAN::Client::DownloadURL - A Download URL data object =head1 VERSION version 2.023000 =head1 SYNOPSIS my $download_url = $mcpan->download_url('Moose'); =head1 DESCRIPTION A MetaCPAN download_url entity object. =head1 ATTRIBUTES =head2 date Returns the date of the release that this URL refers to. =head2 download_url The actual download URL. =head2 status The release status, which is something like C or C =head2 version The version number for the distribution. =head1 AUTHORS =over 4 =item * Sawyer X =item * Mickey Nasriachi =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Sawyer X. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut MetaCPAN-Client-2.023000/lib/MetaCPAN/Client/File.pm0000644000175000017500000001362413232713623020571 0ustar mickeymickeyuse strict; use warnings; package MetaCPAN::Client::File; # ABSTRACT: A File data object $MetaCPAN::Client::File::VERSION = '2.023000'; use Moo; use Carp; with 'MetaCPAN::Client::Role::Entity'; my %known_fields = ( scalar => [qw< abstract author authorized binary date deprecated description directory distribution documentation download_url id indexed level maturity mime name path release sloc slop status version version_numified >], arrayref => [qw< module pod_lines >], hashref => [qw< stat >], ); my @known_fields = map { @{ $known_fields{$_} } } qw< scalar arrayref hashref >; foreach my $field (@known_fields) { has $field => ( is => 'ro', lazy => 1, default => sub { my $self = shift; return $self->data->{$field}; }, ); } sub _known_fields { return \%known_fields } sub pod { my $self = shift; my $ctype = shift || "plain"; $ctype = lc($ctype); grep { $ctype eq $_ } qw or croak "wrong content-type for POD requested"; my $name = $self->module->[0]{name}; return unless $name; require MetaCPAN::Client::Request; return MetaCPAN::Client::Request->new->fetch( "pod/${name}?content-type=text/${ctype}" ); } sub source { my $self = shift; my $author = $self->author; my $release = $self->release; my $path = $self->path; require MetaCPAN::Client::Request; return MetaCPAN::Client::Request->new->fetch( "source/${author}/${release}/${path}" ); } sub metacpan_url { my $self = shift; sprintf("https://metacpan.org/source/%s/%s/%s", $self->author, $self->release, $self->path ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME MetaCPAN::Client::File - A File data object =head1 VERSION version 2.023000 =head1 DESCRIPTION A MetaCPAN file entity object. =head1 ATTRIBUTES =head2 status Returns a release status like C, C, or C. =head2 date An ISO8601 datetime string like C<2016-11-19T12:41:46> indicating when the file was uploaded. =head2 author The author's PAUSE id. =head2 maturity This will be either C or C. =head2 directory A boolean indicating whether or not the path represents a directory. =head2 indexed A boolean indicating whether or not the content is indexed. =head2 documentation The name of the module for which this file contains docs. This may be C =head2 id The file's internal MetaCPAN id. =head2 authorized A boolean indicating whether or not this file was part of an authorized upload. =head2 version The distribution version that contains this file. =head2 version_numified The numified version of the distribution that contains the file. =head2 release The release that contains this file, which will be something like C. =head2 binary A boolean indicating whether or not this file contains binary content. =head2 name The File's name, without any directory path included. =head2 path The file's path I, relative to the root of the archive. =head2 abstract If the file contains POD with a C section, then this attribute will include the abstract portion of the name. =head2 deprecated The deprecated field value for this file. =head2 description If the file contains POD with a C section, then this attribute will contain that description. =head2 distribution The name of the distribution that contains the file. =head2 level A 0-indexed indication of how many directories deep this file is, relative to the archive root. =head2 sloc If the file contains code, this will contain the number of lines of code in the file. =head2 slop If the file contains POD, this will contain the number of lines of POD in the file. =head2 mime The file's mime type. =head2 module If the file contains module indexed by PAUSE, then this attribute contains an arrayref of hashrefs, one for each module. The hashrefs have the following keys: =over 4 =item * name The module name. =item * indexed Whether or not the file is indexed by MetaCPAN. =item * authorized Whether or not the module is part of an authorized upload. =item * version The version of the module that this file contains. =item * version_numified The numified version of the module that this file contains. =item * associated_pod A path you can use with the C<< MetaCPAN::Client->file >> method to get the file that contains POD for this module. In most cases, that will be the same file as that one that contains this C data. =back =head2 pod_lines An arrayref. =head2 stat A hashref containing C all information about the file. The keys are: =over 4 =item * mtime The Unix epoch of the file's last modified time. =item * mode The file's mode (as an integer, not an octal representation). =item * size The file's size in bytes. =back =head2 download_url A URL for the distribution archive that contains this file. =head1 METHODS =head2 pod my $pod = $module->pod(); # default = plain my $pod = $module->pod($type); Returns the POD content for the module/file. Takes a type as argument. Supported types: B, B, B, B. =head2 source my $source = $module->source(); Returns the source code for the file. =head2 metacpan_url Returns a link to the file source page on MetaCPAN. =head1 AUTHORS =over 4 =item * Sawyer X =item * Mickey Nasriachi =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Sawyer X. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut MetaCPAN-Client-2.023000/lib/MetaCPAN/Client/Mirror.pm0000644000175000017500000000421213232713623021155 0ustar mickeymickeyuse strict; use warnings; package MetaCPAN::Client::Mirror; # ABSTRACT: A Mirror data object $MetaCPAN::Client::Mirror::VERSION = '2.023000'; use Moo; use Carp; with 'MetaCPAN::Client::Role::Entity'; my %known_fields = ( scalar => [qw< aka_name A_or_CNAME ccode city continent country dnsrr freq ftp http inceptdate name note org region reitredate rsync src tz >], arrayref => [qw< contact location >], hashref => [qw<>], ); my @known_fields = map { @{ $known_fields{$_} } } qw< scalar arrayref hashref >; foreach my $field (@known_fields) { has $field => ( is => 'ro', lazy => 1, default => sub { my $self = shift; return $self->data->{$field}; }, ); } sub _known_fields { return \%known_fields } 1; __END__ =pod =encoding UTF-8 =head1 NAME MetaCPAN::Client::Mirror - A Mirror data object =head1 VERSION version 2.023000 =head1 SYNOPSIS my $mirror = $mcpan->mirror('eutelia.it'); =head1 DESCRIPTION A MetaCPAN mirror entity object. =head1 ATTRIBUTES =head2 name The name of the mirror, which is what you passed =head2 org The organization that maintains the mirror. =head2 ftp An FTP url for the mirror. =head2 rsync An rsync url for the mirror. =head2 src =head2 city The city where the mirror is located. =head2 country The name of the country where the mirror is located. =head2 ccode The ISO country code for the mirror's country. =head2 aka_name =head2 tz =head2 note =head2 dnsrr =head2 region =head2 inceptdate =head2 freq =head2 continent =head2 http =head2 reitredate =head2 A_or_CNAME =head2 contact Array-Ref. =head2 location Array-Ref. =head1 AUTHORS =over 4 =item * Sawyer X =item * Mickey Nasriachi =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Sawyer X. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut MetaCPAN-Client-2.023000/lib/MetaCPAN/Client.pm0000644000175000017500000005213113232713623017706 0ustar mickeymickeyuse strict; use warnings; package MetaCPAN::Client; # ABSTRACT: A comprehensive, DWIM-featured client to the MetaCPAN API $MetaCPAN::Client::VERSION = '2.023000'; use Moo; use Carp; use Ref::Util qw< is_arrayref is_hashref is_ref >; use URI::Escape qw< uri_escape_utf8 >; use MetaCPAN::Client::Request; use MetaCPAN::Client::Author; use MetaCPAN::Client::Distribution; use MetaCPAN::Client::DownloadURL; use MetaCPAN::Client::Module; use MetaCPAN::Client::File; use MetaCPAN::Client::Favorite; use MetaCPAN::Client::Pod; use MetaCPAN::Client::Rating; use MetaCPAN::Client::Release; use MetaCPAN::Client::Mirror; use MetaCPAN::Client::Package; use MetaCPAN::Client::Permission; use MetaCPAN::Client::ResultSet; has request => ( is => 'ro', handles => [qw], ); my @supported_searches = qw< author distribution favorite module rating release mirror file permission package >; sub BUILDARGS { my ( $class, %args ) = @_; $args{'request'} ||= MetaCPAN::Client::Request->new( ( ua => $args{ua} )x!! $args{ua}, ( domain => $args{domain} )x!! $args{domain}, ( debug => $args{debug} )x!! $args{debug}, ); return \%args; } sub author { my $self = shift; my $arg = shift; my $params = shift; return $self->_get_or_search( 'author', $arg, $params ); } sub module { my $self = shift; my $arg = shift; my $params = shift; return $self->_get_or_search( 'module', $arg, $params ); } sub distribution { my $self = shift; my $arg = shift; my $params = shift; return $self->_get_or_search( 'distribution', $arg, $params ); } sub file { my $self = shift; my $arg = shift; my $params = shift; return $self->_get_or_search( 'file', $arg, $params ); } sub package { my $self = shift; my $arg = shift; my $params = shift; return $self->_get_or_search( 'package', $arg, $params ); } sub permission { my $self = shift; my $arg = shift; my $params = shift; return $self->_get_or_search( 'permission', $arg, $params ); } sub pod { my $self = shift; my $name = shift; my $params = shift || {}; return MetaCPAN::Client::Pod->new({ request => $self->request, name => $name, %$params }); } sub favorite { my $self = shift; my $args = shift; my $params = shift; is_hashref($args) or croak 'favorite takes a hash ref as parameter'; return $self->_search( 'favorite', $args, $params ); } sub rating { my $self = shift; my $args = shift; my $params = shift; is_hashref($args) or croak 'rating takes a hash ref as parameter'; return $self->_search( 'rating', $args, $params ); } sub release { my $self = shift; my $arg = shift; my $params = shift; return $self->_get_or_search( 'release', $arg, $params ); } sub mirror { my $self = shift; my $arg = shift; my $params = shift; return $self->_get_or_search( 'mirror', $arg, $params ); } sub reverse_dependencies { my $self = shift; my $dist = shift; $dist =~ s/::/-/g; return $self->_reverse_deps($dist); } *rev_deps = *reverse_dependencies; sub recent { my $self = shift; my $size = shift || 100; $size eq 'today' and return $self->_recent( size => 1000, filter => _filter_today() ); $size =~ /^[0-9]+$/ and return $self->_recent( size => $size ); croak "recent: invalid size value"; } sub all { my $self = shift; my $type = shift; my $params = shift; # This endpoint used to support only pluralized types (mostly) and convert # to singular types before redispatching. Now it accepts both plural and # unplural forms directly and relies on the underlying methods it # dispatches to to check types (using the global supported types array). $type =~ s/s$//; $params and !is_hashref($params) and croak "all: params must be a hashref"; if ( $params->{fields} and !is_arrayref($params->{fields}) ) { $params->{fields} = [ split /,/ => $params->{fields} ]; } return $self->$type( { __MATCH_ALL__ => 1 }, $params ); } sub download_url { my $self = shift; my $module = shift; return $self->_get( 'download_url', $module ); } sub autocomplete { my $self = shift; my $q = shift; my $res; eval { $res = $self->fetch( '/search/autocomplete?q=' . uri_escape_utf8($q) ); 1; } or do { warn $@; return []; }; return [ map { $_->{fields} } @{ $res->{hits}{hits} } ]; } sub autocomplete_suggest { my $self = shift; my $q = shift; my $res; eval { $res = $self->fetch( '/search/autocomplete/suggest?q=' . uri_escape_utf8($q) ); 1; } or do { warn $@; return []; }; return $res->{suggestions}; } ### sub _get { my $self = shift; ( scalar(@_) == 2 or ( scalar(@_) == 3 and ( !defined $_[2] or is_hashref($_[2]) ) ) ) or croak '_get takes type and search string as parameters (and an optional params hash)'; my $type = shift; my $arg = shift; my $params = shift; my $fields_filter = $self->_read_fields( $params ); my $response = $self->fetch( sprintf("%s/%s%s", $type ,$arg, $fields_filter||'') ); is_hashref($response) or croak sprintf( 'Failed to fetch %s (%s)', ucfirst($type), $arg ); $type = 'DownloadURL' if $type eq 'download_url'; my $class = 'MetaCPAN::Client::' . ucfirst($type); return $class->new_from_request($response, $self); } sub _read_fields { my $self = shift; my $params = shift; $params or return; my $fields = delete $params->{fields}; $fields or return; if ( is_arrayref($fields) ) { grep { ref $_ } @$fields and croak "fields array should not contain any refs."; return sprintf( "?fields=%s", join q{,} => @$fields ); } elsif ( !ref $fields ) { return "?fields=$fields"; } croak "invalid param: fields"; } sub _search { my $self = shift; my $type = shift; my $args = shift; my $params = shift; is_hashref($args) or croak '_search takes a hash ref as query'; ! defined $params or is_hashref($params) or croak '_search takes a hash ref as query parameters'; $params ||= {}; grep { $_ eq $type } @supported_searches or croak 'search type is not supported'; my $scroller = $self->ssearch($type, $args, $params); return MetaCPAN::Client::ResultSet->new( scroller => $scroller, type => $type, ); } sub _get_or_search { my $self = shift; my $type = shift; my $arg = shift; my $params = shift; is_hashref($arg) and return $self->_search( $type, $arg, $params ); defined $arg and !is_ref($arg) and return $self->_get($type, $arg, $params); croak "$type: invalid args (takes scalar value or search parameters hashref)"; } sub _reverse_deps { my $self = shift; my $dist = shift; my $res; eval { $res = $self->fetch( "/reverse_dependencies/dist/$dist", { size => 5000, query => { match_all => {} }, filter => { and => [ { term => { 'status' => 'latest' } }, { term => { 'authorized' => 1 } }, ] }, } ); 1; } or do { warn $@; return _empty_result_set('release'), }; return MetaCPAN::Client::ResultSet->new( items => $res->{'data'}, type => 'release', ); } sub _recent { my $self = shift; my @args = @_; my $res; eval { $res = $self->fetch( '/release/_search', { from => 0, query => { match_all => {} }, @args, sort => [ { 'date' => { order => "desc" } } ], } ); 1; } or do { warn $@; return _empty_result_set('release'); }; return MetaCPAN::Client::ResultSet->new( items => $res->{'hits'}{'hits'}, type => 'release', ); } sub _filter_today { return { range => { date => { from => "now/1d+0h" } } }; } sub _empty_result_set { my $type = shift; return MetaCPAN::Client::ResultSet->new( items => [], type => $type, ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME MetaCPAN::Client - A comprehensive, DWIM-featured client to the MetaCPAN API =head1 VERSION version 2.023000 =head1 SYNOPSIS # simple usage my $mcpan = MetaCPAN::Client->new(); my $author = $mcpan->author('XSAWYERX'); my $dist = $mcpan->distribution('MetaCPAN-Client'); # advanced usage with cache (contributed by Kent Fredric) use CHI; use WWW::Mechanize::Cached; use HTTP::Tiny::Mech; use MetaCPAN::Client; my $mcpan = MetaCPAN::Client->new( ua => HTTP::Tiny::Mech->new( mechua => WWW::Mechanize::Cached->new( cache => CHI->new( driver => 'File', root_dir => '/tmp/metacpan-cache', ), ), ), ); # now $mcpan caches results =head1 DESCRIPTION This is a hopefully-complete API-compliant client to MetaCPAN (L) with DWIM capabilities, to make your life easier. =head1 ATTRIBUTES =head2 request Internal attribute representing the request object making the request to MetaCPAN and analyzing the results. You probably don't want to set this, nor should you have any usage of it. =head2 ua If provided, L will use the user agent object instead of the default, which is L. Then it can be used to fetch the user agent object used by L. =head2 domain If given, will be used to alter the API domain. =head2 debug If given, errors will include some low-level detailed message. =head1 METHODS =head2 author my $author = $mcpan->author('XSAWYERX'); my $author = $mcpan->author($search_spec); Finds an author by either its PAUSE ID or by a search spec defined by a hash reference. Since it is common to many other searches, it is explained below under C. Returns a L object on a simple search (PAUSE ID), or a L object propagated with L objects on a complex (L) search. =head2 module my $module = $mcpan->module('MetaCPAN::Client'); my $module = $mcpan->module($search_spec); Finds a module by either its module name or by a search spec defined by a hash reference. Since it is common to many other searches, it is explained below under C. Returns a L object on a simple search (module name), or a L object propagated with L objects on a complex (L) search. =head2 distribution my $dist = $mcpan->distribution('MetaCPAN-Client'); my $dist = $mcpan->distribution($search_spec); Finds a distribution by either its distribution name or by a search spec defined by a hash reference. Since it is common to many other searches, it is explained below under C. Returns a L object on a simple search (distribution name), or a L object propagated with L objects on a complex (L) search. =head2 file Returns a L object. =head2 favorite my $favorite = $mcpan->favorite({ distribution => 'Moose' }); Returns a L object containing L results. =head2 rating my $rating = $mcpan->rating({ distribution => 'Moose' }); Returns a L object containing L results. =head2 release my $release = $mcpan->release('MetaCPAN-Client'); my $release = $mcpan->release($search_spec); Finds a release by either its distribution name or by a search spec defined by a hash reference. Since it is common to many other searches, it is explained below under C. Returns a L object on a simple search (release name), or a L object propagated with L objects on a complex (L) search. =head2 mirror my $mirror = $mcpan->mirror('kr.freebsd.org'); Returns a L object. =head2 package my $package = $mcpan->package('MooseX::Types'); Returns a L object. =head2 permission my $permission = $mcpan->permission('MooseX::Types'); Returns a L object. =head2 reverse_dependencies my $deps = $mcpan->reverse_dependencies('Search::Elasticsearch'); all L objects of releases that are directly dependent on a given module, returned as L. =head2 rev_deps Alias to C described above. =head2 autocomplete my $ac = $mcpan->autocomplete('Danc'); Call the search/autocomplete endpoint with a query string. Returns an array reference. =head2 autocomplete_suggest my $ac = $mcpan->autocomplete_suggest('Moo'); Call the search/autocomplete/suggest endpoint with a query string. Returns an array reference. =head2 recent my $recent = $mcpan->recent(10); my $recent = $mcpan->recent('today'); return the latest N releases, or all releases from today. returns a L of L. =head2 pod Get POD for given file/module name. returns a L object, which supports various output formats (html, plain, x_pod & x_markdown). my $pod = $mcpan->pod('Moo')->html; my $pod = $mcpan->pod('Moo', { url_prefix => $prefix })->html; =head2 download_url Retrieve information from the 'download_url' endpoint my $download_url = $mcpan->download_url('Moose') Returns a L object =head2 all Retrieve all matches for authors/modules/distributions/favorites or releases. my $all_releases = $mcpan->all('releases') When called with a second parameter containing a hash ref, will support the following keys: =head3 fields See SEARCH PARAMS. my $all_releases = $mcpan->all('releases', { fields => [...] }) =head3 _source See SEARCH PARAMS. my $all_releases = $mcpan->all('releases', { _source => [...] }) =head3 es_filter Pass a raw Elasticsearch filter structure to reduce the number of elements returned by the query. my $some_releases = $mcpan->all('releases', { es_filter => {...} }) =head2 BUILDARGS Internal construction wrapper. Do not use. =head1 SEARCH PARAMS Most searches take params as an optional hash-ref argument. these params will be passed to the search action. In non-scrolled searches, 'fields' filter is the only supported parameter ATM. =head2 fields Filter the fields to reduce the amount of data pulled from MetaCPAN. can be passed as a csv list or an array ref. my $module = $mcpan->module('Moose', { fields => "version,author" }); my $module = $mcpan->module('Moose', { fields => [qw/version author/] }); =head2 _source Note: this param and its description are a bit too Elasticsearch specific. just like 'es_filter' - use only if you know what you're dealing with. Some fields are not indexed in Elasticsearch but stored as part of the entire document. These fields can still be read, but without the internal Elasticsearch optimizations and the server will internally read the whole document. Why do we even need those? because we don't index everything and some things we can't to begin with (like non-leaf fields that hold a structure) my $module = $mcpan->all('releases', { _source => "stat" }); =head2 scroller_time Note: please use with caution. This parameter will set the maximum lifetime of the Elasticsearch scroller on the server (default = '5m'). Normally you do not need to set this value (as tweaking this value can affect resources on the server). In case you do, you probably need to check the efficiency of your code/queries. (Feel free to reach out to us for assistance). my $module = $mcpan->all('releases', { scroller_time => '3m' }); =head2 scroller_size Note: please use with caution. This parameter will set the buffer size to be pulled from Elasticsearch when scrolling (default = 1000). This will affect query performance and memory usage, but you will still get an iterator back to fetch one object at a time. my $module = $mcpan->all('releases', { scroller_size => 500 }); =head3 sort Pass a raw Elasticsearch sort specification for the query. my $some_releases = $mcpan->all('releases', { sort => [{ date => { order => 'desc' } }] }) Note: this param and is a bit too specific to Elasticsearch. Just like L, only use this if you know what you're dealing with. =head1 SEARCH SPEC The hash-based search spec is common to many searches. It is quite feature-rich and allows you to disambiguate different types of searches. Basic search specs just contain a hash of keys and values: my $author = $mcpan->author( { name => 'Micha Nasriachi' } ); # the following is the same as ->author('MICKEY') my $author = $mcpan->author( { pauseid => 'MICKEY' } ); # find all people named Dave, not covering Davids # will return a resultset my $daves = $mcpan->author( { name => 'Dave *' } ); =head2 OR If you want to do a more complicated query that has an I condition, such as "this or that", you can use the following syntax with the C key: # any author named "Dave" or "David" my $daves = $mcpan->author( { either => [ { name => 'Dave *' }, { name => 'David *' }, ] } ); =head2 AND If you want to do a more complicated query that has an I condition, such as "this and that", you can use the following syntax with the C key: # any users named 'John' with a Gmail account my $johns = $mcpan->author( { all => [ { name => 'John *' }, { email => '*gmail.com' }, ] } ); If you want to do something even more complicated, You can also nest your queries, e.g.: my $gmail_daves_or_cpan_sams = $mcpan->author( { either => [ { all => [ { name => 'Dave *' }, { email => '*gmail.com' } ] }, { all => [ { name => 'Sam *' }, { email => '*cpan.org' } ] }, ], } ); =head2 NOT If you want to filter out some of the results of an either/all query adding a I filter condition, such as "not these", you can use the following syntax with the C key: # any author named "Dave" or "David" my $daves = $mcpan->author( { either => [ { name => 'Dave *' }, { name => 'David *' }, ], not => [ { email => '*gmail.com' }, ], } ); =head1 DESIGN This module has three purposes: =over 4 =item * Provide 100% of the MetaCPAN API This module will be updated regularly on every MetaCPAN API change, and intends to provide the user with as much of the API as possible, no shortcuts. If it's documented in the API, you should be able to do it. Because of this design decision, this module has an official MetaCPAN namespace with the blessing of the MetaCPAN developers. Notice this module currently only provides the beta API, not the old soon-to-be-deprecated API. =item * Be lightweight, to allow flexible usage While many modules would help make writing easier, it's important to take into account how they affect your compile-time, run-time, overall memory consumption, and CPU usage. By providing a slim interface implementation, more users are able to use this module, such as long-running processes (like daemons), CLI or GUI applications, cron jobs, and more. =item * DWIM While it's possible to access the methods defined by the API spec, there's still a matter of what you're really trying to achieve. For example, when searching for I<"Dave">, you want to find both I and I (and any other I), but you also want to search for a PAUSE ID of I, if one exists. This is where DWIM comes in. This module provides you with additional generic methods which will try to do what they think you want. Of course, this does not prevent you from manually using the API methods. You still have full control over that, if that's what you wish. You can (and should) read up on the general methods, which will explain how their DWIMish nature works, and what searches they run. =back =head1 AUTHORS =over 4 =item * Sawyer X =item * Mickey Nasriachi =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Sawyer X. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut MetaCPAN-Client-2.023000/dist.ini0000644000175000017500000000151313232713623015476 0ustar mickeymickeyname = MetaCPAN-Client author = Sawyer X author = Mickey Nasriachi license = Perl_5 copyright_holder = Sawyer X copyright_year = 2016 version = 2.023000 [@Starter] -remove = GatherDir MakeMaker.eumm_version = 7.1101 [PodCoverageTests] [Git::GatherDir] [Prereqs::FromCPANfile] [PodWeaver] [MinimumPerlFast] [ReadmeAnyFromPod / pod.root] filename = README.pod type = pod location = root [CheckChangeLog] [PkgVersion] [MetaResources] bugtracker.web = https://github.com/metacpan/metacpan-client/issues repository.url = https://github.com/metacpan/metacpan-client.git repository.web = https://github.com/metacpan/metacpan-client repository.type = git x_IRC = irc://irc.perl.org/#metacpan x_WebIRC = https://chat.mibbit.com/#metacpan@irc.perl.org [Git::Tag] [Git::Push] MetaCPAN-Client-2.023000/Makefile.PL0000644000175000017500000000400713232713623016005 0ustar mickeymickey# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v6.008. use strict; use warnings; use 5.010; use ExtUtils::MakeMaker 7.1101; my %WriteMakefileArgs = ( "ABSTRACT" => "A comprehensive, DWIM-featured client to the MetaCPAN API", "AUTHOR" => "Sawyer X , Mickey Nasriachi ", "CONFIGURE_REQUIRES" => { "ExtUtils::MakeMaker" => "7.1101" }, "DISTNAME" => "MetaCPAN-Client", "LICENSE" => "perl", "MIN_PERL_VERSION" => "5.010", "NAME" => "MetaCPAN::Client", "PREREQ_PM" => { "Carp" => 0, "HTTP::Tiny" => "0.056", "IO::Socket::SSL" => "1.42", "JSON::MaybeXS" => 0, "JSON::PP" => 0, "Moo" => 0, "Moo::Role" => 0, "Net::SSLeay" => "1.49", "Ref::Util" => 0, "Safe::Isa" => 0, "Type::Tiny" => 0, "URI::Escape" => 0, "strict" => 0, "warnings" => 0 }, "TEST_REQUIRES" => { "ExtUtils::MakeMaker" => 0, "File::Spec" => 0, "LWP::Protocol::https" => 0, "Test::Fatal" => 0, "Test::More" => 0, "Test::Needs" => "0.002005", "base" => 0, "blib" => "1.01" }, "VERSION" => "2.023000", "test" => { "TESTS" => "t/*.t t/api/*.t" } ); my %FallbackPrereqs = ( "Carp" => 0, "ExtUtils::MakeMaker" => 0, "File::Spec" => 0, "HTTP::Tiny" => "0.056", "IO::Socket::SSL" => "1.42", "JSON::MaybeXS" => 0, "JSON::PP" => 0, "LWP::Protocol::https" => 0, "Moo" => 0, "Moo::Role" => 0, "Net::SSLeay" => "1.49", "Ref::Util" => 0, "Safe::Isa" => 0, "Test::Fatal" => 0, "Test::More" => 0, "Test::Needs" => "0.002005", "Type::Tiny" => 0, "URI::Escape" => 0, "base" => 0, "blib" => "1.01", "strict" => 0, "warnings" => 0 ); unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) { delete $WriteMakefileArgs{TEST_REQUIRES}; delete $WriteMakefileArgs{BUILD_REQUIRES}; $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs; } delete $WriteMakefileArgs{CONFIGURE_REQUIRES} unless eval { ExtUtils::MakeMaker->VERSION(6.52) }; WriteMakefile(%WriteMakefileArgs); MetaCPAN-Client-2.023000/META.json0000644000175000017500000004553313232713623015465 0ustar mickeymickey{ "abstract" : "A comprehensive, DWIM-featured client to the MetaCPAN API", "author" : [ "Sawyer X ", "Mickey Nasriachi " ], "dynamic_config" : 0, "generated_by" : "Dist::Zilla version 6.008, CPAN::Meta::Converter version 2.150005", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "MetaCPAN-Client", "no_index" : { "directory" : [ "eg", "examples", "inc", "share", "t", "xt" ] }, "prereqs" : { "configure" : { "requires" : { "ExtUtils::MakeMaker" : "7.1101" } }, "develop" : { "requires" : { "File::Spec" : "0", "HTTP::Tiny::Mech" : "1.001002", "IO::Handle" : "0", "IPC::Open3" : "0", "LWP::Protocol::https" : "0", "Pod::Coverage::TrustPod" : "0", "Test::More" : "0", "Test::Pod" : "1.41", "Test::Pod::Coverage" : "1.08", "WWW::Mechanize::Cached" : "1.50" } }, "runtime" : { "requires" : { "Carp" : "0", "HTTP::Tiny" : "0.056", "IO::Socket::SSL" : "1.42", "JSON::MaybeXS" : "0", "JSON::PP" : "0", "Moo" : "0", "Moo::Role" : "0", "Net::SSLeay" : "1.49", "Ref::Util" : "0", "Safe::Isa" : "0", "Type::Tiny" : "0", "URI::Escape" : "0", "perl" : "5.010", "strict" : "0", "warnings" : "0" } }, "test" : { "recommends" : { "CPAN::Meta" : "2.120900", "HTTP::Tiny::Mech" : "1.001002", "WWW::Mechanize::Cached" : "1.50" }, "requires" : { "ExtUtils::MakeMaker" : "0", "File::Spec" : "0", "LWP::Protocol::https" : "0", "Test::Fatal" : "0", "Test::More" : "0", "Test::Needs" : "0.002005", "base" : "0", "blib" : "1.01" } } }, "provides" : { "MetaCPAN::Client" : { "file" : "lib/MetaCPAN/Client.pm", "version" : "2.023000" }, "MetaCPAN::Client::Author" : { "file" : "lib/MetaCPAN/Client/Author.pm", "version" : "2.023000" }, "MetaCPAN::Client::Distribution" : { "file" : "lib/MetaCPAN/Client/Distribution.pm", "version" : "2.023000" }, "MetaCPAN::Client::DownloadURL" : { "file" : "lib/MetaCPAN/Client/DownloadURL.pm", "version" : "2.023000" }, "MetaCPAN::Client::Favorite" : { "file" : "lib/MetaCPAN/Client/Favorite.pm", "version" : "2.023000" }, "MetaCPAN::Client::File" : { "file" : "lib/MetaCPAN/Client/File.pm", "version" : "2.023000" }, "MetaCPAN::Client::Mirror" : { "file" : "lib/MetaCPAN/Client/Mirror.pm", "version" : "2.023000" }, "MetaCPAN::Client::Module" : { "file" : "lib/MetaCPAN/Client/Module.pm", "version" : "2.023000" }, "MetaCPAN::Client::Package" : { "file" : "lib/MetaCPAN/Client/Package.pm", "version" : "2.023000" }, "MetaCPAN::Client::Permission" : { "file" : "lib/MetaCPAN/Client/Permission.pm", "version" : "2.023000" }, "MetaCPAN::Client::Pod" : { "file" : "lib/MetaCPAN/Client/Pod.pm", "version" : "2.023000" }, "MetaCPAN::Client::Rating" : { "file" : "lib/MetaCPAN/Client/Rating.pm", "version" : "2.023000" }, "MetaCPAN::Client::Release" : { "file" : "lib/MetaCPAN/Client/Release.pm", "version" : "2.023000" }, "MetaCPAN::Client::Request" : { "file" : "lib/MetaCPAN/Client/Request.pm", "version" : "2.023000" }, "MetaCPAN::Client::ResultSet" : { "file" : "lib/MetaCPAN/Client/ResultSet.pm", "version" : "2.023000" }, "MetaCPAN::Client::Role::Entity" : { "file" : "lib/MetaCPAN/Client/Role/Entity.pm", "version" : "2.023000" }, "MetaCPAN::Client::Role::HasUA" : { "file" : "lib/MetaCPAN/Client/Role/HasUA.pm", "version" : "2.023000" }, "MetaCPAN::Client::Scroll" : { "file" : "lib/MetaCPAN/Client/Scroll.pm", "version" : "2.023000" }, "MetaCPAN::Client::Types" : { "file" : "lib/MetaCPAN/Client/Types.pm", "version" : "2.023000" } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/metacpan/metacpan-client/issues" }, "repository" : { "type" : "git", "url" : "https://github.com/metacpan/metacpan-client.git", "web" : "https://github.com/metacpan/metacpan-client" }, "x_IRC" : "irc://irc.perl.org/#metacpan", "x_WebIRC" : "https://chat.mibbit.com/#metacpan@irc.perl.org" }, "version" : "2.023000", "x_Dist_Zilla" : { "perl" : { "version" : "5.022001" }, "plugins" : [ { "class" : "Dist::Zilla::Plugin::PruneCruft", "name" : "@Starter/PruneCruft", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::ManifestSkip", "name" : "@Starter/ManifestSkip", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::MetaConfig", "name" : "@Starter/MetaConfig", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::MetaProvides::Package", "config" : { "Dist::Zilla::Plugin::MetaProvides::Package" : { "finder_objects" : [ { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : "@Starter/MetaProvides::Package/AUTOVIV/:InstallModulesPM", "version" : "6.008" } ], "include_underscores" : 0 }, "Dist::Zilla::Role::MetaProvider::Provider" : { "$Dist::Zilla::Role::MetaProvider::Provider::VERSION" : "2.002003", "inherit_missing" : "1", "inherit_version" : "1", "meta_noindex" : "1" }, "Dist::Zilla::Role::ModuleMetadata" : { "Module::Metadata" : "1.000027", "version" : "0.004" } }, "name" : "@Starter/MetaProvides::Package", "version" : "2.004002" }, { "class" : "Dist::Zilla::Plugin::MetaNoIndex", "name" : "@Starter/MetaNoIndex", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::MetaYAML", "name" : "@Starter/MetaYAML", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::MetaJSON", "name" : "@Starter/MetaJSON", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::License", "name" : "@Starter/License", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod", "config" : { "Dist::Zilla::Role::FileWatcher" : { "version" : "0.006" } }, "name" : "@Starter/ReadmeAnyFromPod", "version" : "0.161170" }, { "class" : "Dist::Zilla::Plugin::ExecDir", "name" : "@Starter/ExecDir", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::ShareDir", "name" : "@Starter/ShareDir", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::PodSyntaxTests", "name" : "@Starter/PodSyntaxTests", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::Test::ReportPrereqs", "name" : "@Starter/Test::ReportPrereqs", "version" : "0.025" }, { "class" : "Dist::Zilla::Plugin::Test::Compile", "config" : { "Dist::Zilla::Plugin::Test::Compile" : { "bail_out_on_fail" : "0", "fail_on_warning" : "author", "fake_home" : 0, "filename" : "xt/author/00-compile.t", "module_finder" : [ ":InstallModules" ], "needs_display" : 0, "phase" : "develop", "script_finder" : [ ":PerlExecFiles" ], "skips" : [] } }, "name" : "@Starter/Test::Compile", "version" : "2.054" }, { "class" : "Dist::Zilla::Plugin::MakeMaker", "config" : { "Dist::Zilla::Role::TestRunner" : { "default_jobs" : 1 } }, "name" : "@Starter/MakeMaker", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::Manifest", "name" : "@Starter/Manifest", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::TestRelease", "name" : "@Starter/TestRelease", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::RunExtraTests", "config" : { "Dist::Zilla::Role::TestRunner" : { "default_jobs" : 1 } }, "name" : "@Starter/RunExtraTests", "version" : "0.029" }, { "class" : "Dist::Zilla::Plugin::ConfirmRelease", "name" : "@Starter/ConfirmRelease", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::UploadToCPAN", "name" : "@Starter/UploadToCPAN", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::PodCoverageTests", "name" : "PodCoverageTests", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::Git::GatherDir", "config" : { "Dist::Zilla::Plugin::GatherDir" : { "exclude_filename" : [], "exclude_match" : [], "follow_symlinks" : 0, "include_dotfiles" : 0, "prefix" : "", "prune_directory" : [], "root" : "." }, "Dist::Zilla::Plugin::Git::GatherDir" : { "include_untracked" : 0 } }, "name" : "Git::GatherDir", "version" : "2.039" }, { "class" : "Dist::Zilla::Plugin::Prereqs::FromCPANfile", "name" : "Prereqs::FromCPANfile", "version" : "0.08" }, { "class" : "Dist::Zilla::Plugin::PodWeaver", "config" : { "Dist::Zilla::Plugin::PodWeaver" : { "finder" : [ ":InstallModules", ":ExecFiles" ], "plugins" : [ { "class" : "Pod::Weaver::Plugin::EnsurePod5", "name" : "@CorePrep/EnsurePod5", "version" : "4.014" }, { "class" : "Pod::Weaver::Plugin::H1Nester", "name" : "@CorePrep/H1Nester", "version" : "4.014" }, { "class" : "Pod::Weaver::Plugin::SingleEncoding", "name" : "@Default/SingleEncoding", "version" : "4.014" }, { "class" : "Pod::Weaver::Section::Name", "name" : "@Default/Name", "version" : "4.014" }, { "class" : "Pod::Weaver::Section::Version", "name" : "@Default/Version", "version" : "4.014" }, { "class" : "Pod::Weaver::Section::Region", "name" : "@Default/prelude", "version" : "4.014" }, { "class" : "Pod::Weaver::Section::Generic", "name" : "SYNOPSIS", "version" : "4.014" }, { "class" : "Pod::Weaver::Section::Generic", "name" : "DESCRIPTION", "version" : "4.014" }, { "class" : "Pod::Weaver::Section::Generic", "name" : "OVERVIEW", "version" : "4.014" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "ATTRIBUTES", "version" : "4.014" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "METHODS", "version" : "4.014" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "FUNCTIONS", "version" : "4.014" }, { "class" : "Pod::Weaver::Section::Leftovers", "name" : "@Default/Leftovers", "version" : "4.014" }, { "class" : "Pod::Weaver::Section::Region", "name" : "@Default/postlude", "version" : "4.014" }, { "class" : "Pod::Weaver::Section::Authors", "name" : "@Default/Authors", "version" : "4.014" }, { "class" : "Pod::Weaver::Section::Legal", "name" : "@Default/Legal", "version" : "4.014" } ] } }, "name" : "PodWeaver", "version" : "4.008" }, { "class" : "Dist::Zilla::Plugin::MinimumPerlFast", "name" : "MinimumPerlFast", "version" : "0.003" }, { "class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod", "config" : { "Dist::Zilla::Role::FileWatcher" : { "version" : "0.006" } }, "name" : "pod.root", "version" : "0.161170" }, { "class" : "Dist::Zilla::Plugin::CheckChangeLog", "name" : "CheckChangeLog", "version" : "0.02" }, { "class" : "Dist::Zilla::Plugin::PkgVersion", "name" : "PkgVersion", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::MetaResources", "name" : "MetaResources", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::Git::Tag", "config" : { "Dist::Zilla::Plugin::Git::Tag" : { "branch" : null, "changelog" : "Changes", "signed" : 0, "tag" : "v2.023000", "tag_format" : "v%v", "tag_message" : "v%v" }, "Dist::Zilla::Role::Git::Repo" : { "repo_root" : "." }, "Dist::Zilla::Role::Git::StringFormatter" : { "time_zone" : "local" } }, "name" : "Git::Tag", "version" : "2.039" }, { "class" : "Dist::Zilla::Plugin::Git::Push", "config" : { "Dist::Zilla::Plugin::Git::Push" : { "push_to" : [ "origin" ], "remotes_must_exist" : 1 }, "Dist::Zilla::Role::Git::Repo" : { "repo_root" : "." } }, "name" : "Git::Push", "version" : "2.039" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":InstallModules", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":IncModules", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":TestFiles", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":ExtraTestFiles", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":ExecFiles", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":PerlExecFiles", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":ShareFiles", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":MainModule", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":AllFiles", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":NoFiles", "version" : "6.008" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : "@Starter/MetaProvides::Package/AUTOVIV/:InstallModulesPM", "version" : "6.008" } ], "zilla" : { "class" : "Dist::Zilla::Dist::Builder", "config" : { "is_trial" : "0" }, "version" : "6.008" } }, "x_serialization_backend" : "Cpanel::JSON::XS version 3.0217" } MetaCPAN-Client-2.023000/cpanfile0000644000175000017500000000162613232713623015543 0ustar mickeymickeyrequires "Carp" => "0"; requires "HTTP::Tiny" => "0.056"; requires "IO::Socket::SSL" => "1.42"; requires "JSON::MaybeXS" => "0"; requires "JSON::PP" => "0"; requires "Moo" => "0"; requires "Moo::Role" => "0"; requires "Net::SSLeay" => "1.49"; requires "Ref::Util" => "0"; requires "Safe::Isa" => "0"; requires "Type::Tiny" => "0"; requires "URI::Escape"; requires "perl" => "5.010"; requires "strict" => "0"; requires "warnings" => "0"; on 'test' => sub { requires "Test::Fatal" => "0"; requires "Test::More" => "0"; requires "Test::Needs" => "0.002005"; requires "base" => "0"; requires "blib" => "1.01"; requires "LWP::Protocol::https" => "0"; recommends "HTTP::Tiny::Mech" => "1.001002"; recommends "WWW::Mechanize::Cached" => "1.50"; }; on 'develop' => sub { requires "HTTP::Tiny::Mech" => "1.001002"; requires "LWP::Protocol::https" => "0"; requires "WWW::Mechanize::Cached" => "1.50"; }; MetaCPAN-Client-2.023000/t/0000755000175000017500000000000013232713623014275 5ustar mickeymickeyMetaCPAN-Client-2.023000/t/request.t0000644000175000017500000000142413232713623016153 0ustar mickeymickey#!perl use strict; use warnings; use Test::More tests => 7; use MetaCPAN::Client; use MetaCPAN::Client::Request; my $req = MetaCPAN::Client::Request->new( domain => 'https://mydomain' ); isa_ok( $req, 'MetaCPAN::Client::Request' ); can_ok( $req, qw, ); is( $req->domain, 'https://mydomain', 'Correct domain' ); is( $req->base_url, 'https://mydomain', 'Correct base_url' ); isa_ok( $req->ua, 'HTTP::Tiny' ); my $ver = $MetaCPAN::Client::VERSION || 'xx'; is_deeply( $req->ua_args, [ agent => "MetaCPAN::Client/$ver" ], 'Correct UA args', ); my $client = MetaCPAN::Client->new( domain => 'foo' ); is ( $client->request->domain, 'foo', 'domain set in request' ); MetaCPAN-Client-2.023000/t/result_custom.t0000644000175000017500000000202413232713623017370 0ustar mickeymickey#!perl use strict; use warnings; use Test::More tests => 5; use Test::Fatal qw( exception ); use MetaCPAN::Client; use MetaCPAN::Client::ResultSet; { package Test::Result; use Moo; with 'MetaCPAN::Client::Role::Entity'; sub new_from_request { my ( $class, $request, $client ) = @_; return $class->new( ( defined $client ? ( client => $client ) : () ), data => $request, ); } sub _known_fields { +{} } } my $client = MetaCPAN::Client->new(); my $scroll = $client->ssearch( 'author', { pauseid => 'KENTNL' } ); my $rs = MetaCPAN::Client::ResultSet->new( class => 'Test::Result', scroller => $scroll, ); isa_ok( $rs, 'MetaCPAN::Client::ResultSet' ); can_ok( $rs, qw ); my $item; is( exception { $item = $rs->next; 1 }, undef, "no fail on next" ); isa_ok( $item, 'Test::Result' ); my $ex; isnt( $ex = exception { MetaCPAN::Client::ResultSet->new( scroller => $scroll ) }, undef, 'Must fail is neither class or type are passed' ); MetaCPAN-Client-2.023000/t/api/0000755000175000017500000000000013232713623015046 5ustar mickeymickeyMetaCPAN-Client-2.023000/t/api/_get.t0000644000175000017500000000257013232713623016155 0ustar mickeymickey#!perl use strict; use warnings; use Test::More tests => 13; use Test::Fatal; use lib '.'; use t::lib::Functions; { no warnings qw; *MetaCPAN::Client::Author::new_from_request = sub { my ( $self, $res ) = @_; ::isa_ok( $self, 'MetaCPAN::Client::Author' ); ::is_deeply( $res, { hello => 'world' }, 'Correct response' ); return 'ok'; }; my $count = 0; *MetaCPAN::Client::fetch = sub { my ( $self, $path ) = @_; ::isa_ok( $self, 'MetaCPAN::Client' ); ::is( $path, 'author/myarg', 'Correct path' ); $count++ == 0 and return; return { hello => 'world' }; }; } my $mc = mcpan(); can_ok( $mc, '_get' ); like( exception { $mc->_get() }, qr/^_get takes type and search string as parameters/, 'Failed with no params', ); like( exception { $mc->_get('wah') }, qr/^_get takes type and search string as parameters/, 'Failed with one param', ); like( exception { $mc->_get('wah', 'wah', 'wah') }, qr/^_get takes type and search string as parameters/, 'Failed with more than two params', ); # call fetch and fail like( exception { $mc->_get( 'author', 'myarg' ) }, qr/^Failed to fetch Author \(myarg\)/, 'Correct failure', ); # call fetch and succeed my $res = $mc->_get( 'author', 'myarg' ); is( $res, 'ok', 'Correct result' ); MetaCPAN-Client-2.023000/t/api/distribution.t0000644000175000017500000000104713232713623017754 0ustar mickeymickey#!perl use strict; use warnings; use Test::More tests => 9; use Test::Fatal; use Ref::Util qw< is_hashref >; use lib '.'; use t::lib::Functions; my $mc = mcpan(); can_ok( $mc, 'distribution' ); my $dist = $mc->distribution('Business-ISBN'); isa_ok( $dist, 'MetaCPAN::Client::Distribution' ); can_ok( $dist, 'name' ); is( $dist->name, 'Business-ISBN', 'Correct distribution' ); can_ok( $dist, 'rt' ); ok( is_hashref( $dist->rt ), 'rt returns a hashref' ); can_ok( $dist, 'github' ); ok( is_hashref( $dist->github ), 'github returns a hashref' ); MetaCPAN-Client-2.023000/t/api/pod.t0000644000175000017500000000047513232713623016023 0ustar mickeymickey#!perl use strict; use warnings; use Test::More tests => 5; use lib '.'; use t::lib::Functions; my $mc = mcpan(); can_ok( $mc, 'pod' ); my $pod = $mc->pod('MetaCPAN::API'); isa_ok( $pod, 'MetaCPAN::Client::Pod' ); can_ok( $pod, qw ); like( $pod->x_pod, qr/=head1/, 'got pod' ); MetaCPAN-Client-2.023000/t/api/rating.t0000644000175000017500000000104413232713623016516 0ustar mickeymickey#!perl use strict; use warnings; use Test::More tests => 7; use Test::Fatal; use lib '.'; use t::lib::Functions; my $mc = mcpan(); can_ok( $mc, 'rating' ); my $rs = $mc->rating( { distribution => 'Moose' } ); isa_ok( $rs, 'MetaCPAN::Client::ResultSet' ); can_ok( $rs, 'next' ); my $rating = $rs->next; isa_ok( $rating, 'MetaCPAN::Client::Rating' ); can_ok( $rating, 'distribution' ); is( $rating->distribution, 'Moose', 'Correct distribution' ); __END__ can_ok( $rs, 'name' ); is( $rating->name, 'MetaCPAN-Client', 'Correct distribution' ); MetaCPAN-Client-2.023000/t/api/package.t0000644000175000017500000000127513232713623016633 0ustar mickeymickey#!perl use strict; use warnings; use Test::More tests => 10; use Ref::Util qw< is_arrayref is_ref >; use lib '.'; use t::lib::Functions; my $mc = mcpan(); can_ok( $mc, 'package' ); my $pack = $mc->package('MooseX::Types'); isa_ok( $pack, 'MetaCPAN::Client::Package' ); can_ok( $pack, qw< module_name file distribution version author > ); ok( !is_ref($pack->module_name), "module_name is not a ref"); ok( !is_ref($pack->file), "file is not a ref"); ok( !is_ref($pack->distribution), "distribution is not a ref"); ok( !is_ref($pack->version), "version is not a ref"); ok( !is_ref($pack->dist_version), "version is not a ref"); ok( !is_ref($pack->author), "author is not a ref"); MetaCPAN-Client-2.023000/t/api/download_url.t0000644000175000017500000000054013232713623017723 0ustar mickeymickey#!perl use strict; use warnings; use Test::More tests => 7; use Test::Fatal; use lib '.'; use t::lib::Functions; my $mc = mcpan(); can_ok( $mc, 'rating' ); my $rs = $mc->download_url( 'Moose' ); isa_ok( $rs, 'MetaCPAN::Client::DownloadURL' ); can_ok( $rs, 'date' ); can_ok( $rs, 'download_url' ); can_ok( $rs, 'status' ); can_ok( $rs, 'version' ); MetaCPAN-Client-2.023000/t/api/permission.t0000644000175000017500000000101413232713623017417 0ustar mickeymickey#!perl use strict; use warnings; use Test::More tests => 7; use Ref::Util qw< is_arrayref is_ref >; use lib '.'; use t::lib::Functions; my $mc = mcpan(); can_ok( $mc, 'permission' ); my $perm = $mc->permission('MooseX::Types'); isa_ok( $perm, 'MetaCPAN::Client::Permission' ); can_ok( $perm, qw< module_name owner co_maintainers > ); ok( !is_ref($perm->module_name), "module_name is not a ref"); ok( !is_ref($perm->owner), "owner is not a ref"); ok( is_arrayref($perm->co_maintainers), "co_maintainers is an arrayref"); MetaCPAN-Client-2.023000/t/api/release.t0000644000175000017500000000055313232713623016656 0ustar mickeymickey#!perl use strict; use warnings; use Test::More tests => 5; use Test::Fatal; use lib '.'; use t::lib::Functions; my $mc = mcpan(); can_ok( $mc, 'release' ); my $release = $mc->release('MetaCPAN-API'); isa_ok( $release, 'MetaCPAN::Client::Release' ); can_ok( $release, qw ); is( $release->distribution, 'MetaCPAN-API', 'Correct distribution' ); MetaCPAN-Client-2.023000/t/api/favorite.t0000644000175000017500000000075613232713623017062 0ustar mickeymickey#!perl use strict; use warnings; use Test::More tests => 2 + 4 * 2; use Test::Fatal; use lib '.'; use t::lib::Functions; my $mc = mcpan(); can_ok( $mc, 'favorite' ); foreach my $option ( { author => 'XSAWYERX' }, { dist => 'MetaCPAN-Client' } ) { my $rs = $mc->favorite($option); isa_ok( $rs, 'MetaCPAN::Client::ResultSet' ); can_ok( $rs, qw ); is( $rs->type, 'favorite', 'Correct resultset type' ); isa_ok( $rs->scroller, 'MetaCPAN::Client::Scroll' ); } MetaCPAN-Client-2.023000/t/api/author.t0000644000175000017500000000450413232713623016540 0ustar mickeymickey#!perl use strict; use warnings; use Test::More; use Test::Fatal; use Ref::Util qw< is_arrayref >; use lib '.'; use t::lib::Functions; my $mc = mcpan(); can_ok( $mc, 'author' ); my $author = $mc->author('XSAWYERX'); isa_ok( $author, 'MetaCPAN::Client::Author' ); can_ok( $author, 'pauseid' ); is( $author->pauseid, 'XSAWYERX', 'Correct author' ); my $most_daves; { my $daves = $mc->author( { either => [ { name => 'Dave *' }, { name => 'David *' }, ] } ); isa_ok( $daves, 'MetaCPAN::Client::ResultSet' ); can_ok( $daves, 'total' ); ok( $daves->total > 200, 'Lots of Daves' ); $most_daves = $daves->total; } { my $daves = $mc->author( { either => [ { name => 'Dave *' }, { name => 'David *' }, ], not => [ { name => 'Dave S*' }, { name => 'David S*' }, ], } ); isa_ok( $daves, 'MetaCPAN::Client::ResultSet' ); can_ok( $daves, 'total' ); ok( $daves->total < $most_daves, 'Definitely less Daves' ); } { my $daves = $mc->author( { either => [ { all => [ { name => 'Dave *' }, { email => '*gmail.com' }, ], }, { all => [ { name => 'David *' }, { email => '*gmail.com' }, ], }, ] } ); isa_ok( $daves, 'MetaCPAN::Client::ResultSet' ); can_ok( $daves, 'total' ); ok( $daves->total <= $most_daves, 'Definitely not more Daves' ); while ( my $dave = $daves->next ) { my @emails = is_arrayref $dave->email ? @{ $dave->email } : $dave->email; ok( grep( +( $_ =~ /gmail\.com$/ ), @emails ), 'This Dave has a Gmail account', ); } } my $johns = $mc->author( { all => [ { name => 'John *' }, { email => '*gmail.com' }, ] } ); isa_ok( $johns, 'MetaCPAN::Client::ResultSet' ); can_ok( $johns, 'total' ); ok( $johns->total > 0, 'Got some Johns' ); while ( my $john = $johns->next ) { my @emails = is_arrayref $john->email ? @{ $john->email } : $john->email; ok( grep( +( $_ =~ /gmail\.com$/ ), @emails ), 'This John has a Gmail account', ); } done_testing; MetaCPAN-Client-2.023000/t/api/_search.t0000644000175000017500000000334613232713623016645 0ustar mickeymickey#!perl use strict; use warnings; use Test::More tests => 19; use Test::Fatal; use lib '.'; use t::lib::Functions; { no warnings qw; my $count = 0; *MetaCPAN::Client::ssearch = sub { my ( $self, $type, $args, $params ) = @_; ::isa_ok( $self, 'MetaCPAN::Client' ); ::is( $type, 'author', 'Correct type' ); ::is_deeply( $args, { hello => 'world' }, 'Correct args' ); if ( $count++ == 0 ) { ::is_deeply( $params, {}, 'Correct empty params' ); } else { ::is_deeply( $params, { a => 'b' }, 'Correct params' ); } return { a => 'ok' }; }; *MetaCPAN::Client::ResultSet::new = sub { my ( $self, %args ) = @_; ::isa_ok( $self, 'MetaCPAN::Client::ResultSet' ); ::is_deeply( \%args, { scroller => { a => 'ok' }, type => 'author', }, 'Correct args to ::ResultSet', ); return 'yoyo'; }; } my $mc = mcpan(); can_ok( $mc, '_search' ); like( exception { $mc->_search('author') }, qr/^_search takes a hash ref as query/, 'Failed with no query', ); like( exception { $mc->_search( 'author', { hello => 'world' }, 'fail' ) }, qr/^_search takes a hash ref as query parameters/, 'Failed with no query parameters', ); like( exception { $mc->_search( 'authorz', { hello => 'world' }, { a => 'b' } ) }, qr/^search type is not supported/, 'Unsupported search type', ); is( $mc->_search( 'author', { hello => 'world' } ), 'yoyo', 'Works with no query parameters', ); is( $mc->_search( 'author', { hello => 'world' }, { a => 'b' } ), 'yoyo', 'Correct _search call', ); MetaCPAN-Client-2.023000/t/api/file.t0000644000175000017500000000130113232713623016145 0ustar mickeymickey#!perl use strict; use warnings; use Test::More tests => 11; use Test::Fatal; use lib '.'; use t::lib::Functions; my $mc = mcpan(); can_ok( $mc, 'file' ); my $file = $mc->file('DOY/Moose-2.0001/lib/Moose.pm'); isa_ok( $file, 'MetaCPAN::Client::File' ); can_ok( $file, qw ); is( $file->author, 'DOY', 'Correct author' ); is( $file->distribution, 'Moose', 'Correct distribution' ); is( $file->name, 'Moose.pm', 'Correct name' ); is( $file->path, 'lib/Moose.pm', 'Correct path' ); is( $file->release, 'Moose-2.0001', 'Correct release' ); is( $file->version, '2.0001', 'Correct version' ); like( $file->source, qr/^\s*package Moose\;/, 'Correct source' ); MetaCPAN-Client-2.023000/t/api/_get_or_search.t0000644000175000017500000000214013232713623020173 0ustar mickeymickey#!perl use strict; use warnings; use Test::More tests => 10; use Test::Fatal; use lib '.'; use t::lib::Functions; { no warnings qw; *MetaCPAN::Client::_search = sub { my ( $self, $type, $arg, $params ) = @_; ::isa_ok( $self, 'MetaCPAN::Client' ); ::is( $type, 'type', 'Correct type' ); ::is_deeply( $arg, { hello => 'world' }, 'Correct arg' ); ::is_deeply( $params, { this => 'that' }, 'Correct params' ); }; *MetaCPAN::Client::_get = sub { my ( $self, $type, $arg ) = @_; ::isa_ok( $self, 'MetaCPAN::Client' ); ::is( $type, 'typeB', 'Correct type in _get' ); ::is( $arg, 'argb', 'Correct arg in _get' ); }; } my $mc = mcpan(); can_ok( $mc, '_get_or_search' ); # if arg is hash, it should call _search with it $mc->_get_or_search( 'type', { hello => 'world' }, { this => 'that' } ); # if not, check for arg and call _get $mc->_get_or_search( 'typeB', 'argb' ); # make arg fail check like( exception { $mc->_get_or_search( 'type', sub {1} ) }, qr/^type: invalid args/, 'Failed execution', ); MetaCPAN-Client-2.023000/t/api/reverse-dependencies.t0000644000175000017500000000161013232713623021330 0ustar mickeymickeyuse strict; use warnings; use Test::More; use Test::Fatal; use Ref::Util qw< is_hashref >; use lib '.'; use t::lib::Functions; my $mc = mcpan(); can_ok( $mc, qw< reverse_dependencies rev_deps > ); my $module = 'MetaCPAN::Client'; my $rs = $mc->reverse_dependencies($module); isa_ok( $rs, 'MetaCPAN::Client::ResultSet' ); my @revdeps; while ( my $release = $rs->next ) { is( ref $release, 'MetaCPAN::Client::Release', 'ResultSet->next with ' . $release->distribution . ' is ok', ), push @revdeps, $release->distribution; } ok( @revdeps > 2, 'revdep count for MetaCPAN::Client seems ok' ); foreach my $dep (@revdeps) { $dep =~ s/-/::/g; my $ok = eval { $mc->module($dep)->name; 1; }; is( $ok, 1, "$dep is a valid reverse dependency" ); } # Counting here would be fragile since it depends on dependency changes done_testing(); MetaCPAN-Client-2.023000/t/api/module.t0000644000175000017500000000122713232713623016522 0ustar mickeymickey#!perl use strict; use warnings; use Test::More tests => 10; use Test::Fatal; use lib '.'; use t::lib::Functions; my $mc = mcpan(); can_ok( $mc, 'module' ); my $module = $mc->module('MetaCPAN::API'); isa_ok( $module, 'MetaCPAN::Client::Module' ); can_ok( $module, qw ); is( $module->distribution, 'MetaCPAN-API', 'Correct distribution' ); is( $module->name, 'API.pm', 'Correct name' ); is( $module->path, 'lib/MetaCPAN/API.pm', 'Correct path' ); my $rs = $mc->module( { path => 'lib/MetaCPAN' } ); isa_ok( $rs, 'MetaCPAN::Client::ResultSet' ); can_ok( $rs, 'total' ); ok( $rs->total > 0, 'More than a single result in result set' ); MetaCPAN-Client-2.023000/t/scroll.t0000644000175000017500000000207013232713623015757 0ustar mickeymickey#!perl use strict; use warnings; use Test::More tests => 6; use Ref::Util qw< is_hashref >; use HTTP::Tiny; use MetaCPAN::Client::Scroll; use MetaCPAN::Client::Release; my $scroller = MetaCPAN::Client::Scroll->new( ua => HTTP::Tiny->new, base_url => 'https://fastapi.metacpan.org/v1/', type => 'release', body => { query => { term => { distribution => 'MetaCPAN-Client' } } }, size => 50, ); isa_ok( $scroller, 'MetaCPAN::Client::Scroll' ); can_ok( $scroller, qw< aggregations base_url body _buffer BUILDARGS DEMOLISH _fetch_next _id next size time total type ua > ); my $next = $scroller->next; ok( is_hashref($next), 'next doc returns a hashref' ); my $rel = MetaCPAN::Client::Release->new_from_request( $next->{'_source'} ); isa_ok( $rel, 'MetaCPAN::Client::Release' ); is( $rel->distribution, 'MetaCPAN-Client', 'release object can be created from next doc' ); my $got = 1; # we call ->next once above while ( my $n = $scroller->next ) { $got++ } is( $got, $scroller->total, 'can read all matching docs' ); 1; MetaCPAN-Client-2.023000/t/00-report-prereqs.t0000644000175000017500000001271413232713623017676 0ustar mickeymickey#!perl use strict; use warnings; # This test was generated by Dist::Zilla::Plugin::Test::ReportPrereqs 0.025 use Test::More tests => 1; use ExtUtils::MakeMaker; use File::Spec; # from $version::LAX my $lax_version_re = qr/(?: undef | (?: (?:[0-9]+) (?: \. | (?:\.[0-9]+) (?:_[0-9]+)? )? | (?:\.[0-9]+) (?:_[0-9]+)? ) | (?: v (?:[0-9]+) (?: (?:\.[0-9]+)+ (?:_[0-9]+)? )? | (?:[0-9]+)? (?:\.[0-9]+){2,} (?:_[0-9]+)? ) )/x; # hide optional CPAN::Meta modules from prereq scanner # and check if they are available my $cpan_meta = "CPAN::Meta"; my $cpan_meta_pre = "CPAN::Meta::Prereqs"; my $HAS_CPAN_META = eval "require $cpan_meta; $cpan_meta->VERSION('2.120900')" && eval "require $cpan_meta_pre"; ## no critic # Verify requirements? my $DO_VERIFY_PREREQS = 1; sub _max { my $max = shift; $max = ( $_ > $max ) ? $_ : $max for @_; return $max; } sub _merge_prereqs { my ($collector, $prereqs) = @_; # CPAN::Meta::Prereqs object if (ref $collector eq $cpan_meta_pre) { return $collector->with_merged_prereqs( CPAN::Meta::Prereqs->new( $prereqs ) ); } # Raw hashrefs for my $phase ( keys %$prereqs ) { for my $type ( keys %{ $prereqs->{$phase} } ) { for my $module ( keys %{ $prereqs->{$phase}{$type} } ) { $collector->{$phase}{$type}{$module} = $prereqs->{$phase}{$type}{$module}; } } } return $collector; } my @include = qw( ); my @exclude = qw( ); # Add static prereqs to the included modules list my $static_prereqs = do 't/00-report-prereqs.dd'; # Merge all prereqs (either with ::Prereqs or a hashref) my $full_prereqs = _merge_prereqs( ( $HAS_CPAN_META ? $cpan_meta_pre->new : {} ), $static_prereqs ); # Add dynamic prereqs to the included modules list (if we can) my ($source) = grep { -f } 'MYMETA.json', 'MYMETA.yml'; if ( $source && $HAS_CPAN_META && (my $meta = eval { CPAN::Meta->load_file($source) } ) ) { $full_prereqs = _merge_prereqs($full_prereqs, $meta->prereqs); } else { $source = 'static metadata'; } my @full_reports; my @dep_errors; my $req_hash = $HAS_CPAN_META ? $full_prereqs->as_string_hash : $full_prereqs; # Add static includes into a fake section for my $mod (@include) { $req_hash->{other}{modules}{$mod} = 0; } for my $phase ( qw(configure build test runtime develop other) ) { next unless $req_hash->{$phase}; next if ($phase eq 'develop' and not $ENV{AUTHOR_TESTING}); for my $type ( qw(requires recommends suggests conflicts modules) ) { next unless $req_hash->{$phase}{$type}; my $title = ucfirst($phase).' '.ucfirst($type); my @reports = [qw/Module Want Have/]; for my $mod ( sort keys %{ $req_hash->{$phase}{$type} } ) { next if $mod eq 'perl'; next if grep { $_ eq $mod } @exclude; my $file = $mod; $file =~ s{::}{/}g; $file .= ".pm"; my ($prefix) = grep { -e File::Spec->catfile($_, $file) } @INC; my $want = $req_hash->{$phase}{$type}{$mod}; $want = "undef" unless defined $want; $want = "any" if !$want && $want == 0; my $req_string = $want eq 'any' ? 'any version required' : "version '$want' required"; if ($prefix) { my $have = MM->parse_version( File::Spec->catfile($prefix, $file) ); $have = "undef" unless defined $have; push @reports, [$mod, $want, $have]; if ( $DO_VERIFY_PREREQS && $HAS_CPAN_META && $type eq 'requires' ) { if ( $have !~ /\A$lax_version_re\z/ ) { push @dep_errors, "$mod version '$have' cannot be parsed ($req_string)"; } elsif ( ! $full_prereqs->requirements_for( $phase, $type )->accepts_module( $mod => $have ) ) { push @dep_errors, "$mod version '$have' is not in required range '$want'"; } } } else { push @reports, [$mod, $want, "missing"]; if ( $DO_VERIFY_PREREQS && $type eq 'requires' ) { push @dep_errors, "$mod is not installed ($req_string)"; } } } if ( @reports ) { push @full_reports, "=== $title ===\n\n"; my $ml = _max( map { length $_->[0] } @reports ); my $wl = _max( map { length $_->[1] } @reports ); my $hl = _max( map { length $_->[2] } @reports ); if ($type eq 'modules') { splice @reports, 1, 0, ["-" x $ml, "", "-" x $hl]; push @full_reports, map { sprintf(" %*s %*s\n", -$ml, $_->[0], $hl, $_->[2]) } @reports; } else { splice @reports, 1, 0, ["-" x $ml, "-" x $wl, "-" x $hl]; push @full_reports, map { sprintf(" %*s %*s %*s\n", -$ml, $_->[0], $wl, $_->[1], $hl, $_->[2]) } @reports; } push @full_reports, "\n"; } } } if ( @full_reports ) { diag "\nVersions for all modules listed in $source (including optional ones):\n\n", @full_reports; } if ( @dep_errors ) { diag join("\n", "\n*** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ***\n", "The following REQUIRED prerequisites were not satisfied:\n", @dep_errors, "\n" ); } pass; # vim: ts=4 sts=4 sw=4 et: MetaCPAN-Client-2.023000/t/resultset.t0000644000175000017500000000131613232713623016515 0ustar mickeymickey#!perl use strict; use warnings; use Test::More tests => 3; use Test::Fatal; use MetaCPAN::Client::ResultSet; { package MetaCPAN::Client::Test::ScrollerZ; use base 'MetaCPAN::Client::Scroll'; # < 5.10 FTW (except, no) sub total {0} } like( exception { MetaCPAN::Client::ResultSet->new( type => 'failZZ', scroller => bless {}, 'MetaCPAN::Client::Test::ScrollerZ', ) }, qr/Invalid type/, 'Invalid type fail', ); my $rs = MetaCPAN::Client::ResultSet->new( type => 'author', scroller => bless {}, 'MetaCPAN::Client::Scroll', ); isa_ok( $rs, 'MetaCPAN::Client::ResultSet' ); can_ok( $rs, qw ); MetaCPAN-Client-2.023000/t/lib/0000755000175000017500000000000013232713623015043 5ustar mickeymickeyMetaCPAN-Client-2.023000/t/lib/Functions.pm0000644000175000017500000000047313232713623017355 0ustar mickeymickeyuse strict; use warnings; use MetaCPAN::Client; use Test::More; my $version = $MetaCPAN::Client::VERSION || 'xx'; sub mcpan { my $mc = MetaCPAN::Client->new( ua_args => [ agent => "MetaCPAN::Client-testing/$version" ], @_, ); isa_ok( $mc, 'MetaCPAN::Client' ); return $mc; } 1; MetaCPAN-Client-2.023000/t/ua_trap.t0000644000175000017500000000162613232713623016122 0ustar mickeymickeyuse strict; use warnings; use Test::More; # ABSTRACT: Make sure passed value of UA gets used for things. use Test::Needs { 'WWW::Mechanize::Cached' => 1.50, 'HTTP::Tiny::Mech' => 1.001002, }; use Test::Fatal qw( exception ); { package TrapUA; use Moo; extends 'HTTP::Tiny::Mech'; sub mechua { require WWW::Mechanize::Cached; return WWW::Mechanize::Cached->new(); } } { require HTTP::Tiny; no warnings "redefine"; *HTTP::Tiny::request = sub { my ( $self, @args ) = @_; die "Illegal use of HTTP::Tiny" . pp( \@args ); }; } use MetaCPAN::Client; my $e; is( $e = exception { my $client = MetaCPAN::Client->new( ua => TrapUA->new() ); my $a = $client->author('KENTNL'); my $releases = $a->releases; }, undef, "No illegal methods called" ); if ($e) { diag explain $e } done_testing; MetaCPAN-Client-2.023000/t/00-report-prereqs.dd0000644000175000017500000000546113232713623020023 0ustar mickeymickeydo { my $x = { 'configure' => { 'requires' => { 'ExtUtils::MakeMaker' => '7.1101' } }, 'develop' => { 'requires' => { 'File::Spec' => '0', 'HTTP::Tiny::Mech' => '1.001002', 'IO::Handle' => '0', 'IPC::Open3' => '0', 'LWP::Protocol::https' => '0', 'Pod::Coverage::TrustPod' => '0', 'Test::More' => '0', 'Test::Pod' => '1.41', 'Test::Pod::Coverage' => '1.08', 'WWW::Mechanize::Cached' => '1.50' } }, 'runtime' => { 'requires' => { 'Carp' => '0', 'HTTP::Tiny' => '0.056', 'IO::Socket::SSL' => '1.42', 'JSON::MaybeXS' => '0', 'JSON::PP' => '0', 'Moo' => '0', 'Moo::Role' => '0', 'Net::SSLeay' => '1.49', 'Ref::Util' => '0', 'Safe::Isa' => '0', 'Type::Tiny' => '0', 'URI::Escape' => '0', 'perl' => '5.010', 'strict' => '0', 'warnings' => '0' } }, 'test' => { 'recommends' => { 'CPAN::Meta' => '2.120900', 'HTTP::Tiny::Mech' => '1.001002', 'WWW::Mechanize::Cached' => '1.50' }, 'requires' => { 'ExtUtils::MakeMaker' => '0', 'File::Spec' => '0', 'LWP::Protocol::https' => '0', 'Test::Fatal' => '0', 'Test::More' => '0', 'Test::Needs' => '0.002005', 'base' => '0', 'blib' => '1.01' } } }; $x; }MetaCPAN-Client-2.023000/t/entity.t0000644000175000017500000000240513232713623015777 0ustar mickeymickey#!perl use strict; use warnings; use Test::More tests => 6; use Test::Fatal; { package MetaCPAN::Client::FakeEntityEmpty; use Moo; with 'MetaCPAN::Client::Role::Entity'; sub BUILDARGS { my ( $class, %args ) = @_; return \%args; } } { package MetaCPAN::Client::FakeEntityFull; use Moo; with 'MetaCPAN::Client::Role::Entity'; sub _known_fields { +{ scalar => ['this'], arrayref => [], hashref => [], } } } ok( exception { MetaCPAN::Client::FakeEntityEmpty->new }, 'data is missing, causing exception', ); is( exception { MetaCPAN::Client::FakeEntityEmpty->new( data => {} ) }, undef, 'data available, not causing exception', ); like( exception { MetaCPAN::Client::FakeEntityEmpty->new_from_request( {} ) }, qr/.*Can't locate.*_known_fields/, 'Subroutine _known_fields missing', ); is( exception { MetaCPAN::Client::FakeEntityFull->new( data => {} ) }, undef, 'data available, not causing exception', ); my $fe = MetaCPAN::Client::FakeEntityFull->new_from_request( { that => 'this', this => 'that' } ); isa_ok( $fe, 'MetaCPAN::Client::FakeEntityFull' ); is_deeply( $fe->{'data'}, { this => 'that' }, 'Correct data' ); MetaCPAN-Client-2.023000/README0000644000175000017500000003204213232713623014713 0ustar mickeymickeyNAME MetaCPAN::Client - A comprehensive, DWIM-featured client to the MetaCPAN API VERSION version 2.023000 SYNOPSIS # simple usage my $mcpan = MetaCPAN::Client->new(); my $author = $mcpan->author('XSAWYERX'); my $dist = $mcpan->distribution('MetaCPAN-Client'); # advanced usage with cache (contributed by Kent Fredric) use CHI; use WWW::Mechanize::Cached; use HTTP::Tiny::Mech; use MetaCPAN::Client; my $mcpan = MetaCPAN::Client->new( ua => HTTP::Tiny::Mech->new( mechua => WWW::Mechanize::Cached->new( cache => CHI->new( driver => 'File', root_dir => '/tmp/metacpan-cache', ), ), ), ); # now $mcpan caches results DESCRIPTION This is a hopefully-complete API-compliant client to MetaCPAN (https://metacpan.org) with DWIM capabilities, to make your life easier. ATTRIBUTES request Internal attribute representing the request object making the request to MetaCPAN and analyzing the results. You probably don't want to set this, nor should you have any usage of it. ua If provided, MetaCPAN::Client::Request will use the user agent object instead of the default, which is HTTP::Tiny. Then it can be used to fetch the user agent object used by MetaCPAN::Client::Request. domain If given, will be used to alter the API domain. debug If given, errors will include some low-level detailed message. METHODS author my $author = $mcpan->author('XSAWYERX'); my $author = $mcpan->author($search_spec); Finds an author by either its PAUSE ID or by a search spec defined by a hash reference. Since it is common to many other searches, it is explained below under SEARCH SPEC. Returns a MetaCPAN::Client::Author object on a simple search (PAUSE ID), or a MetaCPAN::Client::ResultSet object propagated with MetaCPAN::Client::Author objects on a complex (search spec based) search. module my $module = $mcpan->module('MetaCPAN::Client'); my $module = $mcpan->module($search_spec); Finds a module by either its module name or by a search spec defined by a hash reference. Since it is common to many other searches, it is explained below under SEARCH SPEC. Returns a MetaCPAN::Client::Module object on a simple search (module name), or a MetaCPAN::Client::ResultSet object propagated with MetaCPAN::Client::Module objects on a complex (search spec based) search. distribution my $dist = $mcpan->distribution('MetaCPAN-Client'); my $dist = $mcpan->distribution($search_spec); Finds a distribution by either its distribution name or by a search spec defined by a hash reference. Since it is common to many other searches, it is explained below under SEARCH SPEC. Returns a MetaCPAN::Client::Distribution object on a simple search (distribution name), or a MetaCPAN::Client::ResultSet object propagated with MetaCPAN::Client::Distribution objects on a complex (search spec based) search. file Returns a MetaCPAN::Client::File object. favorite my $favorite = $mcpan->favorite({ distribution => 'Moose' }); Returns a MetaCPAN::Client::ResultSet object containing MetaCPAN::Client::Favorite results. rating my $rating = $mcpan->rating({ distribution => 'Moose' }); Returns a MetaCPAN::Client::ResultSet object containing MetaCPAN::Client::Rating results. release my $release = $mcpan->release('MetaCPAN-Client'); my $release = $mcpan->release($search_spec); Finds a release by either its distribution name or by a search spec defined by a hash reference. Since it is common to many other searches, it is explained below under SEARCH SPEC. Returns a MetaCPAN::Client::Release object on a simple search (release name), or a MetaCPAN::Client::ResultSet object propagated with MetaCPAN::Client::Release objects on a complex (search spec based) search. mirror my $mirror = $mcpan->mirror('kr.freebsd.org'); Returns a MetaCPAN::Client::Mirror object. package my $package = $mcpan->package('MooseX::Types'); Returns a MetaCPAN::Client::Package object. permission my $permission = $mcpan->permission('MooseX::Types'); Returns a MetaCPAN::Client::Permission object. reverse_dependencies my $deps = $mcpan->reverse_dependencies('Search::Elasticsearch'); all MetaCPAN::Client::Release objects of releases that are directly dependent on a given module, returned as MetaCPAN::Client::ResultSet. rev_deps Alias to reverse_dependencies described above. autocomplete my $ac = $mcpan->autocomplete('Danc'); Call the search/autocomplete endpoint with a query string. Returns an array reference. autocomplete_suggest my $ac = $mcpan->autocomplete_suggest('Moo'); Call the search/autocomplete/suggest endpoint with a query string. Returns an array reference. recent my $recent = $mcpan->recent(10); my $recent = $mcpan->recent('today'); return the latest N releases, or all releases from today. returns a MetaCPAN::Client::ResultSet of MetaCPAN::Client::Release. pod Get POD for given file/module name. returns a MetaCPAN::Client::Pod object, which supports various output formats (html, plain, x_pod & x_markdown). my $pod = $mcpan->pod('Moo')->html; my $pod = $mcpan->pod('Moo', { url_prefix => $prefix })->html; download_url Retrieve information from the 'download_url' endpoint my $download_url = $mcpan->download_url('Moose') Returns a MetaCPAN::Client::DownloadURL object all Retrieve all matches for authors/modules/distributions/favorites or releases. my $all_releases = $mcpan->all('releases') When called with a second parameter containing a hash ref, will support the following keys: fields See SEARCH PARAMS. my $all_releases = $mcpan->all('releases', { fields => [...] }) _source See SEARCH PARAMS. my $all_releases = $mcpan->all('releases', { _source => [...] }) es_filter Pass a raw Elasticsearch filter structure to reduce the number of elements returned by the query. my $some_releases = $mcpan->all('releases', { es_filter => {...} }) BUILDARGS Internal construction wrapper. Do not use. SEARCH PARAMS Most searches take params as an optional hash-ref argument. these params will be passed to the search action. In non-scrolled searches, 'fields' filter is the only supported parameter ATM. fields Filter the fields to reduce the amount of data pulled from MetaCPAN. can be passed as a csv list or an array ref. my $module = $mcpan->module('Moose', { fields => "version,author" }); my $module = $mcpan->module('Moose', { fields => [qw/version author/] }); _source Note: this param and its description are a bit too Elasticsearch specific. just like 'es_filter' - use only if you know what you're dealing with. Some fields are not indexed in Elasticsearch but stored as part of the entire document. These fields can still be read, but without the internal Elasticsearch optimizations and the server will internally read the whole document. Why do we even need those? because we don't index everything and some things we can't to begin with (like non-leaf fields that hold a structure) my $module = $mcpan->all('releases', { _source => "stat" }); scroller_time Note: please use with caution. This parameter will set the maximum lifetime of the Elasticsearch scroller on the server (default = '5m'). Normally you do not need to set this value (as tweaking this value can affect resources on the server). In case you do, you probably need to check the efficiency of your code/queries. (Feel free to reach out to us for assistance). my $module = $mcpan->all('releases', { scroller_time => '3m' }); scroller_size Note: please use with caution. This parameter will set the buffer size to be pulled from Elasticsearch when scrolling (default = 1000). This will affect query performance and memory usage, but you will still get an iterator back to fetch one object at a time. my $module = $mcpan->all('releases', { scroller_size => 500 }); sort Pass a raw Elasticsearch sort specification for the query. my $some_releases = $mcpan->all('releases', { sort => [{ date => { order => 'desc' } }] }) Note: this param and is a bit too specific to Elasticsearch. Just like "es_filter", only use this if you know what you're dealing with. SEARCH SPEC The hash-based search spec is common to many searches. It is quite feature-rich and allows you to disambiguate different types of searches. Basic search specs just contain a hash of keys and values: my $author = $mcpan->author( { name => 'Micha Nasriachi' } ); # the following is the same as ->author('MICKEY') my $author = $mcpan->author( { pauseid => 'MICKEY' } ); # find all people named Dave, not covering Davids # will return a resultset my $daves = $mcpan->author( { name => 'Dave *' } ); OR If you want to do a more complicated query that has an OR condition, such as "this or that", you can use the following syntax with the either key: # any author named "Dave" or "David" my $daves = $mcpan->author( { either => [ { name => 'Dave *' }, { name => 'David *' }, ] } ); AND If you want to do a more complicated query that has an AND condition, such as "this and that", you can use the following syntax with the all key: # any users named 'John' with a Gmail account my $johns = $mcpan->author( { all => [ { name => 'John *' }, { email => '*gmail.com' }, ] } ); If you want to do something even more complicated, You can also nest your queries, e.g.: my $gmail_daves_or_cpan_sams = $mcpan->author( { either => [ { all => [ { name => 'Dave *' }, { email => '*gmail.com' } ] }, { all => [ { name => 'Sam *' }, { email => '*cpan.org' } ] }, ], } ); NOT If you want to filter out some of the results of an either/all query adding a NOT filter condition, such as "not these", you can use the following syntax with the not key: # any author named "Dave" or "David" my $daves = $mcpan->author( { either => [ { name => 'Dave *' }, { name => 'David *' }, ], not => [ { email => '*gmail.com' }, ], } ); DESIGN This module has three purposes: * Provide 100% of the MetaCPAN API This module will be updated regularly on every MetaCPAN API change, and intends to provide the user with as much of the API as possible, no shortcuts. If it's documented in the API, you should be able to do it. Because of this design decision, this module has an official MetaCPAN namespace with the blessing of the MetaCPAN developers. Notice this module currently only provides the beta API, not the old soon-to-be-deprecated API. * Be lightweight, to allow flexible usage While many modules would help make writing easier, it's important to take into account how they affect your compile-time, run-time, overall memory consumption, and CPU usage. By providing a slim interface implementation, more users are able to use this module, such as long-running processes (like daemons), CLI or GUI applications, cron jobs, and more. * DWIM While it's possible to access the methods defined by the API spec, there's still a matter of what you're really trying to achieve. For example, when searching for "Dave", you want to find both Dave Cross and Dave Rolsky (and any other Dave), but you also want to search for a PAUSE ID of DAVE, if one exists. This is where DWIM comes in. This module provides you with additional generic methods which will try to do what they think you want. Of course, this does not prevent you from manually using the API methods. You still have full control over that, if that's what you wish. You can (and should) read up on the general methods, which will explain how their DWIMish nature works, and what searches they run. AUTHORS * Sawyer X * Mickey Nasriachi COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Sawyer X. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. MetaCPAN-Client-2.023000/META.yml0000644000175000017500000002761213232713623015313 0ustar mickeymickey--- abstract: 'A comprehensive, DWIM-featured client to the MetaCPAN API' author: - 'Sawyer X ' - 'Mickey Nasriachi ' build_requires: ExtUtils::MakeMaker: '0' File::Spec: '0' LWP::Protocol::https: '0' Test::Fatal: '0' Test::More: '0' Test::Needs: '0.002005' base: '0' blib: '1.01' configure_requires: ExtUtils::MakeMaker: '7.1101' dynamic_config: 0 generated_by: 'Dist::Zilla version 6.008, CPAN::Meta::Converter version 2.150005' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: MetaCPAN-Client no_index: directory: - eg - examples - inc - share - t - xt provides: MetaCPAN::Client: file: lib/MetaCPAN/Client.pm version: '2.023000' MetaCPAN::Client::Author: file: lib/MetaCPAN/Client/Author.pm version: '2.023000' MetaCPAN::Client::Distribution: file: lib/MetaCPAN/Client/Distribution.pm version: '2.023000' MetaCPAN::Client::DownloadURL: file: lib/MetaCPAN/Client/DownloadURL.pm version: '2.023000' MetaCPAN::Client::Favorite: file: lib/MetaCPAN/Client/Favorite.pm version: '2.023000' MetaCPAN::Client::File: file: lib/MetaCPAN/Client/File.pm version: '2.023000' MetaCPAN::Client::Mirror: file: lib/MetaCPAN/Client/Mirror.pm version: '2.023000' MetaCPAN::Client::Module: file: lib/MetaCPAN/Client/Module.pm version: '2.023000' MetaCPAN::Client::Package: file: lib/MetaCPAN/Client/Package.pm version: '2.023000' MetaCPAN::Client::Permission: file: lib/MetaCPAN/Client/Permission.pm version: '2.023000' MetaCPAN::Client::Pod: file: lib/MetaCPAN/Client/Pod.pm version: '2.023000' MetaCPAN::Client::Rating: file: lib/MetaCPAN/Client/Rating.pm version: '2.023000' MetaCPAN::Client::Release: file: lib/MetaCPAN/Client/Release.pm version: '2.023000' MetaCPAN::Client::Request: file: lib/MetaCPAN/Client/Request.pm version: '2.023000' MetaCPAN::Client::ResultSet: file: lib/MetaCPAN/Client/ResultSet.pm version: '2.023000' MetaCPAN::Client::Role::Entity: file: lib/MetaCPAN/Client/Role/Entity.pm version: '2.023000' MetaCPAN::Client::Role::HasUA: file: lib/MetaCPAN/Client/Role/HasUA.pm version: '2.023000' MetaCPAN::Client::Scroll: file: lib/MetaCPAN/Client/Scroll.pm version: '2.023000' MetaCPAN::Client::Types: file: lib/MetaCPAN/Client/Types.pm version: '2.023000' requires: Carp: '0' HTTP::Tiny: '0.056' IO::Socket::SSL: '1.42' JSON::MaybeXS: '0' JSON::PP: '0' Moo: '0' Moo::Role: '0' Net::SSLeay: '1.49' Ref::Util: '0' Safe::Isa: '0' Type::Tiny: '0' URI::Escape: '0' perl: '5.010' strict: '0' warnings: '0' resources: IRC: irc://irc.perl.org/#metacpan WebIRC: https://chat.mibbit.com/#metacpan@irc.perl.org bugtracker: https://github.com/metacpan/metacpan-client/issues repository: https://github.com/metacpan/metacpan-client.git version: '2.023000' x_Dist_Zilla: perl: version: '5.022001' plugins: - class: Dist::Zilla::Plugin::PruneCruft name: '@Starter/PruneCruft' version: '6.008' - class: Dist::Zilla::Plugin::ManifestSkip name: '@Starter/ManifestSkip' version: '6.008' - class: Dist::Zilla::Plugin::MetaConfig name: '@Starter/MetaConfig' version: '6.008' - class: Dist::Zilla::Plugin::MetaProvides::Package config: Dist::Zilla::Plugin::MetaProvides::Package: finder_objects: - class: Dist::Zilla::Plugin::FinderCode name: '@Starter/MetaProvides::Package/AUTOVIV/:InstallModulesPM' version: '6.008' include_underscores: 0 Dist::Zilla::Role::MetaProvider::Provider: $Dist::Zilla::Role::MetaProvider::Provider::VERSION: '2.002003' inherit_missing: '1' inherit_version: '1' meta_noindex: '1' Dist::Zilla::Role::ModuleMetadata: Module::Metadata: '1.000027' version: '0.004' name: '@Starter/MetaProvides::Package' version: '2.004002' - class: Dist::Zilla::Plugin::MetaNoIndex name: '@Starter/MetaNoIndex' version: '6.008' - class: Dist::Zilla::Plugin::MetaYAML name: '@Starter/MetaYAML' version: '6.008' - class: Dist::Zilla::Plugin::MetaJSON name: '@Starter/MetaJSON' version: '6.008' - class: Dist::Zilla::Plugin::License name: '@Starter/License' version: '6.008' - class: Dist::Zilla::Plugin::ReadmeAnyFromPod config: Dist::Zilla::Role::FileWatcher: version: '0.006' name: '@Starter/ReadmeAnyFromPod' version: '0.161170' - class: Dist::Zilla::Plugin::ExecDir name: '@Starter/ExecDir' version: '6.008' - class: Dist::Zilla::Plugin::ShareDir name: '@Starter/ShareDir' version: '6.008' - class: Dist::Zilla::Plugin::PodSyntaxTests name: '@Starter/PodSyntaxTests' version: '6.008' - class: Dist::Zilla::Plugin::Test::ReportPrereqs name: '@Starter/Test::ReportPrereqs' version: '0.025' - class: Dist::Zilla::Plugin::Test::Compile config: Dist::Zilla::Plugin::Test::Compile: bail_out_on_fail: '0' fail_on_warning: author fake_home: 0 filename: xt/author/00-compile.t module_finder: - ':InstallModules' needs_display: 0 phase: develop script_finder: - ':PerlExecFiles' skips: [] name: '@Starter/Test::Compile' version: '2.054' - class: Dist::Zilla::Plugin::MakeMaker config: Dist::Zilla::Role::TestRunner: default_jobs: 1 name: '@Starter/MakeMaker' version: '6.008' - class: Dist::Zilla::Plugin::Manifest name: '@Starter/Manifest' version: '6.008' - class: Dist::Zilla::Plugin::TestRelease name: '@Starter/TestRelease' version: '6.008' - class: Dist::Zilla::Plugin::RunExtraTests config: Dist::Zilla::Role::TestRunner: default_jobs: 1 name: '@Starter/RunExtraTests' version: '0.029' - class: Dist::Zilla::Plugin::ConfirmRelease name: '@Starter/ConfirmRelease' version: '6.008' - class: Dist::Zilla::Plugin::UploadToCPAN name: '@Starter/UploadToCPAN' version: '6.008' - class: Dist::Zilla::Plugin::PodCoverageTests name: PodCoverageTests version: '6.008' - class: Dist::Zilla::Plugin::Git::GatherDir config: Dist::Zilla::Plugin::GatherDir: exclude_filename: [] exclude_match: [] follow_symlinks: 0 include_dotfiles: 0 prefix: '' prune_directory: [] root: . Dist::Zilla::Plugin::Git::GatherDir: include_untracked: 0 name: Git::GatherDir version: '2.039' - class: Dist::Zilla::Plugin::Prereqs::FromCPANfile name: Prereqs::FromCPANfile version: '0.08' - class: Dist::Zilla::Plugin::PodWeaver config: Dist::Zilla::Plugin::PodWeaver: finder: - ':InstallModules' - ':ExecFiles' plugins: - class: Pod::Weaver::Plugin::EnsurePod5 name: '@CorePrep/EnsurePod5' version: '4.014' - class: Pod::Weaver::Plugin::H1Nester name: '@CorePrep/H1Nester' version: '4.014' - class: Pod::Weaver::Plugin::SingleEncoding name: '@Default/SingleEncoding' version: '4.014' - class: Pod::Weaver::Section::Name name: '@Default/Name' version: '4.014' - class: Pod::Weaver::Section::Version name: '@Default/Version' version: '4.014' - class: Pod::Weaver::Section::Region name: '@Default/prelude' version: '4.014' - class: Pod::Weaver::Section::Generic name: SYNOPSIS version: '4.014' - class: Pod::Weaver::Section::Generic name: DESCRIPTION version: '4.014' - class: Pod::Weaver::Section::Generic name: OVERVIEW version: '4.014' - class: Pod::Weaver::Section::Collect name: ATTRIBUTES version: '4.014' - class: Pod::Weaver::Section::Collect name: METHODS version: '4.014' - class: Pod::Weaver::Section::Collect name: FUNCTIONS version: '4.014' - class: Pod::Weaver::Section::Leftovers name: '@Default/Leftovers' version: '4.014' - class: Pod::Weaver::Section::Region name: '@Default/postlude' version: '4.014' - class: Pod::Weaver::Section::Authors name: '@Default/Authors' version: '4.014' - class: Pod::Weaver::Section::Legal name: '@Default/Legal' version: '4.014' name: PodWeaver version: '4.008' - class: Dist::Zilla::Plugin::MinimumPerlFast name: MinimumPerlFast version: '0.003' - class: Dist::Zilla::Plugin::ReadmeAnyFromPod config: Dist::Zilla::Role::FileWatcher: version: '0.006' name: pod.root version: '0.161170' - class: Dist::Zilla::Plugin::CheckChangeLog name: CheckChangeLog version: '0.02' - class: Dist::Zilla::Plugin::PkgVersion name: PkgVersion version: '6.008' - class: Dist::Zilla::Plugin::MetaResources name: MetaResources version: '6.008' - class: Dist::Zilla::Plugin::Git::Tag config: Dist::Zilla::Plugin::Git::Tag: branch: ~ changelog: Changes signed: 0 tag: v2.023000 tag_format: v%v tag_message: v%v Dist::Zilla::Role::Git::Repo: repo_root: . Dist::Zilla::Role::Git::StringFormatter: time_zone: local name: Git::Tag version: '2.039' - class: Dist::Zilla::Plugin::Git::Push config: Dist::Zilla::Plugin::Git::Push: push_to: - origin remotes_must_exist: 1 Dist::Zilla::Role::Git::Repo: repo_root: . name: Git::Push version: '2.039' - class: Dist::Zilla::Plugin::FinderCode name: ':InstallModules' version: '6.008' - class: Dist::Zilla::Plugin::FinderCode name: ':IncModules' version: '6.008' - class: Dist::Zilla::Plugin::FinderCode name: ':TestFiles' version: '6.008' - class: Dist::Zilla::Plugin::FinderCode name: ':ExtraTestFiles' version: '6.008' - class: Dist::Zilla::Plugin::FinderCode name: ':ExecFiles' version: '6.008' - class: Dist::Zilla::Plugin::FinderCode name: ':PerlExecFiles' version: '6.008' - class: Dist::Zilla::Plugin::FinderCode name: ':ShareFiles' version: '6.008' - class: Dist::Zilla::Plugin::FinderCode name: ':MainModule' version: '6.008' - class: Dist::Zilla::Plugin::FinderCode name: ':AllFiles' version: '6.008' - class: Dist::Zilla::Plugin::FinderCode name: ':NoFiles' version: '6.008' - class: Dist::Zilla::Plugin::FinderCode name: '@Starter/MetaProvides::Package/AUTOVIV/:InstallModulesPM' version: '6.008' zilla: class: Dist::Zilla::Dist::Builder config: is_trial: '0' version: '6.008' x_serialization_backend: 'YAML::Tiny version 1.69'