Merge remote branch 't0m/json' into json
Dan Brook [Sun, 2 May 2010 19:06:51 +0000 (20:06 +0100)]
Conflicts:
Makefile.PL
lib/Gitalist/Controller/Root.pm
lib/Gitalist/Git/Repository.pm

Makefile.PL
lib/Gitalist/Controller/Root.pm
lib/Gitalist/Git/CollectionOfRepositories.pm
lib/Gitalist/Git/HasUtils.pm
lib/Gitalist/Git/Object.pm
lib/Gitalist/Git/Repository.pm
lib/Gitalist/Git/Types.pm
lib/Gitalist/Serializeable.pm [new file with mode: 0644]
t/02git_Repository.t
t/json_view.t [new file with mode: 0644]

index ca22491..54e0b01 100644 (file)
@@ -64,6 +64,8 @@ requires 'Catalyst::Controller::ActionRole';
 requires 'Catalyst::View::Component::SubInclude' => '0.07';
 requires 'Catalyst::View::TT';
 requires 'Try::Tiny';
+requires 'Catalyst::Action::Serialize';
+
 requires 'Template';
 requires 'Template::Provider::Encoding';
 requires 'Template::Plugin::Cycle';
@@ -74,9 +76,14 @@ requires 'Moose';
 requires 'Moose::Autobox';
 requires 'MooseX::MultiMethods' => '0.10';
 requires 'MooseX::Declare' => '0.32';
+requires 'MooseX::Types::DateTime';
+requires 'MooseX::Types::ISO8601';
 requires 'MooseX::Types::Common';
 requires 'MooseX::Types::Path::Class';
 requires 'MooseX::Types';
+requires 'MooseX::Storage';
+requires 'JSON::Any';
+requires 'JSON::XS';
 requires 'namespace::autoclean';
 
 requires 'Git::PurePerl' => '0.46';
@@ -103,6 +110,7 @@ requires 'XML::RSS';
 
 test_requires 'Test::More' => '0.88';
 test_requires 'Test::utf8' => '0.02';
+test_requires 'HTTP::Request::Common';
 
 resources bugtracker => 'http://rt.cpan.org/Public/Dist/Display.html?Name=Gitalist';
 resources repository => 'git://git.shadowcat.co.uk/catagits/Gitalist.git';
index 14ef8ee..a46fff0 100644 (file)
@@ -35,6 +35,7 @@ sub base : Chained('/root') PathPart('') CaptureArgs(0) {
     git_version => $git_version,
     version     => $Gitalist::VERSION,
 
+    # XXX Move these to a plugin!
     time_since => sub {
       return 'never' unless $_[0];
       return age_string(time - $_[0]->epoch);
@@ -58,17 +59,16 @@ sub base : Chained('/root') PathPart('') CaptureArgs(0) {
   );
 }
 
-sub search : Chained('base') Args(0) {}
-
-=head2 search_help
-
-Provides some help for the search form.
-
-=cut
-
-sub search_help : Chained('base') Args(0) {}
-
-sub end : ActionClass('RenderView') {}
+sub end : ActionClass('Serialize') {
+    my ($self, $c) = @_;
+    # Give repository views the current HEAD.
+    if ($c->stash->{Repository}) {
+        $c->stash->{HEAD} = $c->stash->{Repository}->head_hash;
+    }
+    if ($c->stash->{data} && blessed $c->stash->{data}) {
+        $c->stash->{rest} = $c->stash->{data}->pack;
+    }
+}
 
 sub error_404 : Action {
     my ($self, $c) = @_;
@@ -76,6 +76,14 @@ sub error_404 : Action {
     $c->response->body('Page not found');
 }
 
+__PACKAGE__->config(
+    default => 'text/html',
+    map => {
+        'text/html'        => [qw/ View Default /],
+        'application/json' => [qw/ JSON /],
+    }
+);
+
 __PACKAGE__->meta->make_immutable;
 
 __END__
index 69243af..a4822a5 100644 (file)
@@ -6,6 +6,8 @@ role Gitalist::Git::CollectionOfRepositories {
     use Moose::Autobox;
     use aliased 'Gitalist::Git::Repository';
 
+    with 'Gitalist::Serializeable';
+
     has repositories => (
         is => 'ro',
         isa => ArrayRef['Gitalist::Git::Repository'],
index 7d133ac..bcc0ad6 100644 (file)
@@ -2,6 +2,7 @@ use MooseX::Declare;
 
 role Gitalist::Git::HasUtils {
     use Gitalist::Git::Util;
+    use MooseX::Storage::Meta::Attribute::Trait::DoNotSerialize;
 
     method BUILD {}
     after BUILD {
@@ -21,6 +22,7 @@ role Gitalist::Git::HasUtils {
             get_gpp_object
             gpp
         /],
+        traits => [qw/ DoNotSerialize /],
     );
     method _build_util { confess(shift() . " cannot build _util") }
 }
index 4448790..33a4f75 100644 (file)
@@ -1,7 +1,7 @@
 use MooseX::Declare;
 use Moose::Autobox;
 
-class Gitalist::Git::Object {
+class Gitalist::Git::Object with Gitalist::Serializeable {
     use MooseX::Types::Moose qw/Str Int Bool Maybe ArrayRef/;
     use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
 
index 0d0c884..e4eb595 100644 (file)
@@ -3,19 +3,20 @@ use MooseX::Declare;
 class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
     # FIXME, use Types::Path::Class and coerce
     use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
-    use MooseX::Types::Path::Class qw/Dir/;
     use MooseX::Types::Moose qw/Str Maybe Bool HashRef ArrayRef/;
-    use Gitalist::Git::Types qw/SHA1/;
     use MooseX::MultiMethods;
+    use Gitalist::Git::Types qw/SHA1 DateTime Dir/;
     use Moose::Autobox;
     use List::MoreUtils qw/any zip/;
-    use DateTime;
+    use aliased 'DateTime' => 'DT';
     use Encode qw/decode/;
     use I18N::Langinfo qw/langinfo CODESET/;
     use Gitalist::Git::Object::Blob;
     use Gitalist::Git::Object::Tree;
     use Gitalist::Git::Object::Commit;
     use Gitalist::Git::Object::Tag;
+    
+    with 'Gitalist::Serializeable';
 
     our $SHA1RE = qr/[0-9a-fA-F]{40}/;
 
@@ -35,7 +36,8 @@ class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
                   is => 'ro', required => 1 );
 
     has path => ( isa => Dir,
-                  is => 'ro', required => 1);
+                  is => 'ro', required => 1,
+                  traits => [qw/ DoNotSerialize /] );
 
     has description => ( isa => Str,
                          is => 'ro',
@@ -47,7 +49,7 @@ class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
                    lazy_build => 1,
                );
 
-    has last_change => ( isa => Maybe['DateTime'],
+    has last_change => ( isa => Maybe[DateTime],
                          is => 'ro',
                          lazy_build => 1,
                      );
@@ -56,13 +58,15 @@ class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
                      is => 'ro',
                      lazy => 1,
                      default => sub {
-                         -d $_[0]->path->parent->subdir->($_[0]->name)
+                         -d $_[0]->path->parent->subdir($_[0]->name)
                              ? 1 : 0
                          },
                      );
     has heads => ( isa => ArrayRef[HashRef],
                    is => 'ro',
-                   lazy_build => 1);
+                   lazy_build => 1,
+                   traits => [qw/ DoNotSerialize /],
+                   );
     has tags => ( isa => ArrayRef[HashRef],
                    is => 'ro',
                    lazy_build => 1);
@@ -265,7 +269,7 @@ class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
                 --sort=-committerdate --count=1 refs/heads
           });
         if (my ($epoch, $tz) = $output =~ /\s(\d+)\s+([+-]\d+)$/) {
-            my $dt = DateTime->from_epoch(epoch => $epoch);
+            my $dt = DT->from_epoch(epoch => $epoch);
             $dt->set_time_zone($tz);
             $last_change = $dt;
         }
@@ -283,7 +287,7 @@ class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
 
             #FIXME: That isn't the time I'm looking for..
             if (my ($epoch, $tz) = $line =~ /\s(\d+)\s+([+-]\d+)$/) {
-                my $dt = DateTime->from_epoch(epoch => $epoch);
+                my $dt = DT->from_epoch(epoch => $epoch);
                 $dt->set_time_zone($tz);
                 $ret[-1]->{last_change} = $dt;
             }
@@ -309,7 +313,7 @@ class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
 
             #FIXME: That isn't the time I'm looking for..
             if($epoch and $tz) {
-                my $dt = DateTime->from_epoch(epoch => $epoch);
+                my $dt = DT->from_epoch(epoch => $epoch);
                 $dt->set_time_zone($tz);
                 $ret[-1]->{last_change} = $dt;
             }
index af12bbc..5cca578 100644 (file)
@@ -1,8 +1,16 @@
 package Gitalist::Git::Types;
 
 use MooseX::Types
-    -declare => [qw/SHA1/];
+    -declare => [qw/
+        SHA1
+        DateTime
+        Dir
+    /];
 
+use MooseX::Types::Path::Class;
+use MooseX::Types::ISO8601 qw/ISO8601DateTimeStr/;
+use MooseX::Types::DateTime ();
+use MooseX::Storage::Engine ();
 use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
 
 subtype SHA1,
@@ -14,4 +22,34 @@ coerce SHA1,
     from NonEmptySimpleStr,
     via { 1 };
 
+subtype DateTime,
+    as 'MooseX::Types::DateTime::DateTime',
+    where { 1 };
+
+MooseX::Storage::Engine->add_custom_type_handler(
+    DateTime,
+        expand   => sub {
+            my $val = shift;
+            Carp::confess("Not implemented");
+        },
+        collapse => sub {
+            to_ISO8601DateTimeStr(shift);
+        },
+);
+
+subtype Dir,
+    as 'MooseX::Types::Path::Class::Dir',
+    where { 1 };
+
+MooseX::Storage::Engine->add_custom_type_handler(
+    Dir,
+        expand   => sub {
+            my $val = shift;
+            Carp::confess("Not implemented");
+        },
+        collapse => sub {
+            shift() . '';
+        },
+);
+
 1;
diff --git a/lib/Gitalist/Serializeable.pm b/lib/Gitalist/Serializeable.pm
new file mode 100644 (file)
index 0000000..c430127
--- /dev/null
@@ -0,0 +1,32 @@
+package Gitalist::Serializeable;
+use Moose::Role;
+use namespace::autoclean;
+use MooseX::Storage;
+
+with Storage( traits => [qw|OnlyWhenBuilt|] );
+
+1;
+
+=head1 NAME
+
+Gitalist::Serializeable
+
+=head1 SYNOPSIS
+
+  class Gitalist::Git::Foo with Gitalist::Serializeable {
+     ...
+  }
+  
+=head1 DESCRIPTION
+
+Role which applies a customised L<MooseX::Storage>.
+
+=head1 AUTHORS
+
+See L<Gitalist> for authors.
+
+=head1 LICENSE
+
+See L<Gitalist> for the license.
+
+=cut
index e8ee762..175e52f 100644 (file)
@@ -38,6 +38,15 @@ is($proj->name, qw/repo1/, 'repository name is set');
 is($proj->description, qq/some test repository/, 'repository description loaded');
 isa_ok($proj->last_change, 'DateTime', 'last_change');
 
+is_deeply $proj->pack, {
+    '__CLASS__' => 'Gitalist::Git::Repository',
+    'is_bare' => 1,
+    'owner' => "T\x{e9}st",
+    'last_change' => '2009-11-12T19:00:34Z',
+    'name' => 'repo1',
+    'description' => 'some test repository'
+};
+
 my %references = %{$proj->references};
 ok(keys %references >= 2, '->references hash has elements');
 is($references{'36c6c6708b8360d7023e8a1649c45bcf9b3bd818'}->[0], 'heads/master', 'reference looks ok');
diff --git a/t/json_view.t b/t/json_view.t
new file mode 100644 (file)
index 0000000..026479d
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use Test::More;
+use HTTP::Request::Common;
+use FindBin qw/$Bin/;
+use JSON::Any;
+
+BEGIN {
+    $ENV{GITALIST_CONFIG} = $Bin;
+    $ENV{GITALIST_REPO_DIR} = '';
+    use_ok 'Catalyst::Test', 'Gitalist';
+}
+
+my $j = JSON::Any->new;
+
+my $res = request(GET 'http://localhost/summary?p=repo1', 'Content-Type' => 'application/json');
+is $res->code, 200;
+my $data = $j->decode($res->content);
+is ref($data), 'HASH';
+is_deeply $data, {
+          'owner' => 'Tomas Doran',
+          'is_bare' => 1,
+          '__CLASS__' => 'Gitalist::Git::Repository',
+          'last_change' => '2009-11-12T19:00:34Z',
+          'references' => {
+                            '0710a7c8ee11c73e8098d08f9384c2a839c65e4e' => [
+                                                                            'heads/branch1'
+                                                                          ],
+                            '36c6c6708b8360d7023e8a1649c45bcf9b3bd818' => [
+                                                                            'heads/master'
+                                                                          ]
+                          },
+          'name' => 'repo1',
+          'description' => 'some test repository'
+        };
+
+done_testing;
+
+