Skip to content

Instantly share code, notes, and snippets.

@ynonp
Created May 1, 2013 18:47
Show Gist options
  • Save ynonp/5497384 to your computer and use it in GitHub Desktop.
Save ynonp/5497384 to your computer and use it in GitHub Desktop.
use strict;
use warnings;
use v5.14;
package Promise::Common;
use Moose::Role;
has 'ctx', is => 'ro', required => 1;
requires 'state';
sub then { }
sub fulfill { }
sub reject { }
package Promise::Fulfilled;
use Moose;
with 'Promise::Common';
sub state { 'FULFILLED' }
sub then {
my ( $self, $cb ) = @_;
$cb->( $self->ctx->value );
}
sub BUILD {
my ( $self ) = @_;
$_->( $self->ctx->value ) for @{ $self->ctx->yep }
}
package Promise::Rejected;
use Moose;
with 'Promise::Common';
sub state { 'REJECTED' }
sub then {
my ( $self, undef, $cb ) = @_;
$self->$cb( $self->ctx->reason );
}
sub BUILD {
my ( $self ) = @_;
$_->($self->ctx->reason) for @{ $self->ctx->nope }
}
package Promise::Pending;
use Moose;
with 'Promise::Common';
sub state { 'PENDING' }
sub fulfill {
my ( $self, $value ) = @_;
$self->ctx->value( $value );
$self->ctx->_promise( Promise::Fulfilled->new( ctx => $self->ctx ) );
}
sub reject {
my ( $self, $reason ) = @_;
$self->ctx->reason( $reason );
$self->ctx->_promise( Promise::Rejected->new( ctx => $self->ctx ));
}
sub then {
my ( $self, $yep, $nope ) = @_;
$self->ctx->push_yep( $yep );
$self->ctx->push_nope( $nope );
}
package Promise;
use Moose;
has '_promise', is => 'rw', isa => 'Promise::Common',
lazy_build => 1,
handles => [qw/state then fulfill reject/];
has '_original_state', default => 'PENDING',
init_arg => 'state', is => 'ro';
has 'reason', is => 'rw';
has 'value', is => 'rw';
has 'yep', is => 'ro', isa => 'ArrayRef', traits => [qw/Array/],
handles => { push_yep => 'push' }, default => sub {[]};
has 'nope', is => 'ro', isa => 'ArrayRef', traits => [qw/Array/],
handles => { push_nope => 'push' }, default => sub {[]};
sub _build__promise {
my ( $self ) = @_;
my $state = $self->_original_state || 'PENDING';
my $cls = 'Promise::' . ucfirst lc $state;
$cls->new( ctx => shift )
}
package main;
use Test::More tests => 9;
{
my $promise = Promise->new;
my $value = 0;
$promise->then(sub { $value = shift });
ok !$value, "Hasn't been fulfilled yet";
$promise->fulfill("OH HAI");
is $promise->state, "FULFILLED", "Correct state";
is $value, "OH HAI", "Code has been run";
}
{
my $promise = Promise->new(state => "FULFILLED", value => "yay!");
is $promise->state, "FULFILLED", "Already correct state";
my $value = 0;
$promise->then(sub { $value = shift });
is $value, "yay!", "Code ran immediately";
}
{
my $promise = Promise->new;
my $value = 0;
my $reason = 0;
$promise->then(sub { $value = shift }, sub { $reason = shift });
ok !$reason, "Hasn't been rejected yet";
$promise->reject("OH NOES");
is $promise->state, "REJECTED", "Correct state";
ok !$value, "Fulfill code didn't run";
is $reason, "OH NOES", "Reject code has been run";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment