Group
Extension

Github-Score/lib/Github/Score.pm

package Github::Score;
#ABSTRACT: Pull author contribution counts for github repos

use strict;
use warnings;
use LWP;
use JSON;
use HTTP::Request;
use URI;

use Data::Dumper;

use Moose; # automatically turns on strict and warnings

  has 'user' => (is => 'rw', );
  has 'repo' => (is => 'rw', );
  has 'timeout' => (is => 'rw', );
  has 'api_version' => (is => 'rw', );

  sub clear {
      my $self = shift;
      $self->$_(undef) for qw(ua user json uri timeout);
  }


 our $VERSION = '0.001';
 $VERSION = eval $VERSION;
 
 sub new {
     my $self = shift;
     my @args = @_;
 
     unshift @args, 'url' if @args % 2 && !ref( $args[0] );
 
     my %args = ref( $args[0] ) ? %{ $args[0] } : @args;
     if ( exists $args{url} ) {
         ( $args{user}, $args{repo} ) = ( split /\//, delete $args{url} );
     }
 
     my $timeout = $args{timeout} || 10;
 
     bless { 
     	user => $args{user}, 
     	repo => $args{repo}, 
     	timeout => $timeout,
     	api_version => ($args{api_version} || 'v2'), 
     	}, $self;
 }
 
 sub ua { 
 		LWP::UserAgent->new( 
 			timeout => $_[0]->timeout, 
 			agent => join ' ', ( __PACKAGE__, $VERSION ) 
 			); 
}


 sub uri { 
 	URI->new( sprintf( 'http://github.com/api/%s/json/repos/show/%s/%s/contributors', 
 	$_[0]->api_version,$_[0]->user, $_[0]->repo ) 
 	); 
 	}
 sub json { JSON->new->allow_nonref }
 
 sub scores {
     my $self = shift;
 
     my $response = $self->ua->request( HTTP::Request->new( GET => $self->uri->canonical ) );
     return {} unless $response->is_success;
 
     my %scores;
     my $contributors = $self->json->decode( $response->content )->{contributors};
 
     map { $scores{ $_->{login} } = $_->{contributions} } @$contributors;
     return \%scores;
 }
 
 1;


=pod

=head1 NAME

Github::Score - Pull author contribution counts for github repos

=head1 VERSION

version 0.2.0

=head1 AUTHOR

justin.d.hunter@gmail.com

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011 by AHB.

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


__DATA__ 


=head1 NAME 

Github::Score - Collect contributions data from the Github api.

=head1 SYNOPSIS

  use Github::Score;
  
  my $gs1 = Github::Score->new(); ##Bare constructor. Not much use without:
  $gs1->user('Getty'); ## Still need a:
  $gs1->repo('p5-www-duckduckgo');
  
  my $contributors_scores = $gs1->scores();
  ## Do stuff with an array of this sort of thing:
  #$VAR1 = [
  #          {
  #            'login' => 'doy',
  #            'contributions' => 119
  #          },
  #          {
  #            'login' => 'stevan',
  #            'contributions' => 36
  #          },
  #          {
  #            'login' => 'jasonmay',
  #            'contributions' => 5
  #          },
  #          {
  #            'login' => 'arcanez',
  #            'contributions' => 3
  #          }
  #        ];
  
  ## Save yourself a few key-strokes
  my $gs2 = Github::Score->new(user=>'Getty', repo=>'p5-www-duckduckgo'); 
  $contributors_scores = $gs2->scores();
  
  ## Save yourself a few more key-strokes
  my $gs3 = Github::Score->new('Getty/p5-www-duckduckgo'); 
  $contributors_scores = $gs3->scores();
  
  ## Can't afford to wait for up to 10 seconds?
  $gs3->timeout(9.99);
  $contributors_scores = $gs3->scores();

=head1 DESCRIPTION

  http://github-high-scores.heroku.com/ is a site with a retro-80s look and 
  feel where you can look up the author contribution counts for projecs on Github.
  Github::Score is an OO perl API to the same data from the site aimed at the 
  DuckDuckGo community platform. 

=head1 METHODS

=head2 Constructors

=head3 new

 Github::Score objects can be constructed in different ways:

=over 4

=item Empty constructor call

C<    new()>

=item Single url-style string

C<    new('contributor/github-repo')>

=item Key-value pairs

C<<   new(user=>someone, repo=>'some-repo', timeout=> $_10_if_you_leave_it_out) >>

=item Hash reference

C<<   new( {user=>someone, repo=>'some-repo', timeout=> $_10_if_you_leave_it_out)} >>

=back

=head2 Accessors

=head3 B<user>

    Will set $self->{user} to $_[0], if an argument is given.
    Returns: $self->{user}

=head3 B<repo>

    Will set $self-{repo}  to $_[0], if an argument is given.
    Returns: $self-{repo} 

=head3 B<timeout>

    Will set $self->{timeout} to $_[0], if an argument is given.
    Returns: $self->{timeout}

    Note: Defaults to 10 when the object is constructed.

=head3 B<ua>

    Returns: A LWP::UserAgent instance

    Note: Do not use this method directly. It is automatically invoked by the
    scores method.

=head3 B<uri>

    Returns: A URI instance
    
    Note: Do not use this method directly. It is automatically invoked by the
    scores method.

=head3 B<json>

    Returns: A JSON instance
    
    Note: Do not use this method directly. It is automatically invoked by the
    scores method.

=head2 Behaviour

=head3 B<scores>

    Returns: A reference to a hash of login/contribution pairs.
    
    Note: The hash could be empty if there is some error with the request,
    or example a timeout, or if the query is invalid, for example user
    does not contribute to the repository.

=head1 BUGS

    None known, but they will be there somewhere.

=head1 TODO

=over 6

=item Github api v3 support

=item Support regex user/repo queries

=item Retry on timeout?

=item Better documentation.

=back

=head1 SEE ALSO

=over 4

=item L<http://github-high-scores.heroku.com/>

=item L<Net::GitHub>

=item L<http://github.com>

=item L<App::DuckDuckGo>

=item L<WWW::DuckDuckGo>

=item L<http://duck.co/>

=back


=for
Kind of thing you get from the api:
$VAR1 = [
          {
            'gravatar_id' => 'dd9aceaf17982bc33972b3bb8701cd19',
            'location' => 'O\'Fallon, IL',
            'name' => 'Jesse Luehrs',
            'blog' => 'http://tozt.net/',
            'login' => 'doy',
            'email' => 'doy at tozt dot net',
            'type' => 'User',
            'company' => 'Infinity Interactive',
            'contributions' => 119
          },
          {
            'gravatar_id' => '0bffad37a60feece78c306af4456f53a',
            'name' => 'Stevan Little',
            'blog' => 'http://moose.perl.org',
            'login' => 'stevan',
            'email' => 'stevan.little@iinteractive.com',
            'type' => 'User',
            'company' => 'Infinity Interactive',
            'contributions' => 36
          },
          {
            'gravatar_id' => 'c68ae3a25b34be3310bd975c2036940d',
            'location' => 'Annville, PA',
            'name' => 'Jason May',
            'blog' => 'http://jarsonmar.org/',
            'login' => 'jasonmay',
            'email' => 'jason.a.may@gmail.com',
            'type' => 'User',
            'company' => 'Best Practical Solutions',
            'contributions' => 5
          },
          {
            'gravatar_id' => 'be68b0e46958d0dcb621f696f9b1bc1c',
            'location' => 'Revere, MA',
            'name' => 'Justin Hunter',
            'blog' => 'http://warpedreality.org',
            'login' => 'arcanez',
            'email' => 'justin.d.hunter@gmail.com',
            'type' => 'User',
            'company' => 'Cantella',
            'contributions' => 3
          }
        ];
=cut

Powered by Groonga
Maintained by Kenichi Ishigaki <ishigaki@cpan.org>. If you find anything, submit it on GitHub.