view release on metacpan or search on metacpan
Makefile.PL view on Meta::CPAN
AUTHOR => q{Rob Hoelz <rob@hoelz.ro>},
VERSION_FROM => 'lib/AnyEvent/WebService/Tracks.pm',
ABSTRACT_FROM => 'lib/AnyEvent/WebService/Tracks.pm',
($ExtUtils::MakeMaker::VERSION >= 6.3002
? ('LICENSE'=> 'perl')
: ()),
PL_FILES => {},
PREREQ_PM => {
'AnyEvent' => 0,
'AnyEvent::HTTP' => 0,
'DateTime' => 0,
'DateTime::Format::ISO8601' => 0,
'FindBin' => 0,
'List::MoreUtils' => 0,
'MIME::Base64' => 0,
'namespace::clean' => 0,
'Scalar::Util' => 0,
'Storable' => 0,
'Test::Exception' => 0,
'Test::More' => 0,
'URI' => 0,
'XML::Parser' => 0,
lib/AnyEvent/WebService/Tracks.pm view on Meta::CPAN
package AnyEvent::WebService::Tracks;
use strict;
use warnings;
use AnyEvent::HTTP qw(http_request);
use Carp qw(croak);
use DateTime;
use DateTime::Format::ISO8601;
use MIME::Base64 qw(encode_base64);
use URI;
use XML::Parser;
use XML::Writer;
use AnyEvent::WebService::Tracks::Context;
use AnyEvent::WebService::Tracks::Project;
use AnyEvent::WebService::Tracks::Todo;
our $VERSION = '0.02';
lib/AnyEvent/WebService/Tracks.pm view on Meta::CPAN
return bless {
url => URI->new($params{url}),
username => $params{username},
password => $params{password},
}, $class;
}
sub parse_datetime {
my ( $self, $str ) = @_;
return DateTime::Format::ISO8601->parse_datetime($str);
}
sub format_datetime {
my ( $self, $datetime ) = @_;
my @fields = qw/year month day hour minute second/;
my %attrs = map { $_ => $datetime->$_() } @fields;
my $offset = DateTime::TimeZone->offset_as_string($datetime->offset);
return sprintf '%04d-%02d-%02dT%02d:%02d:%02d%s', @attrs{@fields}, $offset;
}
sub handle_error {
my ( $self, $body, $headers, $cb ) = @_;
my $message;
if($body) {
lib/AnyEvent/WebService/Tracks.pm view on Meta::CPAN
my $xml = '';
my $w = XML::Writer->new(OUTPUT => \$xml);
my @keys = sort keys %$attrs;
$w->startTag($root);
foreach my $k (@keys) {
my $v = $attrs->{$k};
my @xml_attrs;
push @xml_attrs, (nil => 'true') unless defined $v;
if(ref($v) eq 'DateTime') {
push @xml_attrs, (type => 'datetime');
$v = $self->format_datetime($v);
}
my $nk = $k;
$nk =~ tr/_/-/;
$w->startTag($nk, @xml_attrs);
$w->characters($v) if defined $v;
$w->endTag($nk);
lib/AnyEvent/WebService/Tracks/Todo.pm view on Meta::CPAN
$self->{'_dirty'}{'show_from'} = 1;
}
}
sub defer {
my ( $self, $amount ) = @_;
my $show_from;
if(! ref($amount)) {
$show_from = DateTime->now->add(days => $amount);
} elsif(ref($amount) eq 'DateTime') {
$show_from = $amount;
} elsif(ref($amount) eq 'DateTime::Duration') {
$show_from = DateTime->now->add_duration($amount);
}
$self->{'show_from'} = $show_from;
$self->{'_dirty'}{'show_from'} = 1;
}
sub context {
my ( $self, $cb_or_ctx ) = @_;
if(ref($cb_or_ctx) eq 'CODE') {
lib/AnyEvent/WebService/Tracks/Todo.pm view on Meta::CPAN
=head2 $todo->complete
Mark this todo item as complete on its next update.
=head2 $todo->activate
Mark this todo item as active on its next update.
=head2 $todo->defer($amount)
Defer this todo item. C<$amount> can be a DateTime, a
DateTime::Duration, or simply an integer (which is interpreted
as the number of days to defer the item.)
=head1 AUTHOR
Rob Hoelz, C<< rob at hoelz.ro >>
=head1 BUGS
Please report any bugs or feature requests to C<bug-AnyEvent-WebService-Tracks at rt.cpan.org>, or through
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=AnyEvent-WebService-Tracks>. I will
t/02-context.t view on Meta::CPAN
$run = sub {
my $name = shift @contexts;
$tracks->create_context($name, sub {
my ( $ctx ) = @_;
ok($ctx);
isa_ok($ctx, 'AnyEvent::WebService::Tracks::Context');
is($ctx->name, $name);
ok(looks_like_number $ctx->id);
isa_ok($ctx->created_at, 'DateTime');
isa_ok($ctx->updated_at, 'DateTime');
ok(looks_like_number $ctx->position);
ok(! $ctx->is_hidden);
dies_ok {
$ctx->id(0);
};
lives_ok {
$ctx->name('New Name');
};
dies_ok {
$ctx->created_at(DateTime->now);
};
dies_ok {
$ctx->updated_at(DateTime->now);
};
lives_ok {
$ctx->position(1);
};
lives_ok {
$ctx->hide;
};
lives_ok {
$ctx->unhide;
};
t/02-context.t view on Meta::CPAN
$run = sub {
my $name = shift @contexts;
$tracks->create_context(name => $name, sub {
my ( $ctx ) = @_;
ok($ctx);
isa_ok($ctx, 'AnyEvent::WebService::Tracks::Context');
is($ctx->name, $name);
ok(looks_like_number $ctx->id);
isa_ok($ctx->created_at, 'DateTime');
isa_ok($ctx->updated_at, 'DateTime');
ok(looks_like_number $ctx->position);
ok(! $ctx->is_hidden);
dies_ok {
$ctx->id(0);
};
lives_ok {
$ctx->name('New Name');
};
dies_ok {
$ctx->created_at(DateTime->now);
};
dies_ok {
$ctx->updated_at(DateTime->now);
};
lives_ok {
$ctx->position(1);
};
lives_ok {
$ctx->hide;
};
lives_ok {
$ctx->unhide;
};
t/02-context.t view on Meta::CPAN
$run = sub {
my $name = shift @contexts;
$tracks->create_context(name => $name, hide => 1, sub {
my ( $ctx ) = @_;
ok($ctx);
isa_ok($ctx, 'AnyEvent::WebService::Tracks::Context');
is($ctx->name, $name);
ok(looks_like_number $ctx->id);
isa_ok($ctx->created_at, 'DateTime');
isa_ok($ctx->updated_at, 'DateTime');
ok(looks_like_number $ctx->position);
ok($ctx->is_hidden);
dies_ok {
$ctx->id(0);
};
lives_ok {
$ctx->name('New Name');
};
dies_ok {
$ctx->created_at(DateTime->now);
};
dies_ok {
$ctx->updated_at(DateTime->now);
};
lives_ok {
$ctx->position(1);
};
lives_ok {
$ctx->hide;
};
lives_ok {
$ctx->unhide;
};
t/03-project.t view on Meta::CPAN
ok($proj);
isa_ok($proj, 'AnyEvent::WebService::Tracks::Project');
is($proj->name, $name);
ok(! defined($proj->description));
ok(looks_like_number $proj->position);
ok(! defined($proj->completed_at));
ok(! $proj->is_complete);
ok(! $proj->is_hidden);
ok($proj->is_active);
isa_ok($proj->created_at, 'DateTime');
isa_ok($proj->updated_at, 'DateTime');
dies_ok {
$proj->completed_at(DateTime->now);
};
dies_ok {
$proj->created_at(DateTime->now);
};
dies_ok {
$proj->id(0);
};
dies_ok {
$proj->updated_at(DateTime->now);
};
lives_ok {
$proj->description('Phony description');
};
lives_ok {
$proj->name('Another name');
};
lives_ok {
$proj->position(4);
t/03-project.t view on Meta::CPAN
ok($proj);
isa_ok($proj, 'AnyEvent::WebService::Tracks::Project');
is($proj->name, $name);
ok(! defined($proj->description));
ok(looks_like_number $proj->id);
ok(looks_like_number $proj->position);
ok(! defined($proj->completed_at));
ok(! $proj->is_complete);
ok(! $proj->is_hidden);
ok($proj->is_active);
isa_ok($proj->created_at, 'DateTime');
isa_ok($proj->updated_at, 'DateTime');
dies_ok {
$proj->completed_at(DateTime->now);
};
dies_ok {
$proj->created_at(DateTime->now);
};
dies_ok {
$proj->id(0);
};
dies_ok {
$proj->updated_at(DateTime->now);
};
lives_ok {
$proj->description('Phony description');
};
lives_ok {
$proj->name('Another name');
};
lives_ok {
$proj->position(4);
t/03-project.t view on Meta::CPAN
ok($proj);
isa_ok($proj, 'AnyEvent::WebService::Tracks::Project');
is($proj->name, $name);
is($proj->description, $desc);
ok(looks_like_number $proj->position);
ok(! defined($proj->completed_at));
ok(! $proj->is_complete);
ok(! $proj->is_hidden);
ok($proj->is_active);
isa_ok($proj->created_at, 'DateTime');
isa_ok($proj->updated_at, 'DateTime');
dies_ok {
$proj->completed_at(DateTime->now);
};
dies_ok {
$proj->created_at(DateTime->now);
};
dies_ok {
$proj->id(0);
};
dies_ok {
$proj->updated_at(DateTime->now);
};
lives_ok {
$proj->description('Phony description');
};
lives_ok {
$proj->description('Another name');
};
lives_ok {
$proj->position(4);
t/04-todo.t view on Meta::CPAN
ok(! defined($todo->due));
ok(! defined($todo->notes));
ok(! defined($todo->show_from));
ok($todo->is_active);
ok(! $todo->is_project_hidden);
ok(! $todo->is_complete);
ok(! $todo->is_deferred);
ok(looks_like_number $todo->id);
ok(! $todo->completed_at);
ok(! $todo->recurring_todo_id);
isa_ok($todo->created_at, 'DateTime');
isa_ok($todo->updated_at, 'DateTime');
dies_ok {
$todo->completed_at(DateTime->now);
};
dies_ok {
$todo->created_at(DateTime->now);
};
dies_ok {
$todo->updated_at(DateTime->now);
};
dies_ok {
$todo->id(0);
};
dies_ok {
$todo->recurring_todo_id(0);
};
lives_ok {
$todo->description('Test description');
};
lives_ok {
$todo->due(DateTime->now);
};
lives_ok {
$todo->notes('Test notes');
};
lives_ok {
$todo->show_from(DateTime->now);
};
$todo->context(sub {
my ( $c ) = @_;
is($c->id, $ctx->id);
$todo->project(sub {
my ( $p, $e ) = @_;
t/04-todo.t view on Meta::CPAN
ok(! defined($todo->due));
ok(! defined($todo->notes));
ok(! defined($todo->show_from));
ok($todo->is_active);
ok(! $todo->is_project_hidden);
ok(! $todo->is_complete);
ok(! $todo->is_deferred);
ok(looks_like_number $todo->id);
ok(! $todo->completed_at);
ok(! $todo->recurring_todo_id);
isa_ok($todo->created_at, 'DateTime');
isa_ok($todo->updated_at, 'DateTime');
dies_ok {
$todo->completed_at(DateTime->now);
};
dies_ok {
$todo->created_at(DateTime->now);
};
dies_ok {
$todo->updated_at(DateTime->now);
};
dies_ok {
$todo->id(0);
};
dies_ok {
$todo->recurring_todo_id(0);
};
lives_ok {
$todo->description('Test description');
};
lives_ok {
$todo->due(DateTime->now);
};
lives_ok {
$todo->notes('Test notes');
};
lives_ok {
$todo->show_from(DateTime->now);
};
$todo->context(sub {
my ( $c ) = @_;
is($c->id, $ctx->id);
$todo->project(sub {
my ( $p, $e ) = @_;
t/04-todo.t view on Meta::CPAN
is($todo->notes, $notes);
ok(! defined($todo->due));
ok(! defined($todo->show_from));
ok($todo->is_active);
ok(! $todo->is_project_hidden);
ok(! $todo->is_complete);
ok(! $todo->is_deferred);
ok(looks_like_number $todo->id);
ok(! $todo->completed_at);
ok(! $todo->recurring_todo_id);
isa_ok($todo->created_at, 'DateTime');
isa_ok($todo->updated_at, 'DateTime');
dies_ok {
$todo->completed_at(DateTime->now);
};
dies_ok {
$todo->created_at(DateTime->now);
};
dies_ok {
$todo->updated_at(DateTime->now);
};
dies_ok {
$todo->id(0);
};
dies_ok {
$todo->recurring_todo_id(0);
};
lives_ok {
$todo->description('Test description');
};
lives_ok {
$todo->due(DateTime->now);
};
lives_ok {
$todo->notes('Test notes');
};
lives_ok {
$todo->show_from(DateTime->now);
};
$todo->context(sub {
my ( $c ) = @_;
is($c->id, $ctx->id);
$todo->project(sub {
my ( $p, $e ) = @_;
t/04-todo.t view on Meta::CPAN
});
};
$run->();
});
};
run_tests_in_loop {
my ( $cond ) = @_;
my $now = DateTime->now;
my $other = $now->clone->add(days => 7, hours => 3, minutes => 1);
my $duration = DateTime::Duration->new(days => 7, hours => 3, minutes => 1);
my @defer = (
1 => $now->clone->add(days => 1),
$other => $other,
$duration => $other,
);
$tracks->create_todo(
description => 'Deferred Task',
context => $ctx,
show_from => $now->clone->add(days => 1),
t/04-todo.t view on Meta::CPAN
});
};
$run->();
});
};
run_tests_in_loop {
my ( $cond ) = @_;
my $time = DateTime->now;
$time->set_hour(17);
$time->set_minute(0);
$time->set_second(0);
$tracks->create_todo(
description => 'Another Deferred Task',
context => $ctx,
show_from => $time->clone->add(days => 1),
sub {
my ( $todo ) = @_;
t/04-todo.t view on Meta::CPAN
$expected->set_second(0);
};
is($todo->show_from, $expected);
$cond->send;
});
};
run_tests_in_loop {
my ( $cond ) = @_;
my $time = DateTime->now;
$time->set_hour(20);
$time->set_minute(0);
$time->set_second(0);
$tracks->create_todo(
description => 'Yet Another Deferred Task',
context => $ctx,
show_from => $time->clone->add(days => 1),
sub {
my ( $todo ) = @_;